void vMarchCube( const BoundedVolume<T,roo::TargetHost> vol, const BoundedVolume<TColor,roo::TargetHost> volColor, int x, int y, int z, std::vector<aiVector3D>& verts, std::vector<aiVector3D>& norms, std::vector<aiFace>& faces, std::vector<aiColor4D>& colors, float fTargetValue = 0.0f ) { const float3 p = vol.VoxelPositionInUnits(x,y,z); const float3 fScale = vol.VoxelSizeUnits(); //Make a local copy of the values at the cube's corners float afCubeValue[8]; for(int iVertex = 0; iVertex < 8; iVertex++) { afCubeValue[iVertex] = vol.Get(x+a2fVertexOffset[iVertex][0],y+a2fVertexOffset[iVertex][1],z+a2fVertexOffset[iVertex][2]); if(!std::isfinite(afCubeValue[iVertex])) return; } //Find which vertices are inside of the surface and which are outside int iFlagIndex = 0; for(int iVertexTest = 0; iVertexTest < 8; iVertexTest++) { if(afCubeValue[iVertexTest] <= fTargetValue) iFlagIndex |= 1<<iVertexTest; } //Find which edges are intersected by the surface int iEdgeFlags = aiCubeEdgeFlags[iFlagIndex]; //If the cube is entirely inside or outside of the surface, then there will be no intersections if(iEdgeFlags == 0) { return; } //Find the point of intersection of the surface with each edge //Then find the normal to the surface at those points float3 asEdgeVertex[12]; float3 asEdgeNorm[12]; for(int iEdge = 0; iEdge < 12; iEdge++) { //if there is an intersection on this edge if(iEdgeFlags & (1<<iEdge)) { float fOffset = fGetOffset(afCubeValue[ a2iEdgeConnection[iEdge][0] ], afCubeValue[ a2iEdgeConnection[iEdge][1] ], fTargetValue); asEdgeVertex[iEdge] = make_float3( p.x + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0] + fOffset * a2fEdgeDirection[iEdge][0]) * fScale.x, p.y + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1] + fOffset * a2fEdgeDirection[iEdge][1]) * fScale.y, p.z + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2] + fOffset * a2fEdgeDirection[iEdge][2]) * fScale.z ); const float3 deriv = vol.GetUnitsBackwardDiffDxDyDz( asEdgeVertex[iEdge] ); asEdgeNorm[iEdge] = deriv / length(deriv); if( !std::isfinite(asEdgeNorm[iEdge].x) || !std::isfinite(asEdgeNorm[iEdge].y) || !std::isfinite(asEdgeNorm[iEdge].z) ) { asEdgeNorm[iEdge] = make_float3(0,0,0); } } } //Draw the triangles that were found. There can be up to five per cube for(int iTriangle = 0; iTriangle < 5; iTriangle++) { if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0) break; aiFace face; face.mNumIndices = 3; face.mIndices = new unsigned int[face.mNumIndices]; for(int iCorner = 0; iCorner < 3; iCorner++) { int iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner]; face.mIndices[iCorner] = verts.size(); verts.push_back(aiVector3D(asEdgeVertex[iVertex].x, asEdgeVertex[iVertex].y, asEdgeVertex[iVertex].z) ); norms.push_back(aiVector3D(asEdgeNorm[iVertex].x, asEdgeNorm[iVertex].y, asEdgeNorm[iVertex].z) ); if(volColor.IsValid()) { const TColor c = volColor.GetUnitsTrilinearClamped(asEdgeVertex[iVertex]); float3 sColor = roo::ConvertPixel<float3,TColor>(c); colors.push_back(aiColor4D(sColor.x, sColor.y, sColor.z, 1.0f)); } } faces.push_back(face); } }
// ------------------------------------------------------------------------------------------------ // read an array of color4 tuples void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el) { out.resize( 0 ); const TokenList& tok = el.Tokens(); if(tok.empty()) { ParseError("unexpected empty element",&el); } if(tok[0]->IsBinary()) { const char* data = tok[0]->begin(), *end = tok[0]->end(); char type; uint32_t count; ReadBinaryDataArrayHead(data, end, type, count, el); if(count % 4 != 0) { ParseError("number of floats is not a multiple of four (4) (binary)",&el); } if(!count) { return; } if (type != 'd' && type != 'f') { ParseError("expected float or double array (binary)",&el); } std::vector<char> buff; ReadBinaryDataArray(type, count, data, end, buff, el); ai_assert(data == end); ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); const uint32_t count4 = count / 4; out.reserve(count4); if (type == 'd') { const double* d = reinterpret_cast<const double*>(&buff[0]); for (unsigned int i = 0; i < count4; ++i, d += 4) { out.push_back(aiColor4D(static_cast<float>(d[0]), static_cast<float>(d[1]), static_cast<float>(d[2]), static_cast<float>(d[3]))); } } else if (type == 'f') { const float* f = reinterpret_cast<const float*>(&buff[0]); for (unsigned int i = 0; i < count4; ++i, f += 4) { out.push_back(aiColor4D(f[0],f[1],f[2],f[3])); } } return; } const size_t dim = ParseTokenAsDim(*tok[0]); // see notes in ParseVectorDataArray() above out.reserve(dim); const Scope& scope = GetRequiredScope(el); const Element& a = GetRequiredElement(scope,"a",&el); if (a.Tokens().size() % 4 != 0) { ParseError("number of floats is not a multiple of four (4)",&el); } for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { aiColor4D v; v.r = ParseTokenAsFloat(**it++); v.g = ParseTokenAsFloat(**it++); v.b = ParseTokenAsFloat(**it++); v.a = ParseTokenAsFloat(**it++); out.push_back(v); } }
//------------------------------------------- void ofxAssimpModelLoader::loadGLResources(){ ofLog(OF_LOG_VERBOSE, "loading gl resources"); // create new mesh helpers for each mesh, will populate their data later. modelMeshes.reserve(scene->mNumMeshes); // create OpenGL buffers and populate them based on each meshes pertinant info. for (unsigned int i = 0; i < scene->mNumMeshes; ++i){ ofLog(OF_LOG_VERBOSE, "loading mesh %u", i); // current mesh we are introspecting aiMesh* mesh = scene->mMeshes[i]; // the current meshHelper we will be populating data into. ofxAssimpMeshHelper meshHelper; meshHelper.mesh = mesh; // set the mesh's default values. aiColor4D dcolor = aiColor4D(0.8f, 0.8f, 0.8f, 1.0f); meshHelper.diffuseColor = dcolor; aiColor4D scolor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); meshHelper.specularColor = scolor; aiColor4D acolor = aiColor4D(0.2f, 0.2f, 0.2f, 1.0f); meshHelper.ambientColor = acolor; aiColor4D ecolor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); meshHelper.emissiveColor = ecolor; // Handle material info aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex]; // Load Textures int texIndex = 0; aiString texPath; //meshHelper.texture = NULL; // TODO: handle other aiTextureTypes if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)){ // This is magic. Thanks Kyle. textures.push_back(ofImage()); ofImage& image = textures.back(); ofLog(OF_LOG_VERBOSE, "loading image from %s", texPath.data); image.loadImage(texPath.data); image.update(); ofLog(OF_LOG_VERBOSE, "texture width: %f height %f", image.getWidth(), image.getHeight()); //meshHelper.texture = &(image.getTextureReference()); meshHelper.textureIndex = textures.size()-1; } if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &dcolor)) meshHelper.diffuseColor = dcolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &scolor)) meshHelper.specularColor = scolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &acolor)) meshHelper.ambientColor = acolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &ecolor)) meshHelper.emissiveColor = ecolor; // Culling unsigned int max = 1; int two_sided; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) meshHelper.twoSided = true; else meshHelper.twoSided = false; // Create a VBO for our vertices GLuint vhandle; glGenBuffers(1, &vhandle); glBindBuffer(GL_ARRAY_BUFFER, vhandle); if(getAnimationCount()) glBufferData(GL_ARRAY_BUFFER, sizeof(aiVertex) * mesh->mNumVertices, NULL, GL_STREAM_DRAW/*GL_STATIC_DRAW GL_STREAM_DRAW*/); else glBufferData(GL_ARRAY_BUFFER, sizeof(aiVertex) * mesh->mNumVertices, NULL, GL_STATIC_DRAW/*GL_STATIC_DRAW GL_STREAM_DRAW*/); // populate vertices aiVertex* verts = (aiVertex*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { verts->vPosition = mesh->mVertices[x]; if (NULL == mesh->mNormals) verts->vNormal = aiVector3D(0.0f,0.0f,0.0f); else verts->vNormal = mesh->mNormals[x]; if (mesh->HasVertexColors(0)) { verts->dColorDiffuse = mesh->mColors[0][x]; } else verts->dColorDiffuse = aiColor4D(1.0, 1.0, 1.0, 1.0); // This varies slightly form Assimp View, we support the 3rd texture component. if (mesh->HasTextureCoords(0)) verts->vTextureUV = mesh->mTextureCoords[0][x]; else verts->vTextureUV = aiVector3D(0.5f,0.5f, 0.0f); // No longer in aiVertex VBO structure /* if (NULL == mesh->mTangents) { verts->vTangent = aiVector3D(0.0f,0.0f,0.0f); verts->vBitangent = aiVector3D(0.0f,0.0f,0.0f); } else { verts->vTangent = mesh->mTangents[x]; verts->vBitangent = mesh->mBitangents[x]; } if (mesh->HasTextureCoords(1)) verts->vTextureUV2 = mesh->mTextureCoords[1][x]; else verts->vTextureUV2 = aiVector3D(0.5f,0.5f, 0.0f); if( mesh->HasBones()){ unsigned char boneIndices[4] = { 0, 0, 0, 0 }; unsigned char boneWeights[4] = { 0, 0, 0, 0 }; ai_assert( weightsPerVertex[x].size() <= 4); for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++){ boneIndices[a] = weightsPerVertex[x][a].mVertexId; boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f); } memcpy( verts->mBoneIndices, boneIndices, sizeof( boneIndices)); memcpy( verts->mBoneWeights, boneWeights, sizeof( boneWeights)); } else{ // memset( verts->mBoneIndices, 0, sizeof( verts->mBoneIndices)); // memset( verts->mBoneWeights, 0, sizeof( verts->mBoneWeights)); } */ ++verts; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); // set the mesh vertex buffer handle to our new vertex buffer. meshHelper.vertexBuffer = vhandle; // Create Index Buffer unsigned int nidx; switch (mesh->mPrimitiveTypes){ case aiPrimitiveType_POINT: nidx = 1;break; case aiPrimitiveType_LINE: nidx = 2;break; case aiPrimitiveType_TRIANGLE: nidx = 3;break; default: assert(false); } GLuint ihandle; glGenBuffers(1, &ihandle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ihandle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * mesh->mNumFaces * nidx, NULL, GL_STATIC_DRAW/*GL_STATIC_DRAW GL_STREAM_DRAW*/); unsigned int* indices = (unsigned int*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_ARB); // now fill the index buffer for (unsigned int x = 0; x < mesh->mNumFaces; ++x){ for (unsigned int a = 0; a < nidx; ++a){ *indices++ = mesh->mFaces[x].mIndices[a]; } } glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // set the mesh index buffer handle to our new index buffer. meshHelper.indexBuffer = ihandle; meshHelper.numIndices = mesh->mNumFaces * nidx; // create the normal buffer. Assimp View creates a second normal buffer. Unsure why. Using only the interleaved normals for now. // This is here for reference. /* GLuint nhandle; glGenBuffers(1, &nhandle); glBindBuffer(GL_ARRAY_BUFFER, nhandle); glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D)* mesh->mNumVertices, NULL, GL_STATIC_DRAW); // populate normals aiVector3D* normals = (aiVector3D*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { aiVector3D vNormal = mesh->mNormals[x]; *normals = vNormal; ++normals; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); meshHelper.normalBuffer = nhandle; */ // Create VAO and populate it GLuint vaoHandle; glGenVertexArraysAPPLE(1, &vaoHandle); // TODO: equivalent PC call. glBindVertexArrayAPPLE(vaoHandle); glBindBuffer(GL_ARRAY_BUFFER, meshHelper.vertexBuffer); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, sizeof(aiVertex), BUFFER_OFFSET(12)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(3, GL_FLOAT, sizeof(aiVertex), BUFFER_OFFSET(24)); //TODO: handle second texture glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, sizeof(aiVertex), BUFFER_OFFSET(36)); // VertexPointer ought to come last, apparently this is some optimization, since if its set once first, it gets fiddled with every time something else is update. glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(aiVertex), 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshHelper.indexBuffer); glBindVertexArrayAPPLE(0); // save the VAO handle into our mesh helper meshHelper.vao = vaoHandle; modelMeshes.push_back(meshHelper); } ofLog(OF_LOG_VERBOSE, "finished loading gl resources"); }
// http://sourceforge.net/projects/assimp/forums/forum/817654/topic/3880745 void ofxAssimpModelLoader::updateGLResources(){ // update mesh position for the animation for (unsigned int i = 0; i < modelMeshes.size(); ++i){ // current mesh we are introspecting const aiMesh* mesh = modelMeshes[i].mesh; // calculate bone matrices std::vector<aiMatrix4x4> boneMatrices( mesh->mNumBones); for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; // find the corresponding node by again looking recursively through the node hierarchy for the same name aiNode* node = scene->mRootNode->FindNode(bone->mName); // start with the mesh-to-bone matrix boneMatrices[a] = bone->mOffsetMatrix; // and now append all node transformations down the parent chain until we're back at mesh coordinates again const aiNode* tempNode = node; while( tempNode) { // check your matrix multiplication order here!!! boneMatrices[a] = tempNode->mTransformation * boneMatrices[a]; // boneMatrices[a] = boneMatrices[a] * tempNode->mTransformation; tempNode = tempNode->mParent; } } // all using the results from the previous code snippet std::vector<aiVector3D> resultPos( mesh->mNumVertices); std::vector<aiVector3D> resultNorm( mesh->mNumVertices); // loop through all vertex weights of all bones for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = boneMatrices[a]; // 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo); for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; resultPos[vertexId] += weight.mWeight * (posTrafo * srcPos); resultNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } // now upload the result position and normal along with the other vertex attributes into a dynamic vertex buffer, VBO or whatever // get mesh helper for this mesh; ofxAssimpMeshHelper meshHelper = modelMeshes[i]; glBindBuffer(GL_ARRAY_BUFFER, meshHelper.vertexBuffer); aiVertex* verts = (aiVertex*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { //verts->vPosition = mesh->mVertices[x]; verts->vPosition = resultPos[x]; if (NULL == mesh->mNormals) verts->vNormal = aiVector3D(0.0f,0.0f,0.0f); else verts->vNormal = resultNorm[x]; if (mesh->HasVertexColors(0)) { verts->dColorDiffuse = mesh->mColors[0][x]; } else verts->dColorDiffuse = aiColor4D(1.0, 1.0, 1.0, 1.0); // This varies slightly form Assimp View, we support the 3rd texture component. if (mesh->HasTextureCoords(0)) verts->vTextureUV = mesh->mTextureCoords[0][x]; else verts->vTextureUV = aiVector3D(0.5f,0.5f, 0.0f); // No longer in aiVertex VBO structure /* if (NULL == mesh->mTangents) { verts->vTangent = aiVector3D(0.0f,0.0f,0.0f); verts->vBitangent = aiVector3D(0.0f,0.0f,0.0f); } else { verts->vTangent = mesh->mTangents[x]; verts->vBitangent = mesh->mBitangents[x]; } if (mesh->HasTextureCoords(1)) verts->vTextureUV2 = mesh->mTextureCoords[1][x]; else verts->vTextureUV2 = aiVector3D(0.5f,0.5f, 0.0f); if( mesh->HasBones()){ unsigned char boneIndices[4] = { 0, 0, 0, 0 }; unsigned char boneWeights[4] = { 0, 0, 0, 0 }; ai_assert( weightsPerVertex[x].size() <= 4); for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++){ boneIndices[a] = weightsPerVertex[x][a].mVertexId; boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f); } memcpy( verts->mBoneIndices, boneIndices, sizeof( boneIndices)); memcpy( verts->mBoneWeights, boneWeights, sizeof( boneWeights)); } else{ // memset( verts->mBoneIndices, 0, sizeof( verts->mBoneIndices)); // memset( verts->mBoneWeights, 0, sizeof( verts->mBoneWeights)); } */ ++verts; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); } }
void CGLView::SetScene(const aiScene *pScene, const QString& pScenePath) { FreeScene();// Clear old data // Why checking here, not at begin of function. Because old scene may not exist at know. So, need cleanup. if(pScene == nullptr) return; mScene = pScene;// Copy pointer of new scene. // // Meshes // // Create helper objects for meshes. This allow to render meshes as OpenGL arrays. if(mScene->HasMeshes()) { // Create mesh helpers array. mHelper_Mesh_Quantity = mScene->mNumMeshes; mHelper_Mesh = new SHelper_Mesh*[mScene->mNumMeshes]; // Walk thru the meshes and extract needed data and, also calculate BBox. for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) { aiMesh& mesh_cur = *mScene->mMeshes[idx_mesh]; // // Calculate BBox // SBBox mesh_bbox; BBox_GetFromVertices(mesh_cur.mVertices, mesh_cur.mNumVertices, mesh_bbox); // // Create vertices indices arrays splited by primitive type. // size_t indcnt_p = 0;// points quantity size_t indcnt_l = 0;// lines quantity size_t indcnt_t = 0;// triangles quantity if(mesh_cur.HasFaces()) { // Usual way: all faces are triangles if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) { indcnt_t = mesh_cur.mNumFaces; } else { // Calculate count of primitives by types. for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) { if(mesh_cur.mFaces[idx_face].mNumIndices == 3) indcnt_t++; else if(mesh_cur.mFaces[idx_face].mNumIndices == 2) indcnt_l++; else if(mesh_cur.mFaces[idx_face].mNumIndices == 1) indcnt_p++; } }// if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) else // Create helper mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, indcnt_l, indcnt_t, mesh_bbox); // Fill indices arrays indcnt_p = 0, indcnt_l = 0, indcnt_t = 0;// Reuse variables as indices for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) { if(mesh_cur.mFaces[idx_face].mNumIndices == 3) { mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[0]; mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[1]; mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[2]; } else if(mesh_cur.mFaces[idx_face].mNumIndices == 2) { mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[0]; mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[1]; } else if(mesh_cur.mFaces[idx_face].mNumIndices == 1) { mHelper_Mesh[idx_mesh]->Index_Point[indcnt_p++] = mesh_cur.mFaces[idx_face].mIndices[0]; } }// for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) }// if(mesh_cur.HasFaces()) else { // If mesh has no faces then vertices can be just points set. indcnt_p = mesh_cur.mNumVertices; // Create helper mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, 0, 0, mesh_bbox); // Fill indices arrays for(size_t idx = 0; idx < indcnt_p; idx++) mHelper_Mesh[idx_mesh]->Index_Point[idx] = idx; }// if(mesh_cur.HasFaces()) else }// for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) }// if(mScene->HasMeshes()) // // Scene BBox // // For calculating right BBox we must walk thru all nodes and apply transformation to meshes BBoxes if(mHelper_Mesh_Quantity > 0) { bool first_assign = true; aiMatrix4x4 mat_root; BBox_GetForNode(*mScene->mRootNode, mat_root, mScene_BBox, first_assign); mScene_Center = mScene_BBox.Maximum + mScene_BBox.Minimum; mScene_Center /= 2; } else { mScene_BBox = {{0, 0, 0}, {0, 0, 0}}; mScene_Center = {0, 0, 0}; }// if(mHelper_Mesh_Count > 0) else // // Textures // ImportTextures(pScenePath); // // Light sources // Lighting_Enable(); // If scene has no lights then enable default if(!mScene->HasLights()) { const GLfloat col_amb[4] = { 0.2, 0.2, 0.2, 1.0 }; SLightParameters lp; lp.Type = aiLightSource_POINT; lp.Ambient.r = col_amb[0], lp.Ambient.g = col_amb[1], lp.Ambient.b = col_amb[2], lp.Ambient.a = col_amb[3]; lp.Diffuse = { 1.0, 1.0, 1.0, 1.0 }; lp.Specular = lp.Diffuse; lp.For.Point.Position = mScene_Center; lp.For.Point.Attenuation_Constant = 1; lp.For.Point.Attenuation_Linear = 0; lp.For.Point.Attenuation_Quadratic = 0; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col_amb); Lighting_EditSource(0, lp); emit SceneObject_LightSource("_default");// Light source will be enabled in signal handler. } else { for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++) { SLightParameters lp; QString name; const aiLight& light_cur = *mScene->mLights[idx_light]; auto col3_to_col4 = [](const aiColor3D& pCol3) -> aiColor4D { return aiColor4D(pCol3.r, pCol3.g, pCol3.b, 1.0); }; ///TODO: find light source node and apply all transformations // General properties name = light_cur.mName.C_Str(); lp.Ambient = col3_to_col4(light_cur.mColorAmbient); lp.Diffuse = col3_to_col4(light_cur.mColorDiffuse); lp.Specular = col3_to_col4(light_cur.mColorSpecular); lp.Type = light_cur.mType; // Depend on type properties switch(light_cur.mType) { case aiLightSource_DIRECTIONAL: lp.For.Directional.Direction = light_cur.mDirection; break; case aiLightSource_POINT: lp.For.Point.Position = light_cur.mPosition; lp.For.Point.Attenuation_Constant = light_cur.mAttenuationConstant; lp.For.Point.Attenuation_Linear = light_cur.mAttenuationLinear; lp.For.Point.Attenuation_Quadratic = light_cur.mAttenuationQuadratic; break; case aiLightSource_SPOT: lp.For.Spot.Position = light_cur.mPosition; lp.For.Spot.Direction = light_cur.mDirection; lp.For.Spot.Attenuation_Constant = light_cur.mAttenuationConstant; lp.For.Spot.Attenuation_Linear = light_cur.mAttenuationLinear; lp.For.Spot.Attenuation_Quadratic = light_cur.mAttenuationQuadratic; lp.For.Spot.CutOff = light_cur.mAngleOuterCone; break; case aiLightSource_AMBIENT: lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; name.append("_unsup_ambient"); break; case aiLightSource_AREA: lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; name.append("_unsup_area"); break; case aiLightSource_UNDEFINED: lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; name.append("_unsup_undefined"); break; default: lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; name.append("_unsupported_invalid"); break; }// switch(light_cur.mType) // Add light source if(name.isEmpty()) name += QString("%1").arg(idx_light);// Use index if name is empty. Lighting_EditSource(idx_light, lp); emit SceneObject_LightSource(name);// Light source will be enabled in signal handler. }// for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++) }// if(!mScene->HasLights()) else // // Cameras // if(!mScene->HasCameras()) { mCamera_DefaultAdded = true; mHelper_CameraDefault.SetDefault(); // Calculate distance from camera to scene. Distance must be enoguh for that viewport contain whole scene. const GLfloat tg_angle = tan(mCamera_FOVY / 2); GLfloat val_x = ((mScene_BBox.Maximum.x - mScene_BBox.Minimum.x) / 2) / (mCamera_Viewport_AspectRatio * tg_angle); GLfloat val_y = ((mScene_BBox.Maximum.y - mScene_BBox.Minimum.y) / 2) / tg_angle; GLfloat val_step = val_x; AssignIfGreater(val_step, val_y); mHelper_CameraDefault.Translation_ToScene.Set(mScene_Center.x, mScene_Center.y, val_step + mScene_BBox.Maximum.z); emit SceneObject_Camera("_default"); } else { mCamera_DefaultAdded = false; for(size_t idx_cam = 0; idx_cam < mScene->mNumCameras; idx_cam++) { emit SceneObject_Camera(mScene->mCameras[idx_cam]->mName.C_Str()); } }// if(!mScene->HasCameras()) else }