Correct scaling of normals during flatten operations

This commit is contained in:
rdb 2015-06-14 23:14:56 +02:00
parent c85a92d378
commit bac400543a
12 changed files with 98 additions and 23 deletions

View File

@ -118,7 +118,7 @@ munge_format_impl(const GeomVertexFormat *orig,
if (normal_type != (const GeomVertexColumn *)NULL) {
new_array_format->add_column
(InternalName::get_normal(), 3, NT_float32, C_vector);
(InternalName::get_normal(), 3, NT_float32, C_normal);
new_format->remove_column(normal_type->get_name());
}
@ -227,7 +227,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
if (normal_type != (const GeomVertexColumn *)NULL) {
new_array_format->add_column
(InternalName::get_normal(), 3, NT_float32, C_vector);
(InternalName::get_normal(), 3, NT_float32, C_normal);
new_format->remove_column(normal_type->get_name());
}

View File

@ -2240,7 +2240,7 @@ make_vertex_data(const EggRenderState *render_state,
if (vertex_pool->has_normals()) {
array_format->add_column
(InternalName::get_normal(), 3,
Geom::NT_stdfloat, Geom::C_vector);
Geom::NT_stdfloat, Geom::C_normal);
}
if (!ignore_color) {

View File

@ -139,6 +139,9 @@ operator << (ostream &out, GeomEnums::Contents contents) {
case GeomEnums::C_matrix:
return out << "matrix";
case GeomEnums::C_normal:
return out << "normal";
}
return out << "**invalid contents (" << (int)contents << ")**";

View File

@ -192,7 +192,7 @@ PUBLISHED:
C_other, // Arbitrary meaning, leave it alone
C_point, // A point in 3-space or 4-space
C_clip_point, // A point pre-transformed into clip coordinates
C_vector, // A surface normal, tangent, or binormal
C_vector, // A surface tangent or binormal (see C_normal for normals)
C_texcoord, // A texture coordinate
C_color, // 3- or 4-component color, ordered R, G, B, [A]
C_index, // An index value into some other table
@ -201,6 +201,10 @@ PUBLISHED:
// A transformation matrix. This is typically three or four
// columns, but we pretend it's only one for convenience.
C_matrix,
// A special version of C_vector that should be used for normal
// vectors, which are scaled differently from other vectors.
C_normal,
};
// The type of animation data that is represented by a particular

View File

@ -394,8 +394,11 @@ align_columns_for_animation() {
Columns::const_iterator ci;
for (ci = orig_columns.begin(); ci != orig_columns.end(); ++ci) {
GeomVertexColumn *column = (*ci);
if ((column->get_contents() == C_point || column->get_contents() == C_vector) &&
(column->get_numeric_type() == NT_float32 || column->get_numeric_type() == NT_float64) &&
if ((column->get_contents() == C_point ||
column->get_contents() == C_vector ||
column->get_contents() == C_normal) &&
(column->get_numeric_type() == NT_float32 ||
column->get_numeric_type() == NT_float64) &&
column->get_num_components() >= 3) {
add_column(column->get_name(), 4, column->get_numeric_type(), column->get_contents(), -1, 16);
} else {

View File

@ -340,6 +340,11 @@ make_packer() const {
break;
}
return new Packer_color;
case C_normal:
if (get_num_values() != 3) {
gobj_cat.error()
<< "GeomVertexColumn with contents C_normal must have 3 components!\n";
}
default:
// Otherwise, we just read it as a generic value.
switch (get_numeric_type()) {

View File

@ -1915,10 +1915,37 @@ do_transform_point_column(const GeomVertexFormat *format, GeomVertexRewriter &da
////////////////////////////////////////////////////////////////////
void GeomVertexData::
do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
const LMatrix4 &mat, int begin_row, int end_row) {
const LMatrix4 &mat, int begin_row, int end_row) {
const GeomVertexColumn *data_column = data.get_column();
int num_values = data_column->get_num_values();
LMatrix4 xform;
bool normalize = false;
if (data_column->get_contents() == C_normal) {
// This is to preserve perpendicularity to the surface.
LVecBase3 scale, shear, hpr;
if (decompose_matrix(mat.get_upper_3(), scale, shear, hpr) &&
IS_NEARLY_EQUAL(scale[0], scale[1]) &&
IS_NEARLY_EQUAL(scale[0], scale[2])) {
if (scale[0] == 1) {
// No scale to worry about.
xform = mat;
} else {
// Simply take the uniform scale out of the transformation.
// Not sure if it might be better to just normalize?
compose_matrix(xform, LVecBase3(1, 1, 1), shear, hpr, LVecBase3::zero());
}
} else {
// There is a non-uniform scale, so we need to do all this to
// preserve orthogonality to the surface.
xform.invert_from(mat);
xform.transpose_in_place();
normalize = true;
}
} else {
xform = mat;
}
if ((num_values == 3 || num_values == 4) &&
data_column->get_numeric_type() == NT_float32) {
// The table of vectors is a table of LVector3f's or LVector4f's.
@ -1929,9 +1956,11 @@ do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &d
size_t num_rows = end_row - begin_row;
unsigned char *datat = data_handle->get_write_pointer();
datat += data_column->get_start() + begin_row * stride;
LMatrix4f matf = LCAST(float, mat);
LMatrix4f matf = LCAST(float, xform);
if (num_values == 3) {
if (normalize) {
table_xform_normal3f(datat, num_rows, stride, matf);
} else if (num_values == 3) {
table_xform_vector3f(datat, num_rows, stride, matf);
} else {
table_xform_vecbase4f(datat, num_rows, stride, matf);
@ -1939,11 +1968,20 @@ do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &d
} else {
// Use the GeomVertexRewriter to transform the vectors.
data.set_row_unsafe(begin_row);
for (int j = begin_row; j < end_row; ++j) {
LVector3 vertex = data.get_data3();
data.set_data3(vertex * mat);
if (normalize) {
for (int j = begin_row; j < end_row; ++j) {
LVector3 vector = data.get_data3();
vector *= xform;
vector.normalize();
data.set_data3(vector);
}
} else {
for (int j = begin_row; j < end_row; ++j) {
LVector3 vector = data.get_data3();
data.set_data3(vector * xform);
}
}
}
}
@ -1965,6 +2003,25 @@ table_xform_point3f(unsigned char *datat, size_t num_rows, size_t stride,
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexData::table_xform_normal3f
// Access: Private, Static
// Description: Transforms each of the LVector3f objects in the
// indicated table by the indicated matrix, and also
// normalizes them.
////////////////////////////////////////////////////////////////////
void GeomVertexData::
table_xform_normal3f(unsigned char *datat, size_t num_rows, size_t stride,
const LMatrix4f &matf) {
// We don't bother checking for the unaligned case here, because in
// practice it doesn't matter with a 3-component vector.
for (size_t i = 0; i < num_rows; ++i) {
LNormalf &vertex = *(LNormalf *)(&datat[i * stride]);
vertex *= matf;
vertex.normalize();
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexData::table_xform_vector3f
// Access: Private, Static

View File

@ -334,6 +334,8 @@ private:
const LMatrix4 &mat, int begin_row, int end_row);
static void table_xform_point3f(unsigned char *datat, size_t num_rows,
size_t stride, const LMatrix4f &matf);
static void table_xform_normal3f(unsigned char *datat, size_t num_rows,
size_t stride, const LMatrix4f &matf);
static void table_xform_vector3f(unsigned char *datat, size_t num_rows,
size_t stride, const LMatrix4f &matf);
static void table_xform_vecbase4f(unsigned char *datat, size_t num_rows,

View File

@ -825,6 +825,7 @@ do_register() {
break;
case C_vector:
case C_normal:
// It's a vector.
_vectors.push_back(column->get_name());
break;
@ -1017,7 +1018,7 @@ make_standard_formats() {
(InternalName::get_vertex(), 3,
NT_stdfloat, C_point,
InternalName::get_normal(), 3,
NT_stdfloat, C_vector));
NT_stdfloat, C_normal));
_v3t2 = register_format(new GeomVertexArrayFormat
(InternalName::get_vertex(), 3,
@ -1029,7 +1030,7 @@ make_standard_formats() {
(InternalName::get_vertex(), 3,
NT_stdfloat, C_point,
InternalName::get_normal(), 3,
NT_stdfloat, C_vector,
NT_stdfloat, C_normal,
InternalName::get_texcoord(), 2,
NT_stdfloat, C_texcoord));
@ -1044,7 +1045,7 @@ make_standard_formats() {
(InternalName::get_vertex(), 3,
NT_stdfloat, C_point,
InternalName::get_normal(), 3,
NT_stdfloat, C_vector,
NT_stdfloat, C_normal,
InternalName::get_color(), 1,
NT_packed_dabc, C_color));
@ -1060,7 +1061,7 @@ make_standard_formats() {
(InternalName::get_vertex(), 3,
NT_stdfloat, C_point,
InternalName::get_normal(), 3,
NT_stdfloat, C_vector,
NT_stdfloat, C_normal,
InternalName::get_color(), 1,
NT_packed_dabc, C_color,
InternalName::get_texcoord(), 2,
@ -1079,7 +1080,7 @@ make_standard_formats() {
(InternalName::get_vertex(), 3,
NT_stdfloat, C_point,
InternalName::get_normal(), 3,
NT_stdfloat, C_vector,
NT_stdfloat, C_normal,
InternalName::get_color(), 4,
NT_uint8, C_color));
@ -1095,7 +1096,7 @@ make_standard_formats() {
(InternalName::get_vertex(), 3,
NT_stdfloat, C_point,
InternalName::get_normal(), 3,
NT_stdfloat, C_vector,
NT_stdfloat, C_normal,
InternalName::get_color(), 4,
NT_uint8, C_color,
InternalName::get_texcoord(), 2,

View File

@ -63,7 +63,7 @@ generate_block(unsigned short mx,
array->add_column(InternalName::get_texcoord(), 2,
Geom::NT_stdfloat, Geom::C_texcoord);
array->add_column(InternalName::get_normal(), 3,
Geom::NT_stdfloat, Geom::C_vector);
Geom::NT_stdfloat, Geom::C_normal);
PT(GeomVertexFormat) format = new GeomVertexFormat();
format->add_array(array);

View File

@ -1062,7 +1062,7 @@ make_array_format(const VisColumns &vis_columns) const {
case CT_normal3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_vector;
contents = GeomEnums::C_normal;
break;
case CT_blend1:
@ -1072,7 +1072,7 @@ make_array_format(const VisColumns &vis_columns) const {
break;
}
nassertr(num_components != 0, NULL);
array_format->add_column(name, num_components, numeric_type, contents);
}

View File

@ -282,7 +282,7 @@ get_format(bool support_normals) const {
if (support_normals && get_normal_mode() == NM_vertex) {
array_format->add_column
(InternalName::get_normal(), 3, Geom::NT_stdfloat,
Geom::C_vector);
Geom::C_normal);
}
if (get_use_vertex_color()) {
array_format->add_column