// --------------------------------------------------------------------------------- // calculate vertex normals given the triangles void Mesh3D:: calculateVertexNormals() { // create 0-normals m_vertexNormals = std::vector< Vector3 >( getNumberOfVertices(), Vector3(0,0,0) ); for(unsigned int i = 0; i < getNumberOfFaces(); i++) { int v1 = getFaceVertexIndex(i,0); int v2 = getFaceVertexIndex(i,1); int v3 = getFaceVertexIndex(i,2); assert( v1 < getNumberOfVertices() ); assert( v2 < getNumberOfVertices() ); assert( v3 < getNumberOfVertices() ); Vector3 p = getVertexPosition( v1 ); Vector3 q = getVertexPosition( v2 ); Vector3 r = getVertexPosition( v3 ); Vector3 n = (q-p).cross(r-p).normalize(); m_vertexNormals[v1] += n; m_vertexNormals[v2] += n; m_vertexNormals[v3] += n; } for(int i = 0; i < getNumberOfVertices(); i++) { assert( m_vertexNormals[i].length() > 0 ); m_vertexNormals[i] = m_vertexNormals[i].normalize(); } }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int VertexGeom::writeXdmf(QTextStream& out, QString dcName, QString hdfFileName) { herr_t err = 0; // Always start the grid out << " <!-- *************** START OF " << dcName << " *************** -->" << "\n"; out << " <Grid Name=\"" << dcName << "\" GridType=\"Uniform\">" << "\n"; #if 0 DataArrayPath dap = getTemporalDataPath(); if(dap.isValid()) { IDataArray::Pointer timeValues = getAttributeMatrix(dap.getAttributeMatrixName())->getAttributeArray(dap.getDataArrayName()); Int32ArrayType::Pointer timeValuePtr = boost::dynamic_pointer_cast<Int32ArrayType>(timeValues); out << " <Time TimeType=\"Single\" Value=\"" << timeValuePtr->getValue(0) << "\"/>\n"; } #endif out << " <Topology TopologyType=\"Polyvertex\" NumberOfElements=\"" << getNumberOfVertices() << "\">" << "\n"; out << " <DataItem Format=\"HDF\" NumberType=\"Int\" Dimensions=\"" << getNumberOfVertices() << "\">" << "\n"; out << " " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << "Verts" << "\n"; out << " </DataItem>" << "\n"; out << " </Topology>" << "\n"; out << " <Geometry Type=\"XYZ\">" << "\n"; out << " <DataItem Format=\"HDF\" Dimensions=\"" << getNumberOfVertices() << " 3\" NumberType=\"Float\" Precision=\"4\">" << "\n"; out << " " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << DREAM3D::Geometry::SharedVertexList << "\n"; out << " </DataItem>" << "\n"; out << " </Geometry>" << "\n"; out << "" << "\n"; return err; }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void QuadGeom::addAttributeMatrix(const QString& name, AttributeMatrix::Pointer data) { if (data->getType() != 0 || data->getType() != 1 || data->getType() != 2) { // QuadGeom can only accept vertex, edge, or face Attribute Matrices return; } if (data->getType() == 0 && static_cast<int64_t>(data->getNumTuples()) != getNumberOfVertices()) { return; } if (data->getType() == 1 && static_cast<int64_t>(data->getNumTuples()) != getNumberOfEdges()) { return; } if (data->getType() == 2 && data->getNumTuples() != getNumberOfElements()) { return; } if (data->getName().compare(name) != 0) { data->setName(name); } m_AttributeMatrices[name] = data; }
// Draw function void Line::drawFunc() { BEGIN_DLIST const unsigned int n = getNumberOfVertices(); const osg::Vec3* v = getVertices(); if (n >= 2) { if (segment) { // Draw as line segments (pairs of vertices) glBegin(GL_LINES); for (unsigned int i = 0; i < n; i++) { lcVertex3v( v[i].ptr() ); } glEnd(); } else { // Draw one long line glBegin(GL_LINE_STRIP); for (unsigned int i = 0; i < n; i++) { lcVertex3v( v[i].ptr() ); } glEnd(); } } END_DLIST }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int VertexGeom::writeGeometryToHDF5(hid_t parentId, bool writeXdmf) { herr_t err = 0; QVector<size_t> tDims(1, 0); if (m_VertexList.get() != NULL) { err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_VertexList); if (err < 0) { return err; } if(writeXdmf == true) { QVector<size_t> cDims(1, 1); DataArray<int64_t>::Pointer vertsPtr = DataArray<int64_t>::CreateArray(getNumberOfVertices(), cDims, DREAM3D::StringConstants::VertsName); int64_t* verts = vertsPtr->getPointer(0); for(size_t i = 0; i < vertsPtr->getNumberOfTuples(); i++) { verts[i] = i; } tDims[0] = vertsPtr->getNumberOfTuples(); err = vertsPtr->writeH5Data(parentId, tDims); } } return err; }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int QuadGeom::writeXdmf(QTextStream& out, QString dcName, QString hdfFileName) { herr_t err = 0; out << " <!-- *************** START OF " << dcName << " *************** -->" << "\n"; out << " <Grid Name=\"" << dcName << "\" GridType=\"Uniform\">" << "\n"; out << " <Topology TopologyType=\"Quadrilateral\" NumberOfElements=\"" << getNumberOfQuads() << "\">" << "\n"; out << " <DataItem Format=\"HDF\" NumberType=\"Int\" Dimensions=\"" << getNumberOfQuads() << " 4\">" << "\n"; out << " " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << DREAM3D::Geometry::SharedQuadList << "\n"; out << " </DataItem>" << "\n"; out << " </Topology>" << "\n"; if (m_VertexList.get() == NULL) { out << "<!-- ********************* GEOMETRY ERROR ****************************************\n"; out << "The Geometry with name '" << getName() << "' in DataContainer '" << dcName << "' \n"; out << "did not have any vertices assigned.\n"; out << "The Geometry types will be missing from the Xdmf which will cause issues when\n"; out << "trying to load the file\n"; out << " ********************************************************************************** -->\n"; } else { out << " <Geometry Type=\"XYZ\">" << "\n"; out << " <DataItem Format=\"HDF\" Dimensions=\"" << getNumberOfVertices() << " 3\" NumberType=\"Float\" Precision=\"4\">" << "\n"; out << " " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << DREAM3D::Geometry::SharedVertexList << "\n"; out << " </DataItem>" << "\n"; out << " </Geometry>" << "\n"; out << "" << "\n"; } return err; }
//------------------------------------------------------------------------------ // drawFunc() //------------------------------------------------------------------------------ void Polygon::drawFunc() { BEGIN_DLIST unsigned int nv = getNumberOfVertices(); const osg::Vec3* vertices = getVertices(); if (nv >= 2) { // Draw with texture unsigned int ntc = getNumberOfTextureCoords(); if (ntc > 0 && hasTexture()) { const osg::Vec2* texCoord = getTextureCoord(); unsigned int tc = 0; // texture count glBegin(GL_POLYGON); for (unsigned int i = 0; i < nv; i++) { if (tc < ntc) { lcTexCoord2v(texCoord[tc++].ptr()); } lcVertex3v( vertices[i].ptr() ); } glEnd(); } // Draw without texture else { // get our color gradient, because if we have one, instead of a regular color, we will // override it here and set it on a per vertex level. ColorGradient* colGradient = dynamic_cast<ColorGradient*>(getColor()); glBegin(GL_POLYGON); osg::Vec3* ptr = nullptr; for (unsigned int i = 0; i < nv; i++) { if (colGradient != nullptr) { Basic::Color* col = colGradient->getColorByIdx(i+1); if (col != nullptr) glColor4f(static_cast<GLfloat>(col->red()), static_cast<GLfloat>(col->green()), static_cast<GLfloat>(col->blue()), static_cast<GLfloat>(col->alpha())); } // if we have a material name, we will set up like we have a material if (getMaterialName() != nullptr) { //lcVertex3v( vertices[i].ptr() ); ptr = const_cast<osg::Vec3*>(reinterpret_cast<const osg::Vec3*>(vertices[i].ptr())); if (ptr != nullptr) { calcNormal(); lcNormal3(norm.x(), norm.y(), -(norm.z())); lcVertex3(ptr->x(), ptr->y(), ptr->z()); } } else { lcVertex3v(vertices[i].ptr()); } } glEnd(); } } END_DLIST }
bool Polygon::calcPlaneCoeff() { if (getNumberOfVertices() >= 3) { coeffValid = calcPlaneCoeff(coeff,getVertices()); } else { coeffValid = false; coeff.set(0,0,0,0); } return coeffValid; }
// Draw function void Point::drawFunc() { BEGIN_DLIST const unsigned int n = getNumberOfVertices(); const osg::Vec3* v = getVertices(); glBegin(GL_POINTS); for (unsigned int i = 0; i < n; i++) { lcVertex3v( v[i].ptr() ); } glEnd(); END_DLIST }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int EdgeGeom::writeGeometryToHDF5(hid_t parentId, bool SIMPL_NOT_USED(writeXdmf)) { herr_t err = 0; if (m_VertexList.get() != NULL) { err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_VertexList); if (err < 0) { return err; } } if (m_EdgeList.get() != NULL) { err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_EdgeList); if (err < 0) { return err; } } if (m_EdgeCentroids.get() != NULL) { err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_EdgeCentroids); if (err < 0) { return err; } } if (m_EdgeNeighbors.get() != NULL) { size_t numEdges = getNumberOfEdges(); err = GeometryHelpers::GeomIO::WriteDynamicListToHDF5<uint16_t, int64_t>(parentId, m_EdgeNeighbors, numEdges, DREAM3D::StringConstants::EdgeNeighbors); if (err < 0) { return err; } } if (m_EdgesContainingVert.get() != NULL) { size_t numVerts = getNumberOfVertices(); err = GeometryHelpers::GeomIO::WriteDynamicListToHDF5<uint16_t, int64_t>(parentId, m_EdgesContainingVert, numVerts, DREAM3D::StringConstants::EdgesContainingVert); if (err < 0) { return err; } } return err; }
/** * Initializes the GameObject by creating vao's and vbo's * and sending the vertex data over to the graphics card. */ void GameObject::initGameObject() { if (scene == nullptr) { abortWithMessage("In GameObject::initGameObject(): Scene for GameObject was never set"); } if (initialized) { return; } glGenVertexArrays(1, &vao); glGenBuffers(2, vbo); scene->middleman->bufferObject(vao, vbo, getNumberOfVertices(), getVertices(), getNumberOfVertices(), getVertexColors()); std::vector<GameObject*>::iterator it = children.begin(); while (it != children.end()) { (*it)->initGameObject(); it++; } initialized = true; }
// Draw function void LineLoop::drawFunc() { BEGIN_DLIST const unsigned int n = getNumberOfVertices(); const osg::Vec3* v = getVertices(); if (n >= 2) { glBegin(GL_LINE_LOOP); for (unsigned int i = 0; i < n; i++) { lcVertex3v( v[i].ptr() ); } glEnd(); } END_DLIST }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void VertexGeom::findDerivatives(DoubleArrayType::Pointer field, DoubleArrayType::Pointer derivatives) { int64_t numVerts = getNumberOfVertices(); int cDims = field->getNumberOfComponents(); double* derivsPtr = derivatives->getPointer(0); for (int64_t i = 0; i < numVerts; i++) { for (int j = 0; j < cDims; j++) { derivsPtr[i * 3 * cDims + j * 3] = 0.0; derivsPtr[i * 3 * cDims + j * 3 + 1] = 0.0; derivsPtr[i * 3 * cDims + j * 3 + 2] = 0.0; } } }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- QString VertexGeom::getInfoString(DREAM3D::InfoStringFormat format) { QString info; QTextStream ss (&info); if(format == DREAM3D::HtmlFormat) { ss << "<tr bgcolor=\"#D3D8E0\"><th colspan=2>Vertex Geometry Info</th></tr>"; ss << "<tr bgcolor=\"#C3C8D0\"><th align=\"right\">NumberOfElements</th><td>" << getNumberOfVertices() << "</td></tr>"; ss << "</tbody></table>"; } else { } return info; }
void GameObject::draw() { if (scene == nullptr) { abortWithMessage("In GameObject::draw(): Scene for GameObject was never set"); } mat4 mv = getModelViewMatrix(); scene->middleman->updateModelViewMatrix(mv); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, getNumberOfVertices()); std::vector<GameObject*>::iterator it = children.begin(); while (it != children.end()) { (*it)->draw(); it++; } }
//--------------------------------------------------------------------------------- void Mesh3D::genericUV() { try { for( int j = 0 ; j < getNumberOfVertices(); j+=3) { m_vertexUV.push_back(Vector2(0, 0)); m_vertexUV.push_back(Vector2(0, 1)); m_vertexUV.push_back(Vector2(1, 1)); //m_vertexIndices[i][j] } std::cout << "Done\n"; } catch(...) { std::cerr << "Error in genericUV" << std::endl; } }
ossim_uint32 ossimPolygon::getVertexCount()const { return getNumberOfVertices(); }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int QuadGeom::findElementsContainingVert() { m_QuadsContainingVert = ElementDynamicList::New(); GeometryHelpers::Connectivity::FindElementsContainingVert<uint16_t, int64_t>(m_QuadList, m_QuadsContainingVert, getNumberOfVertices()); if (m_QuadsContainingVert.get() == NULL) { return -1; } return 1; }
// Draw function void Quad::drawFunc() { bool ok = false; // Draw with texture const unsigned int nv = getNumberOfVertices(); if (nv > 3) { if (!strip) { int rem = nv % 4; if (rem != 0) std::cerr << "Quad::drawFunc() - Quad have to have multiple of 4 vertices, add or remove vertices!!" << std::endl; else { BEGIN_DLIST glBegin(GL_QUADS); ok = true; } } else { int rem = nv % 2; if (rem != 0) std::cerr << "Quad::drawFunc() - quad strips have to have multiple of 2 vertices, add or remove vertices!!" << std::endl; else { BEGIN_DLIST glBegin(GL_QUAD_STRIP); ok = true; } } if (ok) { // get our regular vertices here const osg::Vec3* v = getVertices(); const unsigned int ntc = getNumberOfTextureCoords(); // draw with texture if (ntc > 0 && hasTexture()) { const osg::Vec2* texCoord = getTextureCoord(); unsigned int tc = 0; // texture count for (unsigned int i = 0; i < nv; i++) { // add our textures coordinates if (tc < ntc) lcTexCoord2v(texCoord[tc++].ptr()); // now our vertices lcVertex3v( v[i].ptr() ); } } // draw without texture else { // get our color gradient and apply it (if we have one) ColorGradient* colGradient = dynamic_cast<ColorGradient*>(getColor()); for (unsigned int i = 0; i < nv; i++) { if (colGradient != nullptr) { Basic::Color* col = colGradient->getColorByIdx(i+1); if (col != nullptr) glColor4f(static_cast<GLfloat>(col->red()), static_cast<GLfloat>(col->green()), static_cast<GLfloat>(col->blue()), static_cast<GLfloat>(col->alpha())); } // now add our vertex lcVertex3v( v[i].ptr() ); } } glEnd(); END_DLIST } } else std::cerr << "Quad::drawFunc() - Quad or QuadStrip needs at least 4 vertices!" << std::endl;
void ModelOBJ::generateTangents() { const int *pTriangle = 0; Vertex *pVertex0 = 0; Vertex *pVertex1 = 0; Vertex *pVertex2 = 0; float edge1[3] = {0.0f, 0.0f, 0.0f}; float edge2[3] = {0.0f, 0.0f, 0.0f}; float texEdge1[2] = {0.0f, 0.0f}; float texEdge2[2] = {0.0f, 0.0f}; float tangent[3] = {0.0f, 0.0f, 0.0f}; float bitangent[3] = {0.0f, 0.0f, 0.0f}; float det = 0.0f; float nDotT = 0.0f; float bDotB = 0.0f; float length = 0.0f; int totalVertices = getNumberOfVertices(); int totalTriangles = getNumberOfTriangles(); // Initialize all the vertex tangents and bitangents. for (int i = 0; i < totalVertices; ++i) { pVertex0 = &m_vertexBuffer[i]; pVertex0->tangent[0] = 0.0f; pVertex0->tangent[1] = 0.0f; pVertex0->tangent[2] = 0.0f; pVertex0->tangent[3] = 0.0f; pVertex0->bitangent[0] = 0.0f; pVertex0->bitangent[1] = 0.0f; pVertex0->bitangent[2] = 0.0f; } // Calculate the vertex tangents and bitangents. for (int i = 0; i < totalTriangles; ++i) { pTriangle = &m_indexBuffer[i * 3]; pVertex0 = &m_vertexBuffer[pTriangle[0]]; pVertex1 = &m_vertexBuffer[pTriangle[1]]; pVertex2 = &m_vertexBuffer[pTriangle[2]]; // Calculate the triangle face tangent and bitangent. edge1[0] = pVertex1->position[0] - pVertex0->position[0]; edge1[1] = pVertex1->position[1] - pVertex0->position[1]; edge1[2] = pVertex1->position[2] - pVertex0->position[2]; edge2[0] = pVertex2->position[0] - pVertex0->position[0]; edge2[1] = pVertex2->position[1] - pVertex0->position[1]; edge2[2] = pVertex2->position[2] - pVertex0->position[2]; texEdge1[0] = pVertex1->texCoord[0] - pVertex0->texCoord[0]; texEdge1[1] = pVertex1->texCoord[1] - pVertex0->texCoord[1]; texEdge2[0] = pVertex2->texCoord[0] - pVertex0->texCoord[0]; texEdge2[1] = pVertex2->texCoord[1] - pVertex0->texCoord[1]; det = texEdge1[0] * texEdge2[1] - texEdge2[0] * texEdge1[1]; if (fabs(det) < 1e-6f) { tangent[0] = 1.0f; tangent[1] = 0.0f; tangent[2] = 0.0f; bitangent[0] = 0.0f; bitangent[1] = 1.0f; bitangent[2] = 0.0f; } else { det = 1.0f / det; tangent[0] = (texEdge2[1] * edge1[0] - texEdge1[1] * edge2[0]) * det; tangent[1] = (texEdge2[1] * edge1[1] - texEdge1[1] * edge2[1]) * det; tangent[2] = (texEdge2[1] * edge1[2] - texEdge1[1] * edge2[2]) * det; bitangent[0] = (-texEdge2[0] * edge1[0] + texEdge1[0] * edge2[0]) * det; bitangent[1] = (-texEdge2[0] * edge1[1] + texEdge1[0] * edge2[1]) * det; bitangent[2] = (-texEdge2[0] * edge1[2] + texEdge1[0] * edge2[2]) * det; } // Accumulate the tangents and bitangents. pVertex0->tangent[0] += tangent[0]; pVertex0->tangent[1] += tangent[1]; pVertex0->tangent[2] += tangent[2]; pVertex0->bitangent[0] += bitangent[0]; pVertex0->bitangent[1] += bitangent[1]; pVertex0->bitangent[2] += bitangent[2]; pVertex1->tangent[0] += tangent[0]; pVertex1->tangent[1] += tangent[1]; pVertex1->tangent[2] += tangent[2]; pVertex1->bitangent[0] += bitangent[0]; pVertex1->bitangent[1] += bitangent[1]; pVertex1->bitangent[2] += bitangent[2]; pVertex2->tangent[0] += tangent[0]; pVertex2->tangent[1] += tangent[1]; pVertex2->tangent[2] += tangent[2]; pVertex2->bitangent[0] += bitangent[0]; pVertex2->bitangent[1] += bitangent[1]; pVertex2->bitangent[2] += bitangent[2]; } // Orthogonalize and normalize the vertex tangents. for (int i = 0; i < totalVertices; ++i) { pVertex0 = &m_vertexBuffer[i]; // Gram-Schmidt orthogonalize tangent with normal. nDotT = pVertex0->normal[0] * pVertex0->tangent[0] + pVertex0->normal[1] * pVertex0->tangent[1] + pVertex0->normal[2] * pVertex0->tangent[2]; pVertex0->tangent[0] -= pVertex0->normal[0] * nDotT; pVertex0->tangent[1] -= pVertex0->normal[1] * nDotT; pVertex0->tangent[2] -= pVertex0->normal[2] * nDotT; // Normalize the tangent. length = 1.0f / sqrtf(pVertex0->tangent[0] * pVertex0->tangent[0] + pVertex0->tangent[1] * pVertex0->tangent[1] + pVertex0->tangent[2] * pVertex0->tangent[2]); pVertex0->tangent[0] *= length; pVertex0->tangent[1] *= length; pVertex0->tangent[2] *= length; // Calculate the handedness of the local tangent space. // The bitangent vector is the cross product between the triangle face // normal vector and the calculated tangent vector. The resulting // bitangent vector should be the same as the bitangent vector // calculated from the set of linear equations above. If they point in // different directions then we need to invert the cross product // calculated bitangent vector. We store this scalar multiplier in the // tangent vector's 'w' component so that the correct bitangent vector // can be generated in the normal mapping shader's vertex shader. // // Normal maps have a left handed coordinate system with the origin // located at the top left of the normal map texture. The x coordinates // run horizontally from left to right. The y coordinates run // vertically from top to bottom. The z coordinates run out of the // normal map texture towards the viewer. Our handedness calculations // must take this fact into account as well so that the normal mapping // shader's vertex shader will generate the correct bitangent vectors. // Some normal map authoring tools such as Crazybump // (http://www.crazybump.com/) includes options to allow you to control // the orientation of the normal map normal's y-axis. bitangent[0] = (pVertex0->normal[1] * pVertex0->tangent[2]) - (pVertex0->normal[2] * pVertex0->tangent[1]); bitangent[1] = (pVertex0->normal[2] * pVertex0->tangent[0]) - (pVertex0->normal[0] * pVertex0->tangent[2]); bitangent[2] = (pVertex0->normal[0] * pVertex0->tangent[1]) - (pVertex0->normal[1] * pVertex0->tangent[0]); bDotB = bitangent[0] * pVertex0->bitangent[0] + bitangent[1] * pVertex0->bitangent[1] + bitangent[2] * pVertex0->bitangent[2]; pVertex0->tangent[3] = (bDotB < 0.0f) ? 1.0f : -1.0f; pVertex0->bitangent[0] = bitangent[0]; pVertex0->bitangent[1] = bitangent[1]; pVertex0->bitangent[2] = bitangent[2]; } m_hasTangents = true; }
void ModelOBJ::generateNormals() { const int *pTriangle = 0; Vertex *pVertex0 = 0; Vertex *pVertex1 = 0; Vertex *pVertex2 = 0; float edge1[3] = {0.0f, 0.0f, 0.0f}; float edge2[3] = {0.0f, 0.0f, 0.0f}; float normal[3] = {0.0f, 0.0f, 0.0f}; float length = 0.0f; int totalVertices = getNumberOfVertices(); int totalTriangles = getNumberOfTriangles(); // Initialize all the vertex normals. for (int i = 0; i < totalVertices; ++i) { pVertex0 = &m_vertexBuffer[i]; pVertex0->normal[0] = 0.0f; pVertex0->normal[1] = 0.0f; pVertex0->normal[2] = 0.0f; } // Calculate the vertex normals. for (int i = 0; i < totalTriangles; ++i) { pTriangle = &m_indexBuffer[i * 3]; pVertex0 = &m_vertexBuffer[pTriangle[0]]; pVertex1 = &m_vertexBuffer[pTriangle[1]]; pVertex2 = &m_vertexBuffer[pTriangle[2]]; // Calculate triangle face normal. edge1[0] = pVertex1->position[0] - pVertex0->position[0]; edge1[1] = pVertex1->position[1] - pVertex0->position[1]; edge1[2] = pVertex1->position[2] - pVertex0->position[2]; edge2[0] = pVertex2->position[0] - pVertex0->position[0]; edge2[1] = pVertex2->position[1] - pVertex0->position[1]; edge2[2] = pVertex2->position[2] - pVertex0->position[2]; normal[0] = (edge1[1] * edge2[2]) - (edge1[2] * edge2[1]); normal[1] = (edge1[2] * edge2[0]) - (edge1[0] * edge2[2]); normal[2] = (edge1[0] * edge2[1]) - (edge1[1] * edge2[0]); // Accumulate the normals. pVertex0->normal[0] += normal[0]; pVertex0->normal[1] += normal[1]; pVertex0->normal[2] += normal[2]; pVertex1->normal[0] += normal[0]; pVertex1->normal[1] += normal[1]; pVertex1->normal[2] += normal[2]; pVertex2->normal[0] += normal[0]; pVertex2->normal[1] += normal[1]; pVertex2->normal[2] += normal[2]; } // Normalize the vertex normals. for (int i = 0; i < totalVertices; ++i) { pVertex0 = &m_vertexBuffer[i]; length = 1.0f / sqrtf(pVertex0->normal[0] * pVertex0->normal[0] + pVertex0->normal[1] * pVertex0->normal[1] + pVertex0->normal[2] * pVertex0->normal[2]); pVertex0->normal[0] *= length; pVertex0->normal[1] *= length; pVertex0->normal[2] *= length; } m_hasNormals = true; }