compute and load tangent and binormal

This commit is contained in:
David Rose 2005-07-01 19:14:51 +00:00
parent fa2e6eb726
commit 5d83609638
21 changed files with 2140 additions and 1507 deletions

View File

@ -17,3 +17,24 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: EggGroupNode::TBNVertexValue::operator <
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool EggGroupNode::TBNVertexValue::
operator < (const TBNVertexValue &other) const {
int compare = _pos.compare_to(other._pos);
if (compare != 0) {
return compare < 0;
}
compare = _normal.compare_to(other._normal);
if (compare != 0) {
return compare < 0;
}
compare = _uv.compare_to(other._uv);
if (compare != 0) {
return compare < 0;
}
return _uv_name < other._uv_name;
}

View File

@ -695,6 +695,45 @@ strip_normals() {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: EggGroupNode::recompute_tangent_binormal
// Access: Published
// Description: This function recomputes the tangent and binormal for
// the named texture coordinate set for all vertices at
// this level and below. Use the empty string for the
// default texture coordinate set.
//
// It is necessary for each vertex to already have a
// normal (or at least a polygon normal), as well as a
// texture coordinate in the named texture coordinate
// set, before calling this function. You might precede
// this with recompute_vertex_normals() to ensure that
// the normals exist.
//
// Like recompute_vertex_normals(), this function does
// not remove or adjust vertices in the vertex pool; it
// only adds new vertices with the normals removed.
// Thus, it is a good idea to call
// remove_unused_vertices() after calling this.
////////////////////////////////////////////////////////////////////
void EggGroupNode::
recompute_tangent_binormal(const GlobPattern &uv_name) {
// First, collect all the vertices together with their shared
// polygons.
TBNVertexCollection collection;
r_collect_tangent_binormal(uv_name, collection);
// Now compute the tangent and binormal separately for each common
// group of vertices.
TBNVertexCollection::const_iterator ci;
for (ci = collection.begin(); ci != collection.end(); ++ci) {
const TBNVertexValue &value = (*ci).first;
const TBNVertexGroup &group = (*ci).second;
do_compute_tangent_binormal(value, group);
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: EggGroupNode::triangulate_polygons // Function: EggGroupNode::triangulate_polygons
// Access: Published // Access: Published
@ -1644,7 +1683,7 @@ r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection,
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: EggGroupNode::r_collect_vertex_normals // Function: EggGroupNode::do_compute_vertex_normals
// Access: Private // Access: Private
// Description: This is part of the implementation of // Description: This is part of the implementation of
// recompute_vertex_normals(). It accepts a group of // recompute_vertex_normals(). It accepts a group of
@ -1683,3 +1722,159 @@ do_compute_vertex_normals(const NVertexGroup &group) {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: EggGroupNode::r_collect_tangent_binormal
// Access: Private
// Description: This is part of the implementation of
// recompute_tangent_binormal(). It walks the scene
// graph at this group node and below, identifying all
// the polygons and the vertices they have in common.
////////////////////////////////////////////////////////////////////
void EggGroupNode::
r_collect_tangent_binormal(const GlobPattern &uv_name,
EggGroupNode::TBNVertexCollection &collection) {
Children::iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
EggNode *child = *ci;
if (child->is_of_type(EggPolygon::get_class_type())) {
EggPolygon *polygon = DCAST(EggPolygon, child);
TBNVertexReference ref;
ref._polygon = polygon;
// Now add each vertex from the polygon separately to our
// collection.
size_t num_vertices = polygon->size();
for (size_t i = 0; i < num_vertices; i++) {
// We look at the triangle formed by each three consecutive
// vertices to determine the s direction and t direction at
// each vertex. v1 is the key vertex, the one at position i;
// v2 is vertex i + 1, and v3 is vertex i - 1.
EggVertex *v1 = polygon->get_vertex(i);
EggVertex *v2 = polygon->get_vertex((i + 1) % num_vertices);
EggVertex *v3 = polygon->get_vertex((i + num_vertices - 1) % num_vertices);
if (v1->has_normal() || polygon->has_normal()) {
// Go through all of the UV names on the vertex, looking for
// one that matches the glob pattern.
EggVertex::const_uv_iterator uvi;
for (uvi = v1->uv_begin(); uvi != v1->uv_end(); ++uvi) {
EggVertexUV *uv_obj = (*uvi);
string name = uv_obj->get_name();
if (uv_name.matches(name) &&
v2->has_uv(name) && v3->has_uv(name)) {
TBNVertexValue value;
value._uv_name = name;
value._pos = v1->get_pos3();
if (v1->has_normal()) {
value._normal = v1->get_normal();
} else {
value._normal = polygon->get_normal();
}
value._uv = v1->get_uv(name);
// Compute the s direction and t direction for this vertex.
LPoint3d p1 = v1->get_pos3();
LPoint3d p2 = v2->get_pos3();
LPoint3d p3 = v3->get_pos3();
TexCoordd w1 = v1->get_uv(name);
TexCoordd w2 = v2->get_uv(name);
TexCoordd w3 = v3->get_uv(name);
double x1 = p2[0] - p1[0];
double x2 = p3[0] - p1[0];
double y1 = p2[1] - p1[1];
double y2 = p3[1] - p1[1];
double z1 = p2[2] - p1[2];
double z2 = p3[2] - p1[2];
double s1 = w2[0] - w1[0];
double s2 = w3[0] - w1[0];
double t1 = w2[1] - w1[1];
double t2 = w3[1] - w1[1];
double r = 1.0f / (s1 * t2 - s2 * t1);
ref._sdir.set((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r);
ref._tdir.set((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r);
// Store the vertex referenced to the polygon.
ref._vertex = i;
collection[value].push_back(ref);
}
}
}
}
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
EggGroupNode *group = DCAST(EggGroupNode, child);
// We can't share vertices across an Instance node. Don't
// even bother trying. Instead, just restart.
if (group->is_under_instance()) {
group->recompute_tangent_binormal(uv_name);
} else {
group->r_collect_tangent_binormal(uv_name, collection);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: EggGroupNode::do_compute_tangent_binormal
// Access: Private
// Description: This is part of the implementation of
// recompute_tangent_binormal(). It accepts a group of
// polygons and their common normals and UV's, and
// computes the tangent and binormal for all their
// shared vertices.
////////////////////////////////////////////////////////////////////
void EggGroupNode::
do_compute_tangent_binormal(const TBNVertexValue &value,
const TBNVertexGroup &group) {
nassertv(!group.empty());
// Accumulate together all of the s vectors and t vectors computed
// for the different vertices that are together here.
Normald sdir(0.0, 0.0, 0.0);
Normald tdir(0.0, 0.0, 0.0);
TBNVertexGroup::const_iterator gi;
for (gi = group.begin(); gi != group.end(); ++gi) {
const TBNVertexReference &ref = (*gi);
sdir += ref._sdir;
tdir += ref._tdir;
}
Normald tangent = (sdir - value._normal * value._normal.dot(sdir));
tangent.normalize();
Normald binormal = cross(value._normal, tangent);
if (dot(binormal, tdir) < 0.0f) {
binormal = -binormal;
}
// Shouldn't need to normalize this, but we do just for good measure.
binormal.normalize();
// Now we have the common tangent and binormal; apply them to all
// the vertices.
for (gi = group.begin(); gi != group.end(); ++gi) {
const TBNVertexReference &ref = (*gi);
EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
EggVertexPool *pool = vertex->get_pool();
EggVertex new_vertex(*vertex);
EggVertexUV *uv_obj = new_vertex.get_uv_obj(value._uv_name);
nassertv(uv_obj != (EggVertexUV *)NULL);
uv_obj->set_tangent(tangent);
uv_obj->set_binormal(binormal);
EggVertex *unique = pool->create_unique_vertex(new_vertex);
unique->copy_grefs_from(*vertex);
ref._polygon->set_vertex(ref._vertex, unique);
}
}

View File

@ -27,7 +27,7 @@
#include "typedObject.h" #include "typedObject.h"
#include "pointerTo.h" #include "pointerTo.h"
#include "luse.h" #include "luse.h"
#include "globPattern.h"
#include "plist.h" #include "plist.h"
class EggTextureCollection; class EggTextureCollection;
@ -130,6 +130,8 @@ PUBLISHED:
void recompute_polygon_normals(CoordinateSystem cs = CS_default); void recompute_polygon_normals(CoordinateSystem cs = CS_default);
void strip_normals(); void strip_normals();
void recompute_tangent_binormal(const GlobPattern &uv_name);
enum TriangulateFlags { enum TriangulateFlags {
T_polygon = 0x001, T_polygon = 0x001,
T_convex = 0x002, T_convex = 0x002,
@ -197,6 +199,30 @@ private:
double threshold, CoordinateSystem cs); double threshold, CoordinateSystem cs);
void do_compute_vertex_normals(const NVertexGroup &group); void do_compute_vertex_normals(const NVertexGroup &group);
// This bit is in support of recompute_tangent_binormal().
class TBNVertexReference {
public:
EggPolygon *_polygon;
size_t _vertex;
LVector3d _sdir;
LVector3d _tdir;
};
class TBNVertexValue {
public:
INLINE bool operator < (const TBNVertexValue &other) const;
Vertexd _pos;
Normald _normal;
string _uv_name;
TexCoordd _uv;
};
typedef pvector<TBNVertexReference> TBNVertexGroup;
typedef pmap<TBNVertexValue, TBNVertexGroup> TBNVertexCollection;
void r_collect_tangent_binormal(const GlobPattern &uv_name,
TBNVertexCollection &collection);
void do_compute_tangent_binormal(const TBNVertexValue &value,
const TBNVertexGroup &group);
public: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {
return _type_handle; return _type_handle;

View File

@ -412,6 +412,11 @@ transform(const LMatrix4d &mat) {
morph.set_offset((*mi).get_offset() * mat); morph.set_offset((*mi).get_offset() * mat);
} }
UVMap::iterator ui;
for (ui = _uv_map.begin(); ui != _uv_map.end(); ++ui) {
(*ui).second->transform(mat);
}
EggAttributes::transform(mat); EggAttributes::transform(mat);
} }

View File

@ -295,26 +295,34 @@ has_uvs() const {
// Function: EggVertexPool::get_uv_names // Function: EggVertexPool::get_uv_names
// Access: Public // Access: Public
// Description: Returns the list of UV names that are defined by any // Description: Returns the list of UV names that are defined by any
// vertices in the pool. It is the user's // vertices in the pool. Also returns the subset of UV
// responsibility to clear the vector before calling // names that define the tangent and binormal. It is
// this method. // the user's responsibility to clear both vectors
// before calling this method.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void EggVertexPool:: void EggVertexPool::
get_uv_names(vector_string &uv_names) const { get_uv_names(vector_string &uv_names, vector_string &tbn_names) const {
pset<string> names; pset<string> uv_names_set, tbn_names_set;
IndexVertices::const_iterator ivi; IndexVertices::const_iterator ivi;
for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
EggVertex *vertex = (*ivi).second; EggVertex *vertex = (*ivi).second;
EggVertex::const_uv_iterator uvi; EggVertex::const_uv_iterator uvi;
for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) { for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
names.insert((*uvi)->get_name()); EggVertexUV *uv_obj = (*uvi);
uv_names_set.insert(uv_obj->get_name());
if (uv_obj->has_tangent() && uv_obj->has_binormal()) {
tbn_names_set.insert(uv_obj->get_name());
}
} }
} }
pset<string>::const_iterator si; pset<string>::const_iterator si;
for (si = names.begin(); si != names.end(); ++si) { for (si = uv_names_set.begin(); si != uv_names_set.end(); ++si) {
uv_names.push_back(*si); uv_names.push_back(*si);
} }
for (si = tbn_names_set.begin(); si != tbn_names_set.end(); ++si) {
tbn_names.push_back(*si);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -98,7 +98,7 @@ PUBLISHED:
bool has_colors() const; bool has_colors() const;
bool has_nonwhite_colors() const; bool has_nonwhite_colors() const;
bool has_uvs() const; bool has_uvs() const;
void get_uv_names(vector_string &uv_names) const; void get_uv_names(vector_string &uv_names, vector_string &tbn_names) const;
public: public:
// Can be used to traverse all the vertices in index number order. // Can be used to traverse all the vertices in index number order.

View File

@ -36,3 +36,87 @@ INLINE void EggVertexUV::
set_uv(const TexCoordd &uv) { set_uv(const TexCoordd &uv) {
_uv = uv; _uv = uv;
} }
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::has_tangent
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool EggVertexUV::
has_tangent() const {
return (_flags & F_has_tangent) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::get_tangent
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE const Normald &EggVertexUV::
get_tangent() const {
nassertr(has_tangent(), _tangent);
return _tangent;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::set_tangent
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggVertexUV::
set_tangent(const Normald &tangent) {
_tangent = tangent;
_flags |= F_has_tangent;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::clear_tangent
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggVertexUV::
clear_tangent() {
_flags &= ~F_has_tangent;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::has_binormal
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool EggVertexUV::
has_binormal() const {
return (_flags & F_has_binormal) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::get_binormal
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE const Normald &EggVertexUV::
get_binormal() const {
nassertr(has_binormal(), _binormal);
return _binormal;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::set_binormal
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggVertexUV::
set_binormal(const Normald &binormal) {
_binormal = binormal;
_flags |= F_has_binormal;
}
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::clear_binormal
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggVertexUV::
clear_binormal() {
_flags &= ~F_has_binormal;
}

View File

@ -31,6 +31,7 @@ TypeHandle EggVertexUV::_type_handle;
EggVertexUV:: EggVertexUV::
EggVertexUV(const string &name, const TexCoordd &uv) : EggVertexUV(const string &name, const TexCoordd &uv) :
EggNamedObject(name), EggNamedObject(name),
_flags(0),
_uv(uv) _uv(uv)
{ {
} }
@ -44,6 +45,9 @@ EggVertexUV::
EggVertexUV(const EggVertexUV &copy) : EggVertexUV(const EggVertexUV &copy) :
EggNamedObject(copy), EggNamedObject(copy),
_duvs(copy._duvs), _duvs(copy._duvs),
_flags(copy._flags),
_tangent(copy._tangent),
_binormal(copy._binormal),
_uv(copy._uv) _uv(copy._uv)
{ {
} }
@ -57,6 +61,9 @@ EggVertexUV &EggVertexUV::
operator = (const EggVertexUV &copy) { operator = (const EggVertexUV &copy) {
EggNamedObject::operator = (copy); EggNamedObject::operator = (copy);
_duvs = copy._duvs; _duvs = copy._duvs;
_flags = copy._flags;
_tangent = copy._tangent;
_binormal = copy._binormal;
_uv = copy._uv; _uv = copy._uv;
return (*this); return (*this);
@ -71,6 +78,25 @@ EggVertexUV::
~EggVertexUV() { ~EggVertexUV() {
} }
////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::transform
// Access: Published, Virtual
// Description: Applies the indicated transformation matrix to the
// UV's tangent and/or binormal. This does nothing if
// there is no tangent or binormal.
////////////////////////////////////////////////////////////////////
void EggVertexUV::
transform(const LMatrix4d &mat) {
if (has_tangent()) {
_tangent = _tangent * mat;
_tangent.normalize();
}
if (has_binormal()) {
_binormal = _binormal * mat;
_binormal.normalize();
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: EggVertexUV::write // Function: EggVertexUV::write
// Access: Public // Access: Public
@ -83,12 +109,20 @@ write(ostream &out, int indent_level) const {
inline_name += ' '; inline_name += ' ';
} }
if (_duvs.empty()) { if (_duvs.empty() && _flags == 0) {
indent(out, indent_level) indent(out, indent_level)
<< "<UV> " << inline_name << "{ " << get_uv() << " }\n"; << "<UV> " << inline_name << "{ " << get_uv() << " }\n";
} else { } else {
indent(out, indent_level) << "<UV> " << inline_name << "{\n"; indent(out, indent_level) << "<UV> " << inline_name << "{\n";
indent(out, indent_level+2) << get_uv() << "\n"; indent(out, indent_level+2) << get_uv() << "\n";
if (has_tangent()) {
indent(out, indent_level + 2)
<< "<Tangent> { " << get_tangent() << " }\n";
}
if (has_binormal()) {
indent(out, indent_level + 2)
<< "<Binormal> { " << get_binormal() << " }\n";
}
_duvs.write(out, indent_level+2); _duvs.write(out, indent_level+2);
indent(out, indent_level) << "}\n"; indent(out, indent_level) << "}\n";
} }
@ -103,11 +137,29 @@ write(ostream &out, int indent_level) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int EggVertexUV:: int EggVertexUV::
compare_to(const EggVertexUV &other) const { compare_to(const EggVertexUV &other) const {
int compare = if (_flags != other._flags) {
_uv.compare_to(other._uv, egg_parameters->_uv_threshold); return _flags - other._flags;
}
int compare;
compare = _uv.compare_to(other._uv, egg_parameters->_uv_threshold);
if (compare != 0) { if (compare != 0) {
return compare; return compare;
} }
if (has_tangent()) {
compare = _tangent.compare_to(other._tangent, egg_parameters->_normal_threshold);
if (compare != 0) {
return compare;
}
}
if (has_binormal()) {
compare = _binormal.compare_to(other._binormal, egg_parameters->_normal_threshold);
if (compare != 0) {
return compare;
}
}
if (_duvs != other._duvs) { if (_duvs != other._duvs) {
return _duvs < other._duvs ? -1 : 1; return _duvs < other._duvs ? -1 : 1;
} }

View File

@ -43,12 +43,32 @@ PUBLISHED:
INLINE const TexCoordd &get_uv() const; INLINE const TexCoordd &get_uv() const;
INLINE void set_uv(const TexCoordd &texCoord); INLINE void set_uv(const TexCoordd &texCoord);
INLINE bool has_tangent() const;
INLINE const Normald &get_tangent() const;
INLINE void set_tangent(const Normald &tangent);
INLINE void clear_tangent();
INLINE bool has_binormal() const;
INLINE const Normald &get_binormal() const;
INLINE void set_binormal(const Normald &binormal);
INLINE void clear_binormal();
void transform(const LMatrix4d &mat);
void write(ostream &out, int indent_level) const; void write(ostream &out, int indent_level) const;
int compare_to(const EggVertexUV &other) const; int compare_to(const EggVertexUV &other) const;
EggMorphTexCoordList _duvs; EggMorphTexCoordList _duvs;
private: private:
enum Flags {
F_has_tangent = 0x001,
F_has_binormal = 0x002,
};
int _flags;
Normald _tangent;
Normald _binormal;
TexCoordd _uv; TexCoordd _uv;
public: public:

File diff suppressed because it is too large Load Diff

View File

@ -351,6 +351,10 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
accept(); accept();
return BILLBOARDCENTER; return BILLBOARDCENTER;
} }
"<BINORMAL>" {
accept();
return BINORMAL;
}
"<BUNDLE>" { "<BUNDLE>" {
accept(); accept();
return BUNDLE; return BUNDLE;
@ -579,6 +583,10 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
accept(); accept();
return TAG; return TAG;
} }
"<TANGENT>" {
accept();
return TANGENT;
}
"<TEXLIST>" { "<TEXLIST>" {
accept(); accept();
return TEXLIST; return TEXLIST;

File diff suppressed because it is too large Load Diff

View File

@ -8,85 +8,87 @@
# define BFACE 261 # define BFACE 261
# define BILLBOARD 262 # define BILLBOARD 262
# define BILLBOARDCENTER 263 # define BILLBOARDCENTER 263
# define BUNDLE 264 # define BINORMAL 264
# define CLOSED 265 # define BUNDLE 265
# define COLLIDE 266 # define CLOSED 266
# define COMMENT 267 # define COLLIDE 267
# define COMPONENT 268 # define COMMENT 268
# define COORDSYSTEM 269 # define COMPONENT 269
# define CV 270 # define COORDSYSTEM 270
# define DART 271 # define CV 271
# define DNORMAL 272 # define DART 272
# define DRGBA 273 # define DNORMAL 273
# define DUV 274 # define DRGBA 274
# define DXYZ 275 # define DUV 275
# define DCS 276 # define DXYZ 276
# define DISTANCE 277 # define DCS 277
# define DTREF 278 # define DISTANCE 278
# define DYNAMICVERTEXPOOL 279 # define DTREF 279
# define EXTERNAL_FILE 280 # define DYNAMICVERTEXPOOL 280
# define FLIGHT 281 # define EXTERNAL_FILE 281
# define GROUP 282 # define FLIGHT 282
# define HIP 283 # define GROUP 283
# define INTANGENT 284 # define HIP 284
# define JOINT 285 # define INTANGENT 285
# define KNOTS 286 # define JOINT 286
# define INCLUDE 287 # define KNOTS 287
# define INSTANCE 288 # define INCLUDE 288
# define LINE 289 # define INSTANCE 289
# define LOOP 290 # define LINE 290
# define MATERIAL 291 # define LOOP 291
# define MATRIX3 292 # define MATERIAL 292
# define MATRIX4 293 # define MATRIX3 293
# define MODEL 294 # define MATRIX4 294
# define MREF 295 # define MODEL 295
# define NORMAL 296 # define MREF 296
# define NURBSCURVE 297 # define NORMAL 297
# define NURBSSURFACE 298 # define NURBSCURVE 298
# define OBJECTTYPE 299 # define NURBSSURFACE 299
# define ORDER 300 # define OBJECTTYPE 300
# define OUTTANGENT 301 # define ORDER 301
# define POINTLIGHT 302 # define OUTTANGENT 302
# define POLYGON 303 # define POINTLIGHT 303
# define REF 304 # define POLYGON 304
# define RGBA 305 # define REF 305
# define ROTATE 306 # define RGBA 306
# define ROTX 307 # define ROTATE 307
# define ROTY 308 # define ROTX 308
# define ROTZ 309 # define ROTY 309
# define SANIM 310 # define ROTZ 310
# define SCALAR 311 # define SANIM 311
# define SCALE 312 # define SCALAR 312
# define SEQUENCE 313 # define SCALE 313
# define SHADING 314 # define SEQUENCE 314
# define SWITCH 315 # define SHADING 315
# define SWITCHCONDITION 316 # define SWITCH 316
# define TABLE 317 # define SWITCHCONDITION 317
# define TABLE_V 318 # define TABLE 318
# define TAG 319 # define TABLE_V 319
# define TEXLIST 320 # define TAG 320
# define TEXTURE 321 # define TANGENT 321
# define TLENGTHS 322 # define TEXLIST 322
# define TRANSFORM 323 # define TEXTURE 323
# define TRANSLATE 324 # define TLENGTHS 324
# define TREF 325 # define TRANSFORM 325
# define TRIANGLEFAN 326 # define TRANSLATE 326
# define TRIANGLESTRIP 327 # define TREF 327
# define TRIM 328 # define TRIANGLEFAN 328
# define TXT 329 # define TRIANGLESTRIP 329
# define UKNOTS 330 # define TRIM 330
# define UV 331 # define TXT 331
# define VKNOTS 332 # define UKNOTS 332
# define VERTEX 333 # define UV 333
# define VERTEXANIM 334 # define VKNOTS 334
# define VERTEXPOOL 335 # define VERTEX 335
# define VERTEXREF 336 # define VERTEXANIM 336
# define XFMANIM 337 # define VERTEXPOOL 337
# define XFMSANIM 338 # define VERTEXREF 338
# define START_EGG 339 # define XFMANIM 339
# define START_GROUP_BODY 340 # define XFMSANIM 340
# define START_TEXTURE_BODY 341 # define START_EGG 341
# define START_PRIMITIVE_BODY 342 # define START_GROUP_BODY 342
# define START_TEXTURE_BODY 343
# define START_PRIMITIVE_BODY 344
extern YYSTYPE eggyylval; extern YYSTYPE eggyylval;

View File

@ -146,7 +146,7 @@ egg_cleanup_parser() {
%token <_ulong> ULONG %token <_ulong> ULONG
%token <_string> STRING %token <_string> STRING
%token BEZIERCURVE BFACE BILLBOARD BILLBOARDCENTER BUNDLE CLOSED %token BEZIERCURVE BFACE BILLBOARD BILLBOARDCENTER BINORMAL BUNDLE CLOSED
%token COLLIDE COMMENT COMPONENT %token COLLIDE COMMENT COMPONENT
%token COORDSYSTEM CV DART %token COORDSYSTEM CV DART
%token DNORMAL DRGBA DUV DXYZ DCS DISTANCE DTREF %token DNORMAL DRGBA DUV DXYZ DCS DISTANCE DTREF
@ -157,7 +157,7 @@ egg_cleanup_parser() {
%token NURBSCURVE NURBSSURFACE OBJECTTYPE ORDER %token NURBSCURVE NURBSSURFACE OBJECTTYPE ORDER
%token OUTTANGENT POINTLIGHT POLYGON REF RGBA ROTATE ROTX ROTY ROTZ %token OUTTANGENT POINTLIGHT POLYGON REF RGBA ROTATE ROTX ROTY ROTZ
%token SANIM SCALAR SCALE SEQUENCE SHADING SWITCH SWITCHCONDITION %token SANIM SCALAR SCALE SEQUENCE SHADING SWITCH SWITCHCONDITION
%token TABLE TABLE_V TAG TEXLIST TEXTURE TLENGTHS TRANSFORM TRANSLATE %token TABLE TABLE_V TAG TANGENT TEXLIST TEXTURE TLENGTHS TRANSFORM TRANSLATE
%token TREF TRIANGLEFAN TRIANGLESTRIP %token TREF TRIANGLEFAN TRIANGLESTRIP
%token TRIM TXT UKNOTS UV VKNOTS VERTEX VERTEXANIM %token TRIM TXT UKNOTS UV VKNOTS VERTEX VERTEXANIM
%token VERTEXPOOL VERTEXREF %token VERTEXPOOL VERTEXREF
@ -952,6 +952,22 @@ vertex_uv_body:
real real real real
{ {
DCAST(EggVertexUV, egg_stack.back())->set_uv(TexCoordd($1, $2)); DCAST(EggVertexUV, egg_stack.back())->set_uv(TexCoordd($1, $2));
}
| vertex_uv_body TANGENT '{' real real real '}'
{
if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) {
eggyywarning("Ignoring repeated tangent");
} else {
DCAST(EggVertexUV, egg_stack.back())->set_tangent(Normald($4, $5, $6));
}
}
| vertex_uv_body BINORMAL '{' real real real '}'
{
if (DCAST(EggVertexUV, egg_stack.back())->has_binormal()) {
eggyywarning("Ignoring repeated binormal");
} else {
DCAST(EggVertexUV, egg_stack.back())->set_binormal(Normald($4, $5, $6));
}
} }
| vertex_uv_body DUV string '{' real real '}' | vertex_uv_body DUV string '{' real real '}'
{ {

View File

@ -371,21 +371,85 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
// Now, is our parent node a GeomNode, or just an ordinary // Now, is our parent node a GeomNode, or just an ordinary
// PandaNode? If it's a GeomNode, we can add the new Geom directly // PandaNode? If it's a GeomNode, we can add the new Geom directly
// to our parent; otherwise, we need to create a new node. // to our parent; otherwise, we need to create a new node.
PT(GeomNode) geom_node;
if (parent->is_geom_node() && !render_state->_hidden) { if (parent->is_geom_node() && !render_state->_hidden) {
DCAST(GeomNode, parent)->add_geom(geom, render_state->_state); geom_node = DCAST(GeomNode, parent);
} else { } else {
PT(GeomNode) geom_node = new GeomNode(egg_bin->get_name()); geom_node = new GeomNode(egg_bin->get_name());
if (render_state->_hidden) { if (render_state->_hidden) {
parent->add_stashed(geom_node); parent->add_stashed(geom_node);
} else { } else {
parent->add_child(geom_node); parent->add_child(geom_node);
} }
geom_node->add_geom(geom, render_state->_state); }
geom_node->add_geom(geom, render_state->_state);
if (egg_show_normals) {
show_normals(vertex_pool, geom_node);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: EggLoader::show_normals
// Access: Private
// Description: In the presence of egg-show-normals, generate some
// additional geometry to represent the normals,
// tangents, and binormals of each vertex.
////////////////////////////////////////////////////////////////////
void EggLoader::
show_normals(EggVertexPool *vertex_pool, GeomNode *geom_node) {
PT(GeomPrimitive) primitive = new GeomLines(Geom::UH_static);
CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3cp();
PT(GeomVertexData) vertex_data =
new GeomVertexData(vertex_pool->get_name(), format, Geom::UH_static);
GeomVertexWriter vertex(vertex_data, InternalName::get_vertex());
GeomVertexWriter color(vertex_data, InternalName::get_color());
EggVertexPool::const_iterator vi;
for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
EggVertex *vert = (*vi);
LPoint3d pos = vert->get_pos3();
if (vert->has_normal()) {
vertex.add_data3f(LCAST(float, pos));
vertex.add_data3f(LCAST(float, pos + vert->get_normal() * egg_normal_scale));
color.add_data4f(1.0f, 0.0f, 0.0f, 1.0f);
color.add_data4f(1.0f, 0.0f, 0.0f, 1.0f);
primitive->add_next_vertices(2);
primitive->close_primitive();
}
// Also look for tangents and binormals in each texture coordinate
// set.
EggVertex::const_uv_iterator uvi;
for (uvi = vert->uv_begin(); uvi != vert->uv_end(); ++uvi) {
EggVertexUV *uv_obj = (*uvi);
if (uv_obj->has_tangent()) {
vertex.add_data3f(LCAST(float, pos));
vertex.add_data3f(LCAST(float, pos + uv_obj->get_tangent() * egg_normal_scale));
color.add_data4f(0.0f, 1.0f, 0.0f, 1.0f);
color.add_data4f(0.0f, 1.0f, 0.0f, 1.0f);
primitive->add_next_vertices(2);
primitive->close_primitive();
}
if (uv_obj->has_binormal()) {
vertex.add_data3f(LCAST(float, pos));
vertex.add_data3f(LCAST(float, pos + uv_obj->get_binormal() * egg_normal_scale));
color.add_data4f(0.0f, 0.0f, 1.0f, 1.0f);
color.add_data4f(0.0f, 0.0f, 1.0f, 1.0f);
primitive->add_next_vertices(2);
primitive->close_primitive();
}
} }
} }
return; PT(Geom) geom = new Geom;
geom->set_vertex_data(vertex_data);
geom->add_primitive(primitive);
geom_node->add_geom(geom);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1659,8 +1723,8 @@ make_vertex_data(const EggRenderState *render_state,
Geom::NT_packed_dabc, Geom::C_color); Geom::NT_packed_dabc, Geom::C_color);
} }
vector_string uv_names; vector_string uv_names, tbn_names;
vertex_pool->get_uv_names(uv_names); vertex_pool->get_uv_names(uv_names, tbn_names);
vector_string::const_iterator ni; vector_string::const_iterator ni;
for (ni = uv_names.begin(); ni != uv_names.end(); ++ni) { for (ni = uv_names.begin(); ni != uv_names.end(); ++ni) {
string name = (*ni); string name = (*ni);
@ -1669,8 +1733,19 @@ make_vertex_data(const EggRenderState *render_state,
} }
PT(InternalName) iname = InternalName::get_texcoord_name(name); PT(InternalName) iname = InternalName::get_texcoord_name(name);
array_format->add_column array_format->add_column
(iname, 2, (iname, 2, Geom::NT_float32, Geom::C_texcoord);
Geom::NT_float32, Geom::C_texcoord); }
for (ni = tbn_names.begin(); ni != tbn_names.end(); ++ni) {
string name = (*ni);
if (name == "default") {
name = string();
}
PT(InternalName) iname = InternalName::get_tangent_name(name);
array_format->add_column
(iname, 3, Geom::NT_float32, Geom::C_vector);
iname = InternalName::get_binormal_name(name);
array_format->add_column
(iname, 3, Geom::NT_float32, Geom::C_vector);
} }
PT(GeomVertexFormat) temp_format = new GeomVertexFormat(array_format); PT(GeomVertexFormat) temp_format = new GeomVertexFormat(array_format);
@ -1867,6 +1942,19 @@ make_vertex_data(const EggRenderState *render_state,
gvw.add_data2f(LCAST(float, duv)); gvw.add_data2f(LCAST(float, duv));
} }
} }
// Also add the tangent and binormal, if present.
if (egg_uv->has_tangent() && egg_uv->has_binormal()) {
PT(InternalName) iname = InternalName::get_tangent_name(name);
gvw.set_column(iname);
if (gvw.has_column()) {
LVector3d tangent = egg_uv->get_tangent();
LVector3d binormal = egg_uv->get_binormal();
gvw.add_data3f(LCAST(float, tangent));
gvw.set_column(InternalName::get_binormal_name(name));
gvw.add_data3f(LCAST(float, binormal));
}
}
} }
if (is_dynamic) { if (is_dynamic) {

View File

@ -105,7 +105,9 @@ private:
GeomPrimitive::ShadeModel _shade_model; GeomPrimitive::ShadeModel _shade_model;
}; };
typedef pmap<PrimitiveUnifier, PT(GeomPrimitive) > Primitives; typedef pmap<PrimitiveUnifier, PT(GeomPrimitive) > Primitives;
void show_normals(EggVertexPool *vertex_pool, GeomNode *geom_node);
void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent, void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
const LMatrix4d &mat); const LMatrix4d &mat);
void make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent, void make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,

View File

@ -136,6 +136,19 @@ get_tangent() {
return _tangent; return _tangent;
} }
////////////////////////////////////////////////////////////////////
// Function: InternalName::get_tangent_name
// Access: Published, Static
// Description: Returns the InternalName "tangent.name", where name
// is the supplied string. This is the column header
// for the tangent associated with the named texture
// coordinate set.
////////////////////////////////////////////////////////////////////
INLINE PT(InternalName) InternalName::
get_tangent_name(const string &name) {
return get_tangent()->append(name);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: InternalName::get_binormal // Function: InternalName::get_binormal
// Access: Published, Static // Access: Published, Static
@ -155,6 +168,19 @@ get_binormal() {
return _binormal; return _binormal;
} }
////////////////////////////////////////////////////////////////////
// Function: InternalName::get_binormal_name
// Access: Published, Static
// Description: Returns the InternalName "binormal.name", where name
// is the supplied string. This is the column header
// for the binormal associated with the named texture
// coordinate set.
////////////////////////////////////////////////////////////////////
INLINE PT(InternalName) InternalName::
get_binormal_name(const string &name) {
return get_binormal()->append(name);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: InternalName::get_texcoord // Function: InternalName::get_texcoord
// Access: Published, Static // Access: Published, Static

View File

@ -67,7 +67,9 @@ PUBLISHED:
INLINE static PT(InternalName) get_vertex(); INLINE static PT(InternalName) get_vertex();
INLINE static PT(InternalName) get_normal(); INLINE static PT(InternalName) get_normal();
INLINE static PT(InternalName) get_tangent(); INLINE static PT(InternalName) get_tangent();
INLINE static PT(InternalName) get_tangent_name(const string &name);
INLINE static PT(InternalName) get_binormal(); INLINE static PT(InternalName) get_binormal();
INLINE static PT(InternalName) get_binormal_name(const string &name);
INLINE static PT(InternalName) get_texcoord(); INLINE static PT(InternalName) get_texcoord();
INLINE static PT(InternalName) get_texcoord_name(const string &name); INLINE static PT(InternalName) get_texcoord_name(const string &name);
INLINE static PT(InternalName) get_color(); INLINE static PT(InternalName) get_color();

View File

@ -87,6 +87,18 @@ add_normals_options() {
("nn", "", 48, ("nn", "", 48,
"Preserve normals exactly as they are. This is the default.", "Preserve normals exactly as they are. This is the default.",
&EggBase::dispatch_normals, NULL, &preserve); &EggBase::dispatch_normals, NULL, &preserve);
add_option
("tbn", "name", 48,
"Compute tangent and binormal for the named texture coordinate "
"set(s). The name may include wildcard characters such as * and ?; "
"use \"*\" to recompute tangent and binormal for all texture coordinate "
"sets. "
"The normal must already exist or have been computed via one of the "
"above options. The tangent and binormal are used to implement "
"bump mapping and related texture-based lighting effects. This option "
"may be repeated as necessary to name multiple texture coordinate sets.",
&EggBase::dispatch_vector_string, NULL, &_tbn_names);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -66,6 +66,7 @@ protected:
}; };
NormalsMode _normals_mode; NormalsMode _normals_mode;
double _normals_threshold; double _normals_threshold;
vector_string _tbn_names;
bool _got_transform; bool _got_transform;
LMatrix4d _transform; LMatrix4d _transform;

View File

@ -20,6 +20,7 @@
#include "string_utils.h" #include "string_utils.h"
#include "compose_matrix.h" #include "compose_matrix.h"
#include "globPattern.h"
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: EggWriter::Constructor // Function: EggWriter::Constructor
@ -161,6 +162,14 @@ post_process_egg_file() {
// Do nothing. // Do nothing.
break; break;
} }
for (vector_string::const_iterator si = _tbn_names.begin();
si != _tbn_names.end();
++si) {
GlobPattern uv_name(*si);
nout << "Computing tangent and binormal for \"" << uv_name << "\"\n";
_data->recompute_tangent_binormal(uv_name);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////