root/OpenSceneGraph/trunk/src/osgUtil/TangentSpaceGenerator.cpp @ 13041

Revision 13041, 13.4 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgUtil/TangentSpaceGenerator>
2
3#include <osg/Notify>
4#include <osg/io_utils>
5
6using namespace osgUtil;
7
8TangentSpaceGenerator::TangentSpaceGenerator()
9:    osg::Referenced(),
10    T_(new osg::Vec4Array),
11    B_(new osg::Vec4Array),
12    N_(new osg::Vec4Array)
13{
14}
15
16TangentSpaceGenerator::TangentSpaceGenerator(const TangentSpaceGenerator &copy, const osg::CopyOp &copyop)
17:    osg::Referenced(copy),
18    T_(static_cast<osg::Vec4Array *>(copyop(copy.T_.get()))),
19    B_(static_cast<osg::Vec4Array *>(copyop(copy.B_.get()))),
20    N_(static_cast<osg::Vec4Array *>(copyop(copy.N_.get())))
21{
22}
23
24void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit)
25{
26    // check to see if vertex attributes indices exists, if so expand them to remove them
27    if (geo->suitableForOptimization())
28    {
29        // removing coord indices so we don't have to deal with them in the binormal code.
30        OSG_INFO<<"TangentSpaceGenerator::generate(Geometry*,int): Removing attribute indices"<<std::endl;
31        geo->copyToAndOptimize(*geo);
32    }
33
34    const osg::Array *vx = geo->getVertexArray();
35    const osg::Array *nx = geo->getNormalArray();
36    const osg::Array *tx = geo->getTexCoordArray(normal_map_tex_unit);
37
38    if (!vx || !tx) return;
39
40
41    unsigned int vertex_count = vx->getNumElements();
42    if (geo->getVertexIndices() == NULL) {
43        T_->assign(vertex_count, osg::Vec4());
44        B_->assign(vertex_count, osg::Vec4());
45        N_->assign(vertex_count, osg::Vec4());
46    } else {
47        unsigned int index_count = geo->getVertexIndices()->getNumElements();
48        T_->assign(index_count, osg::Vec4());
49        B_->assign(index_count, osg::Vec4());
50        N_->assign(index_count, osg::Vec4());
51        indices_ = new osg::UIntArray();
52        unsigned int i;
53        for (i=0;i<index_count;i++) {
54            indices_->push_back(i);
55        }
56    }
57
58    unsigned int i; // VC6 doesn't like for-scoped variables
59
60    for (unsigned int pri=0; pri<geo->getNumPrimitiveSets(); ++pri) {
61        osg::PrimitiveSet *pset = geo->getPrimitiveSet(pri);
62
63        unsigned int N = pset->getNumIndices();
64
65        switch (pset->getMode()) {
66
67            case osg::PrimitiveSet::TRIANGLES:
68                for (i=0; i<N; i+=3) {
69                    compute(pset, vx, nx, tx, i, i+1, i+2);
70                }
71                break;
72
73            case osg::PrimitiveSet::QUADS:
74                for (i=0; i<N; i+=4) {
75                    compute(pset, vx, nx, tx, i, i+1, i+2);
76                    compute(pset, vx, nx, tx, i+2, i+3, i);
77                }
78                break;
79
80            case osg::PrimitiveSet::TRIANGLE_STRIP:
81                if (pset->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) {
82                    osg::DrawArrayLengths *dal = static_cast<osg::DrawArrayLengths *>(pset);
83                    unsigned int j = 0;
84                    for (osg::DrawArrayLengths::const_iterator pi=dal->begin(); pi!=dal->end(); ++pi) {
85                        unsigned int iN = static_cast<unsigned int>(*pi-2);
86                        for (i=0; i<iN; ++i, ++j) {
87                            if ((i%2) == 0) {
88                                compute(pset, vx, nx, tx, j, j+1, j+2);
89                            } else {
90                                compute(pset, vx, nx, tx, j+1, j, j+2);
91                            }
92                        }
93                        j += 2;
94                    }
95                } else {
96                    for (i=0; i<N-2; ++i) {
97                        if ((i%2) == 0) {
98                            compute(pset, vx, nx, tx, i, i+1, i+2);
99                        } else {
100                            compute(pset, vx, nx, tx, i+1, i, i+2);
101                        }
102                    }
103                }
104                break;
105
106            case osg::PrimitiveSet::TRIANGLE_FAN:
107            case osg::PrimitiveSet::POLYGON:
108                if (pset->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) {
109                    osg::DrawArrayLengths *dal = static_cast<osg::DrawArrayLengths *>(pset);
110                    unsigned int j = 0;
111                    for (osg::DrawArrayLengths::const_iterator pi=dal->begin(); pi!=dal->end(); ++pi) {
112                        unsigned int iN = static_cast<unsigned int>(*pi-2);
113                        for (i=0; i<iN; ++i) {
114                            compute(pset, vx, nx, tx, 0, j+1, j+2);
115                        }
116                        j += 2;
117                    }
118                } else {
119                    for (i=0; i<N-2; ++i) {
120                        compute(pset, vx, nx, tx, 0, i+1, i+2);
121                    }
122                }
123                break;
124
125            case osg::PrimitiveSet::POINTS:
126            case osg::PrimitiveSet::LINES:
127            case osg::PrimitiveSet::LINE_STRIP:
128            case osg::PrimitiveSet::LINE_LOOP:
129            case osg::PrimitiveSet::LINES_ADJACENCY:
130            case osg::PrimitiveSet::LINE_STRIP_ADJACENCY:
131                break;
132
133            default: OSG_WARN << "Warning: TangentSpaceGenerator: unknown primitive mode " << pset->getMode() << "\n";
134        }
135    }
136
137    // normalize basis vectors and force the normal vector to match
138    // the triangle normal's direction
139    unsigned int attrib_count = vx->getNumElements();
140    if (geo->getVertexIndices() != NULL) {
141        attrib_count = geo->getVertexIndices()->getNumElements();
142    }
143    for (i=0; i<attrib_count; ++i) {
144        osg::Vec4 &vT = (*T_)[i];
145        osg::Vec4 &vB = (*B_)[i];
146        osg::Vec4 &vN = (*N_)[i];
147
148        osg::Vec3 txN = osg::Vec3(vT.x(), vT.y(), vT.z()) ^ osg::Vec3(vB.x(), vB.y(), vB.z());
149
150        if (txN * osg::Vec3(vN.x(), vN.y(), vN.z()) >= 0) {
151            vN = osg::Vec4(txN, 0);
152        } else {
153            vN = osg::Vec4(-txN, 0);
154        }
155
156        vT.normalize();
157        vB.normalize();
158        vN.normalize();
159    }
160    /* TO-DO: if indexed, compress the attributes to have only one
161     * version of each (different indices for each one?) */
162}
163
164void TangentSpaceGenerator::compute(osg::PrimitiveSet *pset,
165                                    const osg::Array* vx,
166                                    const osg::Array* nx,
167                                    const osg::Array* tx,
168                                    int iA, int iB, int iC)
169{
170    iA = pset->index(iA);
171    iB = pset->index(iB);
172    iC = pset->index(iC);
173
174    osg::Vec3 P1;
175    osg::Vec3 P2;
176    osg::Vec3 P3;
177
178    int i; // VC6 doesn't like for-scoped variables
179
180    switch (vx->getType())
181    {
182    case osg::Array::Vec2ArrayType:
183        for (i=0; i<2; ++i) {
184            P1.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iA].ptr()[i];
185            P2.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iB].ptr()[i];
186            P3.ptr()[i] = static_cast<const osg::Vec2Array&>(*vx)[iC].ptr()[i];
187        }
188        break;
189
190    case osg::Array::Vec3ArrayType:
191        P1 = static_cast<const osg::Vec3Array&>(*vx)[iA];
192        P2 = static_cast<const osg::Vec3Array&>(*vx)[iB];
193        P3 = static_cast<const osg::Vec3Array&>(*vx)[iC];
194        break;
195
196    case osg::Array::Vec4ArrayType:
197        for (i=0; i<3; ++i) {
198            P1.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[iA].ptr()[i];
199            P2.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[iB].ptr()[i];
200            P3.ptr()[i] = static_cast<const osg::Vec4Array&>(*vx)[iC].ptr()[i];
201        }
202        break;
203
204    default:
205        OSG_WARN << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl;
206    }
207
208    osg::Vec3 N1;
209    osg::Vec3 N2;
210    osg::Vec3 N3;
211
212    if(nx)
213    {
214        switch (nx->getType())
215        {
216        case osg::Array::Vec2ArrayType:
217            for (i=0; i<2; ++i) {
218                N1.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iA].ptr()[i];
219                N2.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iB].ptr()[i];
220                N3.ptr()[i] = static_cast<const osg::Vec2Array&>(*nx)[iC].ptr()[i];
221            }
222            break;
223
224        case osg::Array::Vec3ArrayType:
225            N1 = static_cast<const osg::Vec3Array&>(*nx)[iA];
226            N2 = static_cast<const osg::Vec3Array&>(*nx)[iB];
227            N3 = static_cast<const osg::Vec3Array&>(*nx)[iC];
228            break;
229
230        case osg::Array::Vec4ArrayType:
231            for (i=0; i<3; ++i) {
232                N1.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[iA].ptr()[i];
233                N2.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[iB].ptr()[i];
234                N3.ptr()[i] = static_cast<const osg::Vec4Array&>(*nx)[iC].ptr()[i];
235            }
236            break;
237
238        default:
239            OSG_WARN << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl;
240        }
241    }
242
243    osg::Vec2 uv1;
244    osg::Vec2 uv2;
245    osg::Vec2 uv3;
246
247    switch (tx->getType())
248    {
249    case osg::Array::Vec2ArrayType:
250        uv1 = static_cast<const osg::Vec2Array&>(*tx)[iA];
251        uv2 = static_cast<const osg::Vec2Array&>(*tx)[iB];
252        uv3 = static_cast<const osg::Vec2Array&>(*tx)[iC];
253        break;
254
255    case osg::Array::Vec3ArrayType:
256        for (i=0; i<2; ++i) {
257            uv1.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iA].ptr()[i];
258            uv2.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iB].ptr()[i];
259            uv3.ptr()[i] = static_cast<const osg::Vec3Array&>(*tx)[iC].ptr()[i];
260        }
261        break;
262
263    case osg::Array::Vec4ArrayType:
264        for (i=0; i<2; ++i) {
265            uv1.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[iA].ptr()[i];
266            uv2.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[iB].ptr()[i];
267            uv3.ptr()[i] = static_cast<const osg::Vec4Array&>(*tx)[iC].ptr()[i];
268        }
269        break;
270
271    default:
272        OSG_WARN << "Warning: TangentSpaceGenerator: texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl;
273    }
274
275    if(nx){
276        osg::Vec3 V, T1, T2, T3, B1, B2, B3;
277
278        V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^
279            osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y());
280        if (V.x() != 0) {
281            V.normalize();
282            T1.x() += -V.y() / V.x();
283            B1.x() += -V.z() / V.x();
284            T2.x() += -V.y() / V.x();
285            B2.x() += -V.z() / V.x();
286            T3.x() += -V.y() / V.x();
287            B3.x() += -V.z() / V.x();
288        }
289
290        V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^
291            osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y());
292        if (V.x() != 0) {
293            V.normalize();
294            T1.y() += -V.y() / V.x();
295            B1.y() += -V.z() / V.x();
296            T2.y() += -V.y() / V.x();
297            B2.y() += -V.z() / V.x();
298            T3.y() += -V.y() / V.x();
299            B3.y() += -V.z() / V.x();
300        }
301
302        V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^
303            osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y());
304        if (V.x() != 0) {
305            V.normalize();
306            T1.z() += -V.y() / V.x();
307            B1.z() += -V.z() / V.x();
308            T2.z() += -V.y() / V.x();
309            B2.z() += -V.z() / V.x();
310            T3.z() += -V.y() / V.x();
311            B3.z() += -V.z() / V.x();
312        }
313
314        osg::Vec3 tempvec;
315        tempvec = N1 ^ T1;
316        (*T_)[iA] = osg::Vec4(tempvec ^ N1, 0);
317        tempvec = B1 ^ N1;
318        (*B_)[iA] = osg::Vec4(N1 ^ tempvec, 0);
319        tempvec = N2 ^ T2;
320        (*T_)[iB] = osg::Vec4(tempvec ^ N2, 0);
321        tempvec = B2 ^ N2;
322        (*B_)[iB] = osg::Vec4(N2 ^ tempvec, 0);
323        tempvec = N3 ^ T3;
324        (*T_)[iC] = osg::Vec4(tempvec ^ N3, 0);
325        tempvec = B3 ^ N3;
326        (*B_)[iC] = osg::Vec4(N3 ^ tempvec, 0);
327
328        (*N_)[iA] += osg::Vec4(N1, 0);
329        (*N_)[iB] += osg::Vec4(N2, 0);
330        (*N_)[iC] += osg::Vec4(N3, 0);
331    }
332    else{
333        osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1);
334
335        osg::Vec3 V;
336
337        V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^
338            osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y());
339        if (V.x() != 0) {
340            V.normalize();
341            (*T_)[iA].x() += -V.y() / V.x();
342            (*B_)[iA].x() += -V.z() / V.x();
343            (*T_)[iB].x() += -V.y() / V.x();
344            (*B_)[iB].x() += -V.z() / V.x();
345            (*T_)[iC].x() += -V.y() / V.x();
346            (*B_)[iC].x() += -V.z() / V.x();
347        }
348
349        V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^
350            osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y());
351        if (V.x() != 0) {
352            V.normalize();
353            (*T_)[iA].y() += -V.y() / V.x();
354            (*B_)[iA].y() += -V.z() / V.x();
355            (*T_)[iB].y() += -V.y() / V.x();
356            (*B_)[iB].y() += -V.z() / V.x();
357            (*T_)[iC].y() += -V.y() / V.x();
358            (*B_)[iC].y() += -V.z() / V.x();
359        }
360
361        V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^
362            osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y());
363        if (V.x() != 0) {
364            V.normalize();
365            (*T_)[iA].z() += -V.y() / V.x();
366            (*B_)[iA].z() += -V.z() / V.x();
367            (*T_)[iB].z() += -V.y() / V.x();
368            (*B_)[iB].z() += -V.z() / V.x();
369            (*T_)[iC].z() += -V.y() / V.x();
370            (*B_)[iC].z() += -V.z() / V.x();
371        }
372
373        (*N_)[iA] += osg::Vec4(face_normal, 0);
374        (*N_)[iB] += osg::Vec4(face_normal, 0);
375        (*N_)[iC] += osg::Vec4(face_normal, 0);
376    }
377}
Note: See TracBrowser for help on using the browser.