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."
This commit is contained in:
Robert Osfield 2005-09-28 13:53:54 +00:00
parent 9e5eed280d
commit 52dea86a3e
2 changed files with 513 additions and 456 deletions

View File

@ -40,7 +40,7 @@ public:
TangentSpaceGenerator();
TangentSpaceGenerator(const TangentSpaceGenerator &copy, const osg::CopyOp &copyop = 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 &copy, const osg::CopyOp &copyop);
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<osg::Vec4Array> T_;

View File

@ -1,6 +1,7 @@
#include <osgUtil/TangentSpaceGenerator>
#include <osg/Notify>
#include <osg/io_utils>
using namespace osgUtil;
@ -20,7 +21,7 @@ TangentSpaceGenerator::TangentSpaceGenerator(const TangentSpaceGenerator &copy,
{
}
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<BasisVectorsComputer> 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; i<N; i+=3) {
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2);
computer->compute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2);
}
break;
case osg::PrimitiveSet::QUADS:
for (i=0; i<N; i+=4) {
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2);
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, i+2, i+3, i);
computer->compute(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<unsigned>(*pi-2);
for (i=0; i<iN; ++i, ++j) {
if ((i%2) == 0) {
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, j, j+1, j+2);
computer->compute(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; i<N-2; ++i) {
if ((i%2) == 0) {
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2);
computer->compute(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<unsigned>(*pi-2);
for (i=0; i<iN; ++i) {
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, 0, j+1, j+2);
computer->compute(pset, vx, nx, tx, vix, nix, tix, 0, j+1, j+2);
}
j += 2;
}
} else {
for (i=0; i<N-2; ++i) {
compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, 2, i+1, i+2);
computer->compute(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<const osg::Vec2Array&>(*vx)[iA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iC].ptr()[i];
}
break;
osg::Vec3 P1;
osg::Vec3 P2;
osg::Vec3 P3;
case osg::Array::Vec3ArrayType:
P1 = static_cast<const osg::Vec3Array&>(*vx)[iA];
P2 = static_cast<const osg::Vec3Array&>(*vx)[iB];
P3 = static_cast<const osg::Vec3Array&>(*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<const osg::Vec4Array&>(*vx)[iA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[iB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*vx)[iA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iC].ptr()[i];
}
break;
case osg::Array::Vec3ArrayType:
P1 = static_cast<const osg::Vec3Array&>(*vx)[iA];
P2 = static_cast<const osg::Vec3Array&>(*vx)[iB];
P3 = static_cast<const osg::Vec3Array&>(*vx)[iC];
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<3; ++i) {
P1.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[iA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[iB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*nx)[iA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iC].ptr()[i];
}
break;
case osg::Array::Vec3ArrayType:
N1 = static_cast<const osg::Vec3Array&>(*nx)[iA];
N2 = static_cast<const osg::Vec3Array&>(*nx)[iB];
N3 = static_cast<const osg::Vec3Array&>(*nx)[iC];
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<3; ++i) {
N1.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[iA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[iB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*nx)[iA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iC].ptr()[i];
}
}
break;
osg::Vec2 uv1;
osg::Vec2 uv2;
osg::Vec2 uv3;
case osg::Array::Vec3ArrayType:
N1 = static_cast<const osg::Vec3Array&>(*nx)[iA];
N2 = static_cast<const osg::Vec3Array&>(*nx)[iB];
N3 = static_cast<const osg::Vec3Array&>(*nx)[iC];
break;
switch (tx->getType())
{
case osg::Array::Vec2ArrayType:
uv1 = static_cast<const osg::Vec2Array&>(*tx)[iA];
uv2 = static_cast<const osg::Vec2Array&>(*tx)[iB];
uv3 = static_cast<const osg::Vec2Array&>(*tx)[iC];
break;
case osg::Array::Vec3ArrayType:
for (i=0; i<2; ++i) {
uv1.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iC].ptr()[i];
}
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<2; ++i) {
uv1.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[iA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[iB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec4Array&>(*nx)[iA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[iB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*tx)[iA];
uv2 = static_cast<const osg::Vec2Array&>(*tx)[iB];
uv3 = static_cast<const osg::Vec2Array&>(*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<const osg::Vec3Array&>(*tx)[iA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec3Array&>(*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<const osg::Vec4Array&>(*tx)[iA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[iB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*vx)[viA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[viB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[viC].ptr()[i];
}
break;
case osg::Array::Vec3ArrayType:
P1 = static_cast<const osg::Vec3Array&>(*vx)[viA];
P2 = static_cast<const osg::Vec3Array&>(*vx)[viB];
P3 = static_cast<const osg::Vec3Array&>(*vx)[viC];
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<3; ++i) {
P1.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[viA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[viB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*vx)[viA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[viB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[viC].ptr()[i];
}
break;
case osg::Array::Vec3ArrayType:
P1 = static_cast<const osg::Vec3Array&>(*vx)[viA];
P2 = static_cast<const osg::Vec3Array&>(*vx)[viB];
P3 = static_cast<const osg::Vec3Array&>(*vx)[viC];
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<3; ++i) {
P1.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[viA].ptr()[i];
P2.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[viB].ptr()[i];
P3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*nx)[niA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[niB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[niC].ptr()[i];
}
break;
case osg::Array::Vec3ArrayType:
N1 = static_cast<const osg::Vec3Array&>(*nx)[niA];
N2 = static_cast<const osg::Vec3Array&>(*nx)[niB];
N3 = static_cast<const osg::Vec3Array&>(*nx)[niC];
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<3; ++i) {
N1.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[niA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[niB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*nx)[niA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[niB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[niC].ptr()[i];
}
}
break;
osg::Vec2 uv1;
osg::Vec2 uv2;
osg::Vec2 uv3;
case osg::Array::Vec3ArrayType:
N1 = static_cast<const osg::Vec3Array&>(*nx)[niA];
N2 = static_cast<const osg::Vec3Array&>(*nx)[niB];
N3 = static_cast<const osg::Vec3Array&>(*nx)[niC];
break;
switch (tx->getType())
{
case osg::Array::Vec2ArrayType:
uv1 = static_cast<const osg::Vec2Array&>(*tx)[tiA];
uv2 = static_cast<const osg::Vec2Array&>(*tx)[tiB];
uv3 = static_cast<const osg::Vec2Array&>(*tx)[tiC];
break;
case osg::Array::Vec3ArrayType:
for (i=0; i<2; ++i) {
uv1.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[tiA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[tiB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[tiC].ptr()[i];
}
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<2; ++i) {
uv1.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[tiA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[tiB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec4Array&>(*nx)[niA].ptr()[i];
N2.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[niB].ptr()[i];
N3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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<const osg::Vec2Array&>(*tx)[tiA];
uv2 = static_cast<const osg::Vec2Array&>(*tx)[tiB];
uv3 = static_cast<const osg::Vec2Array&>(*tx)[tiC];
break;
case osg::Array::Vec3ArrayType:
for (i=0; i<2; ++i) {
uv1.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[tiA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[tiB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[tiC].ptr()[i];
}
break;
case osg::Array::Vec4ArrayType:
for (i=0; i<2; ++i) {
uv1.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[tiA].ptr()[i];
uv2.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[tiB].ptr()[i];
uv3.ptr()[i] = static_cast<const osg::Vec4Array&>(*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;
}
}