/////////////////////////////////////////////////////////////////////////////////////////////////// // Calculate the tangent basis for a triangle on the surface of a model // This vector is needed for most normal mapping shaders void m3dCalculateTangentBasis(const M3DVector3f vTriangle[3], const M3DVector2f vTexCoords[3], const M3DVector3f N, M3DVector3f vTangent) { M3DVector3f dv2v1, dv3v1; float dc2c1t, dc2c1b, dc3c1t, dc3c1b; float M; m3dSubtractVectors3(dv2v1, vTriangle[1], vTriangle[0]); m3dSubtractVectors3(dv3v1, vTriangle[2], vTriangle[0]); dc2c1t = vTexCoords[1][0] - vTexCoords[0][0]; dc2c1b = vTexCoords[1][1] - vTexCoords[0][1]; dc3c1t = vTexCoords[2][0] - vTexCoords[0][0]; dc3c1b = vTexCoords[2][1] - vTexCoords[0][1]; M = (dc2c1t * dc3c1b) - (dc3c1t * dc2c1b); M = 1.0f / M; m3dScaleVector3(dv2v1, dc3c1b); m3dScaleVector3(dv3v1, dc2c1b); m3dSubtractVectors3(vTangent, dv2v1, dv3v1); m3dScaleVector3(vTangent, M); // This potentially changes the direction of the vector m3dNormalizeVector(vTangent); M3DVector3f B; m3dCrossProduct(B, N, vTangent); m3dCrossProduct(vTangent, B, N); m3dNormalizeVector(vTangent); }
///////////////////////////////////////////////////////////////// // Add a triangle to the mesh. This searches the current list for identical // (well, almost identical - these are floats you know...) verts. If one is found, it // is added to the index array. If not, it is added to both the index array and the vertex // array grows by one as well. void CVBOMesh::AddTriangle(M3DVector3f verts[3], M3DVector3f vNorms[3], M3DVector2f vTexCoords[3]) { const float e = 0.000001; // How small a difference to equate // First thing we do is make sure the normals are unit length! // It's almost always a good idea to work with pre-normalized normals m3dNormalizeVector(vNorms[0]); m3dNormalizeVector(vNorms[1]); m3dNormalizeVector(vNorms[2]); // Search for match - triangle consists of three verts for(GLuint iVertex = 0; iVertex < 3; iVertex++) { GLuint iMatch = 0; for(iMatch = 0; iMatch < nNumVerts; iMatch++) { // If the vertex positions are the same if(m3dCloseEnough(pVerts[iMatch][0], verts[iVertex][0], e) && m3dCloseEnough(pVerts[iMatch][1], verts[iVertex][1], e) && m3dCloseEnough(pVerts[iMatch][2], verts[iVertex][2], e) && // AND the Normal is the same... m3dCloseEnough(pNorms[iMatch][0], vNorms[iVertex][0], e) && m3dCloseEnough(pNorms[iMatch][1], vNorms[iVertex][1], e) && m3dCloseEnough(pNorms[iMatch][2], vNorms[iVertex][2], e) && // And Texture is the same... m3dCloseEnough(pTexCoords[iMatch][0], vTexCoords[iVertex][0], e) && m3dCloseEnough(pTexCoords[iMatch][1], vTexCoords[iVertex][1], e)) { // Then add the index only pIndexes[nNumIndexes] = iMatch; nNumIndexes++; break; } } // No match for this vertex, add to end of list if(iMatch == nNumVerts) { memcpy(pVerts[nNumVerts], verts[iVertex], sizeof(M3DVector3f)); memcpy(pNorms[nNumVerts], vNorms[iVertex], sizeof(M3DVector3f)); memcpy(pTexCoords[nNumVerts], &vTexCoords[iVertex], sizeof(M3DVector2f)); pIndexes[nNumIndexes] = nNumVerts; nNumIndexes++; nNumVerts++; } } }
// For best results, put this in a display list // Draw a torus (doughnut) at z = fZVal... torus is in xy plane void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor) { M3DVector3f vNormal; double majorStep = 2.0f*M3D_PI / numMajor; double minorStep = 2.0f*M3D_PI / numMinor; int i, j; for (i=0; i<numMajor; ++i) { double a0 = i * majorStep; double a1 = a0 + majorStep; GLfloat x0 = (GLfloat) cos(a0); GLfloat y0 = (GLfloat) sin(a0); GLfloat x1 = (GLfloat) cos(a1); GLfloat y1 = (GLfloat) sin(a1); glBegin(GL_TRIANGLE_STRIP); for (j=0; j<=numMinor; ++j) { double b = j * minorStep; GLfloat c = (GLfloat) cos(b); GLfloat r = minorRadius * c + majorRadius; GLfloat z = minorRadius * (GLfloat) sin(b); // First point glTexCoord2f((float)(i)/(float)(numMajor), (float)(j)/(float)(numMinor)); vNormal[0] = x0*c; vNormal[1] = y0*c; vNormal[2] = z/minorRadius; m3dNormalizeVector(vNormal); glNormal3fv(vNormal); glVertex3f(x0*r, y0*r, z); glTexCoord2f((float)(i+1)/(float)(numMajor), (float)(j)/(float)(numMinor)); vNormal[0] = x1*c; vNormal[1] = y1*c; vNormal[2] = z/minorRadius; m3dNormalizeVector(vNormal); glNormal3fv(vNormal); glVertex3f(x1*r, y1*r, z); } glEnd(); } }
// Ditto above, but for doubles void m3dGetPlaneEquation(M3DVector4d planeEq, const M3DVector3d p1, const M3DVector3d p2, const M3DVector3d p3) { // Get two vectors... do the cross product M3DVector3d v1, v2; // V1 = p3 - p1 v1[0] = p3[0] - p1[0]; v1[1] = p3[1] - p1[1]; v1[2] = p3[2] - p1[2]; // V2 = P2 - p1 v2[0] = p2[0] - p1[0]; v2[1] = p2[1] - p1[1]; v2[2] = p2[2] - p1[2]; // Unit normal to plane - Not sure which is the best way here m3dCrossProduct(planeEq, v1, v2); m3dNormalizeVector(planeEq); // Back substitute to get D planeEq[3] = -(planeEq[0] * p3[0] + planeEq[1] * p3[1] + planeEq[2] * p3[2]); }