From 52dea86a3e1fd2f8ee81aec43ba060d46bd6e755 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 28 Sep 2005 13:53:54 +0000 Subject: [PATCH] From A. Botorabi, "slightly modified osgUtil's TangentSpaceGenerator class to allow the option for using or not using geom's indices for tangent space vectors generation. now, Ruben's code is also used (it was disabled before). in order to keep backward compatibility, the compute method behaves as before in default case." --- include/osgUtil/TangentSpaceGenerator | 71 +- src/osgUtil/TangentSpaceGenerator.cpp | 898 +++++++++++++------------- 2 files changed, 513 insertions(+), 456 deletions(-) diff --git a/include/osgUtil/TangentSpaceGenerator b/include/osgUtil/TangentSpaceGenerator index f158fac0a..05936daea 100644 --- a/include/osgUtil/TangentSpaceGenerator +++ b/include/osgUtil/TangentSpaceGenerator @@ -40,7 +40,7 @@ public: TangentSpaceGenerator(); TangentSpaceGenerator(const TangentSpaceGenerator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY); - void generate(osg::Geometry *geo, int normal_map_tex_unit = 0); + void generate(osg::Geometry *geo, int normal_map_tex_unit = 0, bool use_indices = false); inline osg::Vec4Array *getTangentArray() { return T_.get(); } inline const osg::Vec4Array *getTangentArray() const { return T_.get(); } @@ -55,18 +55,71 @@ public: inline void setBinormalArray(osg::Vec4Array *array) { B_ = array; } inline osg::IndexArray *getIndices() { return indices_.get(); } + protected: + virtual ~TangentSpaceGenerator() {} TangentSpaceGenerator &operator=(const TangentSpaceGenerator &) { return *this; } - void compute_basis_vectors(osg::PrimitiveSet *pset, - const osg::Array *vx, - const osg::Array *nx, - const osg::Array *tx, - const osg::IndexArray *vix, - const osg::IndexArray *nix, - const osg::IndexArray *tix, - int iA, int iB, int iC); + // Base class for computing basis vectors + class BasisVectorsComputer : public osg::Referenced + { + public: + explicit BasisVectorsComputer(TangentSpaceGenerator* base) : base_( base ) {} + + virtual void compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC) = 0; + + protected: + virtual ~BasisVectorsComputer() {} + BasisVectorsComputer(const TangentSpaceGenerator ©, const osg::CopyOp ©op); + + TangentSpaceGenerator* base_; + }; + + // Class for computing basis vectors without using indices + class VectorsComputerNoIndices : public BasisVectorsComputer + { + public: + explicit VectorsComputerNoIndices(TangentSpaceGenerator* base) : BasisVectorsComputer( base ) {} + + void compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC); + + protected: + virtual ~VectorsComputerNoIndices() {} + }; + + // Class for computing basis vectors using indices + class VectorsComputerUsingIndices : public BasisVectorsComputer + { + public: + explicit VectorsComputerUsingIndices(TangentSpaceGenerator* base) : BasisVectorsComputer( base ) {} + + void compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC); + + protected: + virtual ~VectorsComputerUsingIndices() {} + }; private: osg::ref_ptr T_; diff --git a/src/osgUtil/TangentSpaceGenerator.cpp b/src/osgUtil/TangentSpaceGenerator.cpp index 264283d3d..595c2296a 100644 --- a/src/osgUtil/TangentSpaceGenerator.cpp +++ b/src/osgUtil/TangentSpaceGenerator.cpp @@ -1,6 +1,7 @@ #include #include +#include using namespace osgUtil; @@ -20,7 +21,7 @@ TangentSpaceGenerator::TangentSpaceGenerator(const TangentSpaceGenerator ©, { } -void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit) +void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit, bool use_indices) { const osg::Array *vx = geo->getVertexArray(); const osg::IndexArray *vix = geo->getVertexIndices(); @@ -31,6 +32,13 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit if (!vx || !tx) return; + + osg::ref_ptr computer; + if (use_indices) + computer = new VectorsComputerUsingIndices(this); + else + computer = new VectorsComputerNoIndices(this); + unsigned int vertex_count = vx->getNumElements(); if (geo->getVertexIndices() == NULL) { T_->assign(vertex_count, osg::Vec4()); @@ -59,14 +67,14 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit case osg::PrimitiveSet::TRIANGLES: for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2); } break; case osg::PrimitiveSet::QUADS: for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2); + computer->compute(pset, vx, nx, tx, vix, nix, tix, i+2, i+3, i); } break; @@ -78,9 +86,9 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit unsigned iN = static_cast(*pi-2); for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, j, j+1, j+2); } else { - compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, j+1, j, j+2); + computer->compute(pset, vx, nx, tx, vix, nix, tix, j+1, j, j+2); } } j += 2; @@ -88,9 +96,9 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit } else { for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2); } else { - compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, i+1, i, i+2); + computer->compute(pset, vx, nx, tx, vix, nix, tix, i+1, i, i+2); } } } @@ -103,13 +111,13 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit for (osg::DrawArrayLengths::const_iterator pi=dal->begin(); pi!=dal->end(); ++pi) { unsigned iN = static_cast(*pi-2); for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, 0, j+1, j+2); } j += 2; } } else { for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, 2, i+1, i+2); } } break; @@ -151,471 +159,467 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit * version of each (different indices for each one?) */ } -#if 1 // Original compute_basis_vectors implementation - void TangentSpaceGenerator::compute_basis_vectors(osg::PrimitiveSet* pset, - const osg::Array* vx, - const osg::Array* nx, - const osg::Array* tx, - const osg::IndexArray* /*vix*/, - const osg::IndexArray* /*nix*/, - const osg::IndexArray* /*tix*/, - int iA, int iB, int iC) +void TangentSpaceGenerator::VectorsComputerNoIndices::compute(osg::PrimitiveSet *pset, + const osg::Array* vx, + const osg::Array* nx, + const osg::Array* tx, + const osg::IndexArray* /*vix*/, + const osg::IndexArray* /*nix*/, + const osg::IndexArray* /*tix*/, + int iA, int iB, int iC) +{ + iA = pset->index(iA); + iB = pset->index(iB); + iC = pset->index(iC); + + osg::Vec3 P1; + osg::Vec3 P2; + osg::Vec3 P3; + + int i; // VC6 doesn't like for-scoped variables + + switch (vx->getType()) { - iA = pset->index(iA); - iB = pset->index(iB); - iC = pset->index(iC); + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; + } + break; - osg::Vec3 P1; - osg::Vec3 P2; - osg::Vec3 P3; + case osg::Array::Vec3ArrayType: + P1 = static_cast(*vx)[iA]; + P2 = static_cast(*vx)[iB]; + P3 = static_cast(*vx)[iC]; + break; - int i; // VC6 doesn't like for-scoped variables + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; + } + break; - switch (vx->getType()) + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + osg::Vec3 N1; + osg::Vec3 N2; + osg::Vec3 N3; + + if(nx) + { + switch (nx->getType()) { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - P1 = static_cast(*vx)[iA]; - P2 = static_cast(*vx)[iB]; - P3 = static_cast(*vx)[iC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - osg::Vec3 N1; - osg::Vec3 N2; - osg::Vec3 N3; - - if(nx) - { - switch (nx->getType()) - { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - N1 = static_cast(*nx)[iA]; - N2 = static_cast(*nx)[iB]; - N3 = static_cast(*nx)[iC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; } - } + break; - osg::Vec2 uv1; - osg::Vec2 uv2; - osg::Vec2 uv3; + case osg::Array::Vec3ArrayType: + N1 = static_cast(*nx)[iA]; + N2 = static_cast(*nx)[iB]; + N3 = static_cast(*nx)[iC]; + break; - switch (tx->getType()) - { - case osg::Array::Vec2ArrayType: - uv1 = static_cast(*tx)[iA]; - uv2 = static_cast(*tx)[iB]; - uv3 = static_cast(*tx)[iC]; - break; - - case osg::Array::Vec3ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; - } - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - if(nx){ - osg::Vec3 V, T1, T2, T3, B1, B2, B3; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.x() += -V.y() / V.x(); - B1.x() += -V.z() / V.x(); - T2.x() += -V.y() / V.x(); - B2.x() += -V.z() / V.x(); - T3.x() += -V.y() / V.x(); - B3.x() += -V.z() / V.x(); + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; } + break; - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.y() += -V.y() / V.x(); - B1.y() += -V.z() / V.x(); - T2.y() += -V.y() / V.x(); - B2.y() += -V.z() / V.x(); - T3.y() += -V.y() / V.x(); - B3.y() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.z() += -V.y() / V.x(); - B1.z() += -V.z() / V.x(); - T2.z() += -V.y() / V.x(); - B2.z() += -V.z() / V.x(); - T3.z() += -V.y() / V.x(); - B3.z() += -V.z() / V.x(); - } - - osg::Vec3 tempvec; - tempvec = N1 ^ T1; - (*T_)[iA] = osg::Vec4(tempvec ^ N1, 0); - tempvec = B1 ^ N1; - (*B_)[iA] = osg::Vec4(N1 ^ tempvec, 0); - tempvec = N2 ^ T2; - (*T_)[iB] = osg::Vec4(tempvec ^ N2, 0); - tempvec = B2 ^ N2; - (*B_)[iB] = osg::Vec4(N2 ^ tempvec, 0); - tempvec = N3 ^ T3; - (*T_)[iC] = osg::Vec4(tempvec ^ N3, 0); - tempvec = B3 ^ N3; - (*B_)[iC] = osg::Vec4(N3 ^ tempvec, 0); - - (*N_)[iA] += osg::Vec4(N1, 0); - (*N_)[iB] += osg::Vec4(N2, 0); - (*N_)[iC] += osg::Vec4(N3, 0); - } - else{ - osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); - - osg::Vec3 V; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[iA].x() += -V.y() / V.x(); - (*B_)[iA].x() += -V.z() / V.x(); - (*T_)[iB].x() += -V.y() / V.x(); - (*B_)[iB].x() += -V.z() / V.x(); - (*T_)[iC].x() += -V.y() / V.x(); - (*B_)[iC].x() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[iA].y() += -V.y() / V.x(); - (*B_)[iA].y() += -V.z() / V.x(); - (*T_)[iB].y() += -V.y() / V.x(); - (*B_)[iB].y() += -V.z() / V.x(); - (*T_)[iC].y() += -V.y() / V.x(); - (*B_)[iC].y() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[iA].z() += -V.y() / V.x(); - (*B_)[iA].z() += -V.z() / V.x(); - (*T_)[iB].z() += -V.y() / V.x(); - (*B_)[iB].z() += -V.z() / V.x(); - (*T_)[iC].z() += -V.y() / V.x(); - (*B_)[iC].z() += -V.z() / V.x(); - } - - (*N_)[iA] += osg::Vec4(face_normal, 0); - (*N_)[iB] += osg::Vec4(face_normal, 0); - (*N_)[iC] += osg::Vec4(face_normal, 0); + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; } } -#else + osg::Vec2 uv1; + osg::Vec2 uv2; + osg::Vec2 uv3; - // Ruben's new code, supporting index arrays - void TangentSpaceGenerator::compute_basis_vectors(osg::PrimitiveSet *pset, - const osg::Array *vx, - const osg::Array *nx, - const osg::Array *tx, - const osg::IndexArray *vix, - const osg::IndexArray *nix, - const osg::IndexArray *tix, - int iA, int iB, int iC) + switch (tx->getType()) { - int v1 = pset->index(iA); - int v2 = pset->index(iB); - int v3 = pset->index(iC); - int viA = v1; - int viB = v2; - int viC = v3; + case osg::Array::Vec2ArrayType: + uv1 = static_cast(*tx)[iA]; + uv2 = static_cast(*tx)[iB]; + uv3 = static_cast(*tx)[iC]; + break; - if (vix != NULL) { - viA = vix->index(v1); - viB = vix->index(v2); - viC = vix->index(v3); + case osg::Array::Vec3ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; } - int niA = viA; - int niB = viA; - int niC = viA; - int tiA = viA; - int tiB = viA; - int tiC = viA; - if (nix != NULL) { - niA = nix->index(v1); - niB = nix->index(v2); - niC = nix->index(v3); + break; + + case osg::Array::Vec4ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; } - if (tix != NULL) { - tiA = tix->index(v1); - tiB = tix->index(v2); - tiC = tix->index(v3); + break; + + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + if(nx){ + osg::Vec3 V, T1, T2, T3, B1, B2, B3; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.x() += -V.y() / V.x(); + B1.x() += -V.z() / V.x(); + T2.x() += -V.y() / V.x(); + B2.x() += -V.z() / V.x(); + T3.x() += -V.y() / V.x(); + B3.x() += -V.z() / V.x(); } - osg::Vec3 P1; - osg::Vec3 P2; - osg::Vec3 P3; + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.y() += -V.y() / V.x(); + B1.y() += -V.z() / V.x(); + T2.y() += -V.y() / V.x(); + B2.y() += -V.z() / V.x(); + T3.y() += -V.y() / V.x(); + B3.y() += -V.z() / V.x(); + } - int i; // VC6 doesn't like for-scoped variables + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.z() += -V.y() / V.x(); + B1.z() += -V.z() / V.x(); + T2.z() += -V.y() / V.x(); + B2.z() += -V.z() / V.x(); + T3.z() += -V.y() / V.x(); + B3.z() += -V.z() / V.x(); + } - switch (vx->getType()) + osg::Vec3 tempvec; + tempvec = N1 ^ T1; + (*base_->T_)[iA] = osg::Vec4(tempvec ^ N1, 0); + tempvec = B1 ^ N1; + (*base_->B_)[iA] = osg::Vec4(N1 ^ tempvec, 0); + tempvec = N2 ^ T2; + (*base_->T_)[iB] = osg::Vec4(tempvec ^ N2, 0); + tempvec = B2 ^ N2; + (*base_->B_)[iB] = osg::Vec4(N2 ^ tempvec, 0); + tempvec = N3 ^ T3; + (*base_->T_)[iC] = osg::Vec4(tempvec ^ N3, 0); + tempvec = B3 ^ N3; + (*base_->B_)[iC] = osg::Vec4(N3 ^ tempvec, 0); + + (*base_->N_)[iA] += osg::Vec4(N1, 0); + (*base_->N_)[iB] += osg::Vec4(N2, 0); + (*base_->N_)[iC] += osg::Vec4(N3, 0); + } + else{ + osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); + + osg::Vec3 V; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[iA].x() += -V.y() / V.x(); + (*base_->B_)[iA].x() += -V.z() / V.x(); + (*base_->T_)[iB].x() += -V.y() / V.x(); + (*base_->B_)[iB].x() += -V.z() / V.x(); + (*base_->T_)[iC].x() += -V.y() / V.x(); + (*base_->B_)[iC].x() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[iA].y() += -V.y() / V.x(); + (*base_->B_)[iA].y() += -V.z() / V.x(); + (*base_->T_)[iB].y() += -V.y() / V.x(); + (*base_->B_)[iB].y() += -V.z() / V.x(); + (*base_->T_)[iC].y() += -V.y() / V.x(); + (*base_->B_)[iC].y() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[iA].z() += -V.y() / V.x(); + (*base_->B_)[iA].z() += -V.z() / V.x(); + (*base_->T_)[iB].z() += -V.y() / V.x(); + (*base_->B_)[iB].z() += -V.z() / V.x(); + (*base_->T_)[iC].z() += -V.y() / V.x(); + (*base_->B_)[iC].z() += -V.z() / V.x(); + } + + (*base_->N_)[iA] += osg::Vec4(face_normal, 0); + (*base_->N_)[iB] += osg::Vec4(face_normal, 0); + (*base_->N_)[iC] += osg::Vec4(face_normal, 0); + } +} + +// This method is the original code of Ruben +void TangentSpaceGenerator::VectorsComputerUsingIndices::compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC) +{ + int v1 = pset->index(iA); + int v2 = pset->index(iB); + int v3 = pset->index(iC); + int viA = v1; + int viB = v2; + int viC = v3; + + if (vix != NULL) { + viA = vix->index(v1); + viB = vix->index(v2); + viC = vix->index(v3); + } + int niA = viA; + int niB = viA; + int niC = viA; + int tiA = viA; + int tiB = viA; + int tiC = viA; + if (nix != NULL) { + niA = nix->index(v1); + niB = nix->index(v2); + niC = nix->index(v3); + } + if (tix != NULL) { + tiA = tix->index(v1); + tiB = tix->index(v2); + tiC = tix->index(v3); + } + + osg::Vec3 P1; + osg::Vec3 P2; + osg::Vec3 P3; + + int i; // VC6 doesn't like for-scoped variables + + switch (vx->getType()) + { + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; + } + break; + + case osg::Array::Vec3ArrayType: + P1 = static_cast(*vx)[viA]; + P2 = static_cast(*vx)[viB]; + P3 = static_cast(*vx)[viC]; + break; + + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; + } + break; + + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + osg::Vec3 N1; + osg::Vec3 N2; + osg::Vec3 N3; + + if(nx) + { + switch (nx->getType()) { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - P1 = static_cast(*vx)[viA]; - P2 = static_cast(*vx)[viB]; - P3 = static_cast(*vx)[viC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - osg::Vec3 N1; - osg::Vec3 N2; - osg::Vec3 N3; - - if(nx) - { - switch (nx->getType()) - { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - N1 = static_cast(*nx)[niA]; - N2 = static_cast(*nx)[niB]; - N3 = static_cast(*nx)[niC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; } - } + break; - osg::Vec2 uv1; - osg::Vec2 uv2; - osg::Vec2 uv3; + case osg::Array::Vec3ArrayType: + N1 = static_cast(*nx)[niA]; + N2 = static_cast(*nx)[niB]; + N3 = static_cast(*nx)[niC]; + break; - switch (tx->getType()) - { - case osg::Array::Vec2ArrayType: - uv1 = static_cast(*tx)[tiA]; - uv2 = static_cast(*tx)[tiB]; - uv3 = static_cast(*tx)[tiC]; - break; - - case osg::Array::Vec3ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; - } - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator::compute_basis_vectors(,,,) texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - if (nx) - { - osg::Vec3 V, T1, T2, T3, B1, B2, B3; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.x() = -V.y() / V.x(); - B1.x() = -V.z() / V.x(); - T2.x() = -V.y() / V.x(); - B2.x() = -V.z() / V.x(); - T3.x() = -V.y() / V.x(); - B3.x() = -V.z() / V.x(); - } else { - osg::notify(osg::NOTICE)<<"Bu!" << uv1 << " || " << uv2 << " || " << uv3 << std::endl; + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; } + break; - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.y() = -V.y() / V.x(); - B1.y() = -V.z() / V.x(); - T2.y() = -V.y() / V.x(); - B2.y() = -V.z() / V.x(); - T3.y() = -V.y() / V.x(); - B3.y() = -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.z() = -V.y() / V.x(); - B1.z() = -V.z() / V.x(); - T2.z() = -V.y() / V.x(); - B2.z() = -V.z() / V.x(); - T3.z() = -V.y() / V.x(); - B3.z() = -V.z() / V.x(); - } - - (*T_)[v1] = osg::Vec4(T1, 0); - (*B_)[v1] = osg::Vec4(B1, 0); - (*T_)[v2] = osg::Vec4(T2, 0); - (*B_)[v2] = osg::Vec4(B2, 0); - (*T_)[v3] = osg::Vec4(T3, 0); - (*B_)[v3] = osg::Vec4(B3, 0); - - (*N_)[v1] += osg::Vec4(N1, 0); - (*N_)[v2] += osg::Vec4(N2, 0); - (*N_)[v3] += osg::Vec4(N3, 0); - - } - else{ - osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); - - osg::Vec3 V; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[v1].x() += -V.y() / V.x(); - (*B_)[v1].x() += -V.z() / V.x(); - (*T_)[v2].x() += -V.y() / V.x(); - (*B_)[v2].x() += -V.z() / V.x(); - (*T_)[v3].x() += -V.y() / V.x(); - (*B_)[v3].x() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[v1].y() += -V.y() / V.x(); - (*B_)[v1].y() += -V.z() / V.x(); - (*T_)[v2].y() += -V.y() / V.x(); - (*B_)[v2].y() += -V.z() / V.x(); - (*T_)[v3].y() += -V.y() / V.x(); - (*B_)[v3].y() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[v1].z() += -V.y() / V.x(); - (*B_)[v1].z() += -V.z() / V.x(); - (*T_)[v2].z() += -V.y() / V.x(); - (*B_)[v2].z() += -V.z() / V.x(); - (*T_)[v3].z() += -V.y() / V.x(); - (*B_)[v3].z() += -V.z() / V.x(); - } - - (*N_)[v1] += osg::Vec4(face_normal, 0); - (*N_)[v2] += osg::Vec4(face_normal, 0); - (*N_)[v3] += osg::Vec4(face_normal, 0); - } - if ( (*B_)[v1].length() == 0 || (*B_)[v2].length() == 0 || (*B_)[v3].length() == 0) { - osg::notify(osg::WARN) << "WARNING: zero binormal/s!" << std::endl; - osg::notify(osg::WARN) << " " << P1 << "|" << P2 << "|" << P3 << std::endl; - osg::notify(osg::WARN) << " " << iA << "|" << iB << "|" << iC << std::endl; + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; } } -#endif + + osg::Vec2 uv1; + osg::Vec2 uv2; + osg::Vec2 uv3; + + switch (tx->getType()) + { + case osg::Array::Vec2ArrayType: + uv1 = static_cast(*tx)[tiA]; + uv2 = static_cast(*tx)[tiB]; + uv3 = static_cast(*tx)[tiC]; + break; + + case osg::Array::Vec3ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; + } + break; + + case osg::Array::Vec4ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; + } + break; + + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator::compute_basis_vectors(,,,) texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + if (nx) + { + osg::Vec3 V, T1, T2, T3, B1, B2, B3; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.x() = -V.y() / V.x(); + B1.x() = -V.z() / V.x(); + T2.x() = -V.y() / V.x(); + B2.x() = -V.z() / V.x(); + T3.x() = -V.y() / V.x(); + B3.x() = -V.z() / V.x(); + } else { + osg::notify(osg::NOTICE)<<"Bu!" << uv1 << " || " << uv2 << " || " << uv3 << std::endl; + } + + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.y() = -V.y() / V.x(); + B1.y() = -V.z() / V.x(); + T2.y() = -V.y() / V.x(); + B2.y() = -V.z() / V.x(); + T3.y() = -V.y() / V.x(); + B3.y() = -V.z() / V.x(); + } + + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.z() = -V.y() / V.x(); + B1.z() = -V.z() / V.x(); + T2.z() = -V.y() / V.x(); + B2.z() = -V.z() / V.x(); + T3.z() = -V.y() / V.x(); + B3.z() = -V.z() / V.x(); + } + + (*base_->T_)[v1] = osg::Vec4(T1, 0); + (*base_->B_)[v1] = osg::Vec4(B1, 0); + (*base_->T_)[v2] = osg::Vec4(T2, 0); + (*base_->B_)[v2] = osg::Vec4(B2, 0); + (*base_->T_)[v3] = osg::Vec4(T3, 0); + (*base_->B_)[v3] = osg::Vec4(B3, 0); + + (*base_->N_)[v1] += osg::Vec4(N1, 0); + (*base_->N_)[v2] += osg::Vec4(N2, 0); + (*base_->N_)[v3] += osg::Vec4(N3, 0); + + } + else{ + osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); + + osg::Vec3 V; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[v1].x() += -V.y() / V.x(); + (*base_->B_)[v1].x() += -V.z() / V.x(); + (*base_->T_)[v2].x() += -V.y() / V.x(); + (*base_->B_)[v2].x() += -V.z() / V.x(); + (*base_->T_)[v3].x() += -V.y() / V.x(); + (*base_->B_)[v3].x() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[v1].y() += -V.y() / V.x(); + (*base_->B_)[v1].y() += -V.z() / V.x(); + (*base_->T_)[v2].y() += -V.y() / V.x(); + (*base_->B_)[v2].y() += -V.z() / V.x(); + (*base_->T_)[v3].y() += -V.y() / V.x(); + (*base_->B_)[v3].y() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[v1].z() += -V.y() / V.x(); + (*base_->B_)[v1].z() += -V.z() / V.x(); + (*base_->T_)[v2].z() += -V.y() / V.x(); + (*base_->B_)[v2].z() += -V.z() / V.x(); + (*base_->T_)[v3].z() += -V.y() / V.x(); + (*base_->B_)[v3].z() += -V.z() / V.x(); + } + + (*base_->N_)[v1] += osg::Vec4(face_normal, 0); + (*base_->N_)[v2] += osg::Vec4(face_normal, 0); + (*base_->N_)[v3] += osg::Vec4(face_normal, 0); + } + if ( (*base_->B_)[v1].length() == 0 || (*base_->B_)[v2].length() == 0 || (*base_->B_)[v3].length() == 0) { + osg::notify(osg::WARN) << "WARNING: zero binormal/s!" << std::endl; + osg::notify(osg::WARN) << " " << P1 << "|" << P2 << "|" << P3 << std::endl; + osg::notify(osg::WARN) << " " << iA << "|" << iB << "|" << iC << std::endl; + } +}