void CMesh::generateFlatNormals() { if (hasNormals()) return; // for each face... for (vector<SPolygonFace>::iterator itFace = m_faceVector.begin(); itFace != m_faceVector.end(); ++itFace) { const SVertex& v1 = m_vertVector[(*itFace).v[0]]; const SVertex& v2 = m_vertVector[(*itFace).v[1]]; const SVertex& v3 = m_vertVector[(*itFace).v[2]]; SVertex v(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z); SVertex w(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z); SVertex vn(v.y*w.z - v.z*w.y, v.z*w.x - v.x*w.z, v.x*w.y - v.y*w.x); float length = sqrtf(vn.x*vn.x+vn.y*vn.y+vn.z*vn.z); if (0 < length) { const float a = 1/length; vn.x *= a; vn.y *= a; vn.z *= a; } m_normVector.push_back(vn); // register the generated normal through the face fill((*itFace).vn.begin(), (*itFace).vn.end(), m_normVector.size()-1); } }
void ccDrawableObject::getDrawingParameters(glDrawParams& params) const { //color override if (isColorOverriden()) { params.showColors=true; params.showNorms=hasNormals() && normalsShown()/*false*/; params.showSF=false; } else { params.showNorms = hasNormals() && normalsShown(); params.showSF = hasDisplayedScalarField() && sfShown(); //colors are not displayed if scalar field is displayed params.showColors = !params.showSF && hasColors() && colorsShown(); } }
void ofxMesh::toMesh(ofMesh & mesh){ mesh.clear(); if (hasVertices()) { mesh.getVertices()=getVertices(); } if (hasColors()) { mesh.getColors()=getColors(); } if (hasNormals()) { mesh.getNormals()=getNormals(); } if (hasTexCoords()) { mesh.getTexCoords()=getTexCoords(); } if (hasIndices()) { mesh.getIndices()=getIndices(); } }
ccPointCloud* ccGenericMesh::samplePoints( bool densityBased, double samplingParameter, bool withNormals, bool withRGB, bool withTexture, CCLib::GenericProgressCallback* pDlg/*=0*/) { bool withFeatures = (withNormals || withRGB || withTexture); GenericChunkedArray<1,unsigned>* triIndices = (withFeatures ? new GenericChunkedArray<1,unsigned> : 0); CCLib::SimpleCloud* sampledCloud = 0; if (densityBased) { sampledCloud = CCLib::MeshSamplingTools::samplePointsOnMesh(this,samplingParameter,pDlg,triIndices); } else { sampledCloud = CCLib::MeshSamplingTools::samplePointsOnMesh(this,static_cast<unsigned>(samplingParameter),pDlg,triIndices); } //convert to real point cloud ccPointCloud* cloud = 0; if (sampledCloud) { cloud = ccPointCloud::From(sampledCloud); delete sampledCloud; sampledCloud = 0; } if (!cloud) { if (triIndices) triIndices->release(); ccLog::Warning("[ccGenericMesh::samplePoints] Not enough memory!"); return 0; } if (withFeatures && triIndices && triIndices->currentSize() >= cloud->size()) { //generate normals if (withNormals && hasNormals()) { if (cloud->reserveTheNormsTable()) { for (unsigned i=0; i<cloud->size(); ++i) { unsigned triIndex = triIndices->getValue(i); const CCVector3* P = cloud->getPoint(i); CCVector3 N(0,0,1); interpolateNormals(triIndex,*P,N); cloud->addNorm(N); } cloud->showNormals(true); } else { ccLog::Warning("[ccGenericMesh::samplePoints] Failed to interpolate normals (not enough memory?)"); } } //generate colors if (withTexture && hasMaterials()) { if (cloud->reserveTheRGBTable()) { for (unsigned i=0; i<cloud->size(); ++i) { unsigned triIndex = triIndices->getValue(i); const CCVector3* P = cloud->getPoint(i); colorType C[3]={MAX_COLOR_COMP,MAX_COLOR_COMP,MAX_COLOR_COMP}; getColorFromMaterial(triIndex,*P,C,withRGB); cloud->addRGBColor(C); } cloud->showColors(true); } else { ccLog::Warning("[ccGenericMesh::samplePoints] Failed to export texture colors (not enough memory?)"); } } else if (withRGB && hasColors()) { if (cloud->reserveTheRGBTable()) { for (unsigned i=0; i<cloud->size(); ++i) { unsigned triIndex = triIndices->getValue(i); const CCVector3* P = cloud->getPoint(i); colorType C[3] = { MAX_COLOR_COMP, MAX_COLOR_COMP, MAX_COLOR_COMP }; interpolateColors(triIndex,*P,C); cloud->addRGBColor(C); } cloud->showColors(true); } else { ccLog::Warning("[ccGenericMesh::samplePoints] Failed to interpolate colors (not enough memory?)"); } } } //we rename the resulting cloud cloud->setName(getName()+QString(".sampled")); cloud->setDisplay(getDisplay()); cloud->prepareDisplayForRefresh(); //copy 'shift on load' information if (getAssociatedCloud()) { const CCVector3d& shift = getAssociatedCloud()->getGlobalShift(); cloud->setGlobalShift(shift); double scale = getAssociatedCloud()->getGlobalScale(); cloud->setGlobalScale(scale); } if (triIndices) triIndices->release(); return cloud; }
QGeometry *ObjLoader::geometry() const { QByteArray bufferBytes; const int count = m_points.size(); const quint32 elementSize = 3 + (hasTextureCoordinates() ? 2 : 0) + (hasNormals() ? 3 : 0) + (hasTangents() ? 4 : 0); const quint32 stride = elementSize * sizeof(float); bufferBytes.resize(stride * count); float* fptr = reinterpret_cast<float*>(bufferBytes.data()); for (int index = 0; index < count; ++index) { *fptr++ = m_points.at(index).x(); *fptr++ = m_points.at(index).y(); *fptr++ = m_points.at(index).z(); if (hasTextureCoordinates()) { *fptr++ = m_texCoords.at(index).x(); *fptr++ = m_texCoords.at(index).y(); } if (hasNormals()) { *fptr++ = m_normals.at(index).x(); *fptr++ = m_normals.at(index).y(); *fptr++ = m_normals.at(index).z(); } if (hasTangents()) { *fptr++ = m_tangents.at(index).x(); *fptr++ = m_tangents.at(index).y(); *fptr++ = m_tangents.at(index).z(); *fptr++ = m_tangents.at(index).w(); } } // of buffer filling loop QBuffer *buf(new QBuffer(QBuffer::VertexBuffer)); buf->setData(bufferBytes); QGeometry *geometry = new QGeometry(); QAttribute *positionAttribute = new QAttribute(buf, QAttribute::defaultPositionAttributeName(), QAttribute::Float, 3, count, 0, stride); geometry->addAttribute(positionAttribute); quint32 offset = sizeof(float) * 3; if (hasTextureCoordinates()) { QAttribute *texCoordAttribute = new QAttribute(buf, QAttribute::defaultTextureCoordinateAttributeName(), QAttribute::Float, 2, count, offset, stride); geometry->addAttribute(texCoordAttribute); offset += sizeof(float) * 2; } if (hasNormals()) { QAttribute *normalAttribute = new QAttribute(buf, QAttribute::defaultNormalAttributeName(), QAttribute::Float, 3, count, offset, stride); geometry->addAttribute(normalAttribute); offset += sizeof(float) * 3; } if (hasTangents()) { QAttribute *tangentAttribute = new QAttribute(buf, QAttribute::defaultTangentAttributeName(),QAttribute::Float, 4, count, offset, stride); geometry->addAttribute(tangentAttribute); offset += sizeof(float) * 4; } QByteArray indexBytes; QAttribute::DataType ty; if (m_indices.size() < 65536) { // we can use USHORT ty = QAttribute::UnsignedShort; indexBytes.resize(m_indices.size() * sizeof(quint16)); quint16* usptr = reinterpret_cast<quint16*>(indexBytes.data()); for (int i=0; i<m_indices.size(); ++i) *usptr++ = static_cast<quint16>(m_indices.at(i)); } else { // use UINT - no conversion needed, but let's ensure int is 32-bit! ty = QAttribute::UnsignedInt; Q_ASSERT(sizeof(int) == sizeof(quint32)); indexBytes.resize(m_indices.size() * sizeof(quint32)); memcpy(indexBytes.data(), reinterpret_cast<const char*>(m_indices.data()), indexBytes.size()); } QBuffer *indexBuffer(new QBuffer(QBuffer::IndexBuffer)); indexBuffer->setData(indexBytes); QAttribute *indexAttribute = new QAttribute(indexBuffer, ty, 1, m_indices.size()); indexAttribute->setAttributeType(QAttribute::IndexAttribute); geometry->addAttribute(indexAttribute); return geometry; }
bool ModelOBJ::import(const char *pszFilename, bool rebuildNormals) { FILE *pFile = fopen(pszFilename, "r"); if (!pFile) return false; // Extract the directory the OBJ file is in from the file name. // This directory path will be used to load the OBJ's associated MTL file. m_directoryPath.clear(); std::string filename = pszFilename; std::string::size_type offset = filename.find_last_of('\\'); if (offset != std::string::npos) { m_directoryPath = filename.substr(0, ++offset); } else { offset = filename.find_last_of('/'); if (offset != std::string::npos) m_directoryPath = filename.substr(0, ++offset); } // Import the OBJ file. importGeometryFirstPass(pFile); rewind(pFile); importGeometrySecondPass(pFile); fclose(pFile); // Perform post import tasks. buildMeshes(); bounds(m_center, m_width, m_height, m_length, m_radius); // Build vertex normals if required. if (rebuildNormals) { generateNormals(); } else { if (!hasNormals()) generateNormals(); } // Build tangents is required. for (int i = 0; i < m_numberOfMaterials; ++i) { if (!m_materials[i].bumpMapFilename.empty()) { generateTangents(); break; } } return true; }
bool ccGenericMesh::laplacianSmooth(unsigned nbIteration, float factor, CCLib::GenericProgressCallback* progressCb/*=0*/) { if (!m_associatedCloud) return false; //vertices unsigned vertCount = m_associatedCloud->size(); //triangles unsigned faceCount = size(); if (!vertCount || !faceCount) return false; GenericChunkedArray<3,PointCoordinateType>* verticesDisplacement = new GenericChunkedArray<3,PointCoordinateType>; if (!verticesDisplacement->resize(vertCount)) { //not enough memory verticesDisplacement->release(); return false; } //compute the number of edges to which belong each vertex unsigned* edgesCount = new unsigned[vertCount]; if (!edgesCount) { //not enough memory verticesDisplacement->release(); return false; } memset(edgesCount, 0, sizeof(unsigned)*vertCount); placeIteratorAtBegining(); for(unsigned j=0; j<faceCount; j++) { const CCLib::TriangleSummitsIndexes* tri = getNextTriangleIndexes(); edgesCount[tri->i1]+=2; edgesCount[tri->i2]+=2; edgesCount[tri->i3]+=2; } //progress dialog CCLib::NormalizedProgress* nProgress = 0; if (progressCb) { unsigned totalSteps = nbIteration; nProgress = new CCLib::NormalizedProgress(progressCb,totalSteps); progressCb->setMethodTitle("Laplacian smooth"); progressCb->setInfo(qPrintable(QString("Iterations: %1\nVertices: %2\nFaces: %3").arg(nbIteration).arg(vertCount).arg(faceCount))); progressCb->start(); } //repeat Laplacian smoothing iterations for(unsigned iter = 0; iter < nbIteration; iter++) { verticesDisplacement->fill(0); //for each triangle placeIteratorAtBegining(); for(unsigned j=0; j<faceCount; j++) { const CCLib::TriangleSummitsIndexes* tri = getNextTriangleIndexes(); const CCVector3* A = m_associatedCloud->getPoint(tri->i1); const CCVector3* B = m_associatedCloud->getPoint(tri->i2); const CCVector3* C = m_associatedCloud->getPoint(tri->i3); CCVector3 dAB = (*B-*A); CCVector3 dAC = (*C-*A); CCVector3 dBC = (*C-*B); CCVector3* dA = (CCVector3*)verticesDisplacement->getValue(tri->i1); (*dA) += dAB+dAC; CCVector3* dB = (CCVector3*)verticesDisplacement->getValue(tri->i2); (*dB) += dBC-dAB; CCVector3* dC = (CCVector3*)verticesDisplacement->getValue(tri->i3); (*dC) -= dAC+dBC; } if (nProgress && !nProgress->oneStep()) { //cancelled by user break; } //apply displacement verticesDisplacement->placeIteratorAtBegining(); for (unsigned i=0; i<vertCount; i++) { //this is a "persistent" pointer and we know what type of cloud is behind ;) CCVector3* P = const_cast<CCVector3*>(m_associatedCloud->getPointPersistentPtr(i)); const CCVector3* d = (const CCVector3*)verticesDisplacement->getValue(i); (*P) += (*d)*(factor/(PointCoordinateType)edgesCount[i]); } } m_associatedCloud->updateModificationTime(); if (hasNormals()) computeNormals(); if (verticesDisplacement) verticesDisplacement->release(); verticesDisplacement=0; if (edgesCount) delete[] edgesCount; edgesCount=0; if (nProgress) delete nProgress; nProgress=0; return true; }
void SkinnedMesh::buildSkinnedMesh(ID3DXMesh* mesh) { //==================================================================== // First add a normal component and 2D texture coordinates component. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh* tempMesh = 0; HR(mesh->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &tempMesh)); if( !hasNormals(tempMesh) ) HR(D3DXComputeNormals(tempMesh, 0)); //==================================================================== // Optimize the mesh; in particular, the vertex cache. DWORD* adj = new DWORD[tempMesh->GetNumFaces()*3]; ID3DXBuffer* remap = 0; HR(tempMesh->GenerateAdjacency(EPSILON, adj)); ID3DXMesh* optimizedTempMesh = 0; HR(tempMesh->Optimize(D3DXMESH_SYSTEMMEM | D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_ATTRSORT, adj, 0, 0, &remap, &optimizedTempMesh)); ReleaseCOM(tempMesh); // Done w/ this mesh. delete[] adj; // Done with buffer. // In the .X file (specifically the array DWORD vertexIndices[nWeights] // data member of the SkinWeights template) each bone has an array of // indices which identify the vertices of the mesh that the bone influences. // Because we have just rearranged the vertices (from optimizing), the vertex // indices of a bone are obviously incorrect (i.e., they index to vertices the bone // does not influence since we moved vertices around). In order to update a bone's // vertex indices to the vertices the bone _does_ influence, we simply need to specify // where we remapped the vertices to, so that the vertex indices can be updated to // match. This is done with the ID3DXSkinInfo::Remap method. HR(mSkinInfo->Remap(optimizedTempMesh->GetNumVertices(), (DWORD*)remap->GetBufferPointer())); ReleaseCOM(remap); // Done with remap info. //==================================================================== // The vertex format of the source mesh does not include vertex weights // nor bone index data, which are both needed for vertex blending. // Therefore, we must convert the source mesh to an "indexed-blended-mesh," // which does have the necessary data. DWORD numBoneComboEntries = 0; ID3DXBuffer* boneComboTable = 0; HR(mSkinInfo->ConvertToIndexedBlendedMesh(optimizedTempMesh, D3DXMESH_MANAGED | D3DXMESH_WRITEONLY, MAX_NUM_BONES_SUPPORTED, 0, 0, 0, 0, &mMaxVertInfluences, &numBoneComboEntries, &boneComboTable, &mSkinnedMesh)); ReleaseCOM(optimizedTempMesh); // Done with tempMesh. ReleaseCOM(boneComboTable); // Don't need bone table. #if defined(DEBUG) | defined(_DEBUG) // Output to the debug output the vertex declaration of the mesh at this point. // This is for insight only to see what exactly ConvertToIndexedBlendedMesh // does to the vertex declaration. D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(mSkinnedMesh->GetDeclaration(elems)); OutputDebugString("\nVertex Format After ConvertToIndexedBlendedMesh\n"); int i = 0; while( elems[i].Stream != 0xff ) // While not D3DDECL_END() { if( elems[i].Type == D3DDECLTYPE_FLOAT1) OutputDebugString("Type = D3DDECLTYPE_FLOAT1; "); if( elems[i].Type == D3DDECLTYPE_FLOAT2) OutputDebugString("Type = D3DDECLTYPE_FLOAT2; "); if( elems[i].Type == D3DDECLTYPE_FLOAT3) OutputDebugString("Type = D3DDECLTYPE_FLOAT3; "); if( elems[i].Type == D3DDECLTYPE_UBYTE4) OutputDebugString("Type = D3DDECLTYPE_UBYTE4; "); if( elems[i].Usage == D3DDECLUSAGE_POSITION) OutputDebugString("Usage = D3DDECLUSAGE_POSITION\n"); if( elems[i].Usage == D3DDECLUSAGE_BLENDWEIGHT) OutputDebugString("Usage = D3DDECLUSAGE_BLENDWEIGHT\n"); if( elems[i].Usage == D3DDECLUSAGE_BLENDINDICES) OutputDebugString("Usage = D3DDECLUSAGE_BLENDINDICES\n"); if( elems[i].Usage == D3DDECLUSAGE_NORMAL) OutputDebugString("Usage = D3DDECLUSAGE_NORMAL\n"); if( elems[i].Usage == D3DDECLUSAGE_TEXCOORD) OutputDebugString("Usage = D3DDECLUSAGE_TEXCOORD\n"); ++i; } #endif }
void ofxOBJModel::loadVbo() { int count = 0; for(int i = 0; i < meshes.size(); i++) { for(int j = 0; j < meshes[i]->faces.size(); j++) { int pointCount = meshes[i]->faces[j]->points.size(); if(pointCount==3) { count += 3; } else { // if the poly has more than 3 sides, // we're gonna do a triangle fan. // 4 points goes to 6 points // 5 points goes to 9 points // 6 points goes to 12 points count += (pointCount - 2)*3; } } } coords = new ofVec3f[count]; ofVec3f *normals = NULL; ofVec2f *texCoords = NULL; if(hasNormals()) normals = new ofVec3f[count]; if(hasTexCoords()) texCoords = new ofVec2f[count]; int pos = 0; for(int i = 0; i < meshes.size(); i++) { for(int j = 0; j < meshes[i]->faces.size(); j++) { int pointCount = meshes[i]->faces[j]->points.size(); if(pointCount==3) { for(int k = 0; k < pointCount; k++) { coords[pos] = meshes[i]->faces[j]->points[k]; if(normals!=NULL) { normals[pos] = meshes[i]->faces[j]->normals[k]; } if(texCoords!=NULL) { texCoords[pos] = meshes[i]->faces[j]->texCoords[k]; } pos++; } } else { // triangle fan int triCount = pointCount - 2; for(int tri = 0; tri < triCount; tri++) { for(int p = 0; p < 3; p++) { coords[pos] = meshes[i]->faces[j]->points[tri+p]; if(normals!=NULL) { normals[pos] = meshes[i]->faces[j]->normals[tri+p]; } if(texCoords!=NULL) { texCoords[pos] = meshes[i]->faces[j]->texCoords[tri+p]; } pos++; } } } } } vbo.clear(); vbo.setVertexData(coords, count, GL_STATIC_DRAW_ARB); if(normals!=NULL) vbo.setNormalData(normals, count, GL_STATIC_DRAW_ARB); if(texCoords!=NULL) vbo.setTexCoordData(texCoords, count, GL_STATIC_DRAW_ARB); //delete [] coords; if(normals!=NULL) delete [] normals; if(texCoords!=NULL) delete [] texCoords; vboCoordCount = count; }