void ModelLoader::CreateIndexBuffer() { aiMesh* mesh = scene->mMeshes[0]; aiMesh* otherMesh = scene->mMeshes[1]; UINT count = mesh->mNumFaces; const aiFace* faces = mesh->mFaces; indexCount = mesh->mNumFaces*3; std::vector<USHORT> indexData( indexCount ); for( UINT faceIndex = 0, dataIndex = 0; faceIndex<count; ++faceIndex, dataIndex += 3 ) { assert( faces[faceIndex].mNumIndices==3 ); //mesh should be triangulated indexData[dataIndex] = (USHORT)faces[faceIndex].mIndices[0]; indexData[dataIndex+1] = (USHORT)faces[faceIndex].mIndices[1]; indexData[dataIndex+2] = (USHORT)faces[faceIndex].mIndices[2]; } D3D11_BUFFER_DESC ibd; ibd.Usage = D3D11_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof( USHORT ) * indexData.size(); ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; ibd.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA initData; initData.pSysMem = indexData.data(); HR( device->CreateBuffer( &ibd, &initData, &ib ) ); }
Mesh* CreateSolidPlane(float xSize, float zSize, int xSegments, int zSegments, const glm::mat4& transform) { int numVertices = (xSegments + 1) * (zSegments + 1); std::vector<VertexPositionNormal> vertexData(numVertices); float xStep = xSize / xSegments; float zStep = zSize / zSegments; VertexPositionNormal* vertexPtr = &vertexData[0]; float z = -0.5f * zSize; for (int j = 0; j <= zSegments; j++) { float x = -0.5f * xSize; for (int i = 0; i <= xSegments; i++) { vertexPtr->pos.x = x; vertexPtr->pos.y = 0; vertexPtr->pos.z = z; vertexPtr->normal.x = 0; vertexPtr->normal.y = 1; vertexPtr->normal.z = 0; ++vertexPtr; x += xStep; } z += zStep; } int numTriangles = 2 * xSegments * zSegments; int numElements = 3 * numTriangles; std::vector<unsigned> indexData(numElements); // use 32-bit indices for large planes!!!11!!! unsigned* indexPtr = &indexData[0]; unsigned e = 0; for (int j = 0; j < zSegments; j++) { for (int i = 0; i < xSegments; i++) { // the four corners of this "square" unsigned e = (xSegments + 1) * j + i; unsigned e1 = e; unsigned e2 = e + 1; unsigned e3 = e + xSegments + 1; unsigned e4 = e + xSegments + 2; // triangle 1 *indexPtr++ = e1; *indexPtr++ = e3; *indexPtr++ = e4; // triangle 2 *indexPtr++ = e1; *indexPtr++ = e4; *indexPtr++ = e2; ++e; } ++e; } return CreateMesh(GL_TRIANGLES, vertexData, indexData); }
void Quads::uploadIndices() const { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf); glBufferData( GL_ELEMENT_ARRAY_BUFFER, indexDataByteCount(), indexData(), GL_STATIC_DRAW); }
Quad::Quad(RenderDevice* renderDevice) : Mesh(renderDevice) { VertexFloat verticeArray[] = { VertexFloat(-1.0f, 1.0f, 0.0f, 0.0, 0.0, 1.0, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), VertexFloat(-1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), VertexFloat(1.0f, -1.0f, 0.0f, 0.0, 0.0, 1.0, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f), VertexFloat(1.0f, 1.0f, 0.0f, 0.0, 0.0, 1.0, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f) }; std::vector<VertexFloat> vertexData(verticeArray, verticeArray + sizeof(verticeArray) / sizeof(verticeArray[0])); unsigned int indexArray[] = { 0, 1, 2, 0, 2, 3, }; std::vector<unsigned int> indexData(indexArray, indexArray + sizeof(indexArray) / sizeof(indexArray[0])); m_Buffer->setVertices(vertexData.size(), &vertexData[0]); m_Buffer->setIndices(indexData.size(), &indexData[0]); }
int main() { int width = 640; int height = 480; if(glfwInit() == GL_FALSE) { std::cerr << "failed to init GLFW" << std::endl; return 1; } // select opengl version glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3); // create a window if(glfwOpenWindow(width, height, 0, 0, 0, 8, 24, 8, GLFW_WINDOW) == GL_FALSE) { std::cerr << "failed to open window" << std::endl; glfwTerminate(); return 1; } // setup windows close callback glfwSetWindowCloseCallback(closedWindow); // this time we disable the mouse cursor since we want differential // mouse input glfwDisable(GLFW_MOUSE_CURSOR); if (gl3wInit()) { std::cerr << "failed to init GL3W" << std::endl; glfwCloseWindow(); glfwTerminate(); return 1; } // draw shader std::string vertex_source = "#version 330\n" "uniform mat4 ViewProjection;\n" "layout(location = 0) in vec4 vposition;\n" "layout(location = 1) in vec3 normal;\n" "out vec4 fcolor;\n" "void main() {\n" " float brightness = dot(normal,normalize(vec3(1,2,3)));\n" " brightness = 0.3+((brightness>0)?0.7*brightness:0.3*brightness);\n" " fcolor = vec4(brightness,brightness,brightness,1);\n" " gl_Position = ViewProjection*vposition;\n" "}\n"; std::string fragment_source = "#version 330\n" "in vec4 fcolor;\n" "layout(location = 0) out vec4 FragColor;\n" "void main() {\n" " FragColor = abs(fcolor);\n" "}\n"; // program and shader handles GLuint shader_program, vertex_shader, fragment_shader; // we need these to properly pass the strings const char *source; int length; // create and compiler vertex shader vertex_shader = glCreateShader(GL_VERTEX_SHADER); source = vertex_source.c_str(); length = vertex_source.size(); glShaderSource(vertex_shader, 1, &source, &length); glCompileShader(vertex_shader); if(!check_shader_compile_status(vertex_shader)) { return 1; } // create and compiler fragment shader fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); source = fragment_source.c_str(); length = fragment_source.size(); glShaderSource(fragment_shader, 1, &source, &length); glCompileShader(fragment_shader); if(!check_shader_compile_status(fragment_shader)) { return 1; } // create program shader_program = glCreateProgram(); // attach shaders glAttachShader(shader_program, vertex_shader); glAttachShader(shader_program, fragment_shader); // link the program and check for errors glLinkProgram(shader_program); check_program_link_status(shader_program); // obtain location of projection uniform GLint DrawViewProjection_location = glGetUniformLocation(shader_program, "ViewProjection"); // trivial shader for occlusion queries std::string query_vertex_source = "#version 330\n" "uniform mat4 ViewProjection;\n" "layout(location = 0) in vec4 vposition;\n" "void main() {\n" " gl_Position = ViewProjection*vposition;\n" "}\n"; std::string query_fragment_source = "#version 330\n" "void main() {\n" "}\n"; // program and shader handles GLuint query_shader_program, query_vertex_shader, query_fragment_shader; // create and compiler vertex shader query_vertex_shader = glCreateShader(GL_VERTEX_SHADER); source = query_vertex_source.c_str(); length = query_vertex_source.size(); glShaderSource(query_vertex_shader, 1, &source, &length); glCompileShader(query_vertex_shader); if(!check_shader_compile_status(query_vertex_shader)) { return 1; } // create and compiler fragment shader query_fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); source = query_fragment_source.c_str(); length = query_fragment_source.size(); glShaderSource(query_fragment_shader, 1, &source, &length); glCompileShader(query_fragment_shader); if(!check_shader_compile_status(query_fragment_shader)) { return 1; } // create program query_shader_program = glCreateProgram(); // attach shaders glAttachShader(query_shader_program, query_vertex_shader); glAttachShader(query_shader_program, query_fragment_shader); // link the program and check for errors glLinkProgram(query_shader_program); check_program_link_status(query_shader_program); // obtain location of projection uniform GLint QueryViewProjection_location = glGetUniformLocation(query_shader_program, "ViewProjection"); // chunk container and chunk parameters std::vector<Chunk> chunks; int chunkrange = 4; int chunksize = 32; // chunk extraction std::cout << "generating chunks, this may take a while." << std::endl; // iterate over all chunks we want to extract for(int i = -chunkrange;i<chunkrange;++i) for(int j = -chunkrange;j<chunkrange;++j) for(int k = -chunkrange;k<chunkrange;++k) { Chunk chunk; // chunk data // generate and bind the vao glGenVertexArrays(1, &chunk.vao); glBindVertexArray(chunk.vao); // generate and bind the vertex buffer object glGenBuffers(1, &chunk.vbo); glBindBuffer(GL_ARRAY_BUFFER, chunk.vbo); std::vector<glm::vec3> vertexData; glm::vec3 offset = static_cast<float>(chunksize) * glm::vec3(i,j,k); float threshold = 0.0f; // iterate over all blocks within the chunk for(int x = 0;x<chunksize;++x) for(int y = 0;y<chunksize;++y) for(int z = 0;z<chunksize;++z) { glm::vec3 pos = glm::vec3(x,y,z) + offset; // insert quads if current block is solid and neighbors are not if(world_function(pos)<threshold) { if(world_function(pos+glm::vec3(1,0,0))>=threshold) { vertexData.push_back(pos+0.5f*glm::vec3( 1, 1, 1)); vertexData.push_back(glm::vec3( 1, 0, 0)); vertexData.push_back(pos+0.5f*glm::vec3( 1,-1, 1)); vertexData.push_back(glm::vec3( 1, 0, 0)); vertexData.push_back(pos+0.5f*glm::vec3( 1, 1,-1)); vertexData.push_back(glm::vec3( 1, 0, 0)); vertexData.push_back(pos+0.5f*glm::vec3( 1,-1,-1)); vertexData.push_back(glm::vec3( 1, 0, 0)); } if(world_function(pos+glm::vec3(0,1,0))>=threshold) { vertexData.push_back(pos+0.5f*glm::vec3( 1, 1, 1)); vertexData.push_back(glm::vec3( 0, 1, 0)); vertexData.push_back(pos+0.5f*glm::vec3( 1, 1,-1)); vertexData.push_back(glm::vec3( 0, 1, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1, 1, 1)); vertexData.push_back(glm::vec3( 0, 1, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1, 1,-1)); vertexData.push_back(glm::vec3( 0, 1, 0)); } if(world_function(pos+glm::vec3(0,0,1))>=threshold) { vertexData.push_back(pos+0.5f*glm::vec3( 1, 1, 1)); vertexData.push_back(glm::vec3( 0, 0, 1)); vertexData.push_back(pos+0.5f*glm::vec3(-1, 1, 1)); vertexData.push_back(glm::vec3( 0, 0, 1)); vertexData.push_back(pos+0.5f*glm::vec3( 1,-1, 1)); vertexData.push_back(glm::vec3( 0, 0, 1)); vertexData.push_back(pos+0.5f*glm::vec3(-1,-1, 1)); vertexData.push_back(glm::vec3( 0, 0, 1)); } if(world_function(pos-glm::vec3(1,0,0))>=threshold) { vertexData.push_back(pos+0.5f*glm::vec3(-1, 1, 1)); vertexData.push_back(glm::vec3(-1, 0, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1, 1,-1)); vertexData.push_back(glm::vec3(-1, 0, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1,-1, 1)); vertexData.push_back(glm::vec3(-1, 0, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1,-1,-1)); vertexData.push_back(glm::vec3(-1, 0, 0)); } if(world_function(pos-glm::vec3(0,1,0))>=threshold) { vertexData.push_back(pos+0.5f*glm::vec3( 1,-1, 1)); vertexData.push_back(glm::vec3( 0,-1, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1,-1, 1)); vertexData.push_back(glm::vec3( 0,-1, 0)); vertexData.push_back(pos+0.5f*glm::vec3( 1,-1,-1)); vertexData.push_back(glm::vec3( 0,-1, 0)); vertexData.push_back(pos+0.5f*glm::vec3(-1,-1,-1)); vertexData.push_back(glm::vec3( 0,-1, 0)); } if(world_function(pos-glm::vec3(0,0,1))>=threshold) { vertexData.push_back(pos+0.5f*glm::vec3( 1, 1,-1)); vertexData.push_back(glm::vec3( 0, 0,-1)); vertexData.push_back(pos+0.5f*glm::vec3( 1,-1,-1)); vertexData.push_back(glm::vec3( 0, 0,-1)); vertexData.push_back(pos+0.5f*glm::vec3(-1, 1,-1)); vertexData.push_back(glm::vec3( 0, 0,-1)); vertexData.push_back(pos+0.5f*glm::vec3(-1,-1,-1)); vertexData.push_back(glm::vec3( 0, 0,-1)); } } } // upload glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3)*vertexData.size(), &vertexData[0], GL_STATIC_DRAW); // set up generic attrib pointers glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (char*)0 + 0*sizeof(GLfloat)); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (char*)0 + 3*sizeof(GLfloat)); // generate and bind the index buffer object glGenBuffers(1, &chunk.ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk.ibo); chunk.quadcount = vertexData.size()/8; std::vector<GLuint> indexData(6*chunk.quadcount); for(int i = 0;i<chunk.quadcount;++i) { indexData[6*i + 0] = 4*i + 0; indexData[6*i + 1] = 4*i + 1; indexData[6*i + 2] = 4*i + 2; indexData[6*i + 3] = 4*i + 2; indexData[6*i + 4] = 4*i + 1; indexData[6*i + 5] = 4*i + 3; } // upload glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*indexData.size(), &indexData[0], GL_STATIC_DRAW); // chunk bounding box // generate and bind the vao glGenVertexArrays(1, &chunk.bounding_vao); glBindVertexArray(chunk.bounding_vao); // generate and bind the vertex buffer object glGenBuffers(1, &chunk.bounding_vbo); glBindBuffer(GL_ARRAY_BUFFER, chunk.bounding_vbo); // data for the bounding cube GLfloat boundingVertexData[] = { // X Y Z // face 0: offset.x+chunksize-0.5f, offset.y+chunksize-0.5f, offset.z+chunksize-0.5f, offset.x-0.5f, offset.y+chunksize-0.5f, offset.z+chunksize-0.5f, offset.x+chunksize-0.5f, offset.y-0.5f, offset.z+chunksize-0.5f, offset.x-0.5f, offset.y-0.5f, offset.z+chunksize-0.5f, // face 1: offset.x+chunksize-0.5f, offset.y+chunksize-0.5f, offset.z+chunksize-0.5f, offset.x+chunksize-0.5f, offset.y-0.5f, offset.z+chunksize-0.5f, offset.x+chunksize-0.5f, offset.y+chunksize-0.5f, offset.z-0.5f, offset.x+chunksize-0.5f, offset.y-0.5f, offset.z-0.5f, // face 2: offset.x+chunksize-0.5f, offset.y+chunksize-0.5f, offset.z+chunksize-0.5f, offset.x+chunksize-0.5f, offset.y+chunksize-0.5f, offset.z-0.5f, offset.x-0.5f, offset.y+chunksize-0.5f, offset.z+chunksize-0.5f, offset.x-0.5f, offset.y+chunksize-0.5f, offset.z-0.5f, // face 3: offset.x+chunksize-0.5f, offset.y+chunksize-0.5f, offset.z-0.5f, offset.x+chunksize-0.5f, offset.y-0.5f, offset.z-0.5f, offset.x-0.5f, offset.y+chunksize-0.5f, offset.z-0.5f, offset.x-0.5f, offset.y-0.5f, offset.z-0.5f, // face 4: offset.x-0.5f, offset.y+chunksize-0.5f, offset.z+chunksize-0.5f, offset.x-0.5f, offset.y+chunksize-0.5f, offset.z-0.5f, offset.x-0.5f, offset.y-0.5f, offset.z+chunksize-0.5f, offset.x-0.5f, offset.y-0.5f, offset.z-0.5f, // face 5: offset.x+chunksize-0.5f, offset.y-0.5f, offset.z+chunksize-0.5f, offset.x-0.5f, offset.y-0.5f, offset.z+chunksize-0.5f, offset.x+chunksize-0.5f, offset.y-0.5f, offset.z-0.5f, offset.x-0.5f, offset.y-0.5f, offset.z-0.5f, }; // 6 faces with 4 vertices with 6 components (floats) // fill with data glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*6*4*3, boundingVertexData, GL_STATIC_DRAW); // set up generic attrib pointers glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (char*)0 + 0*sizeof(GLfloat)); // generate and bind the index buffer object glGenBuffers(1, &chunk.bounding_ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk.bounding_ibo); GLuint boundingIndexData[] = { 0, 1, 2, 2, 1, 3, 4, 5, 6, 6, 5, 7, 8, 9,10,10, 9,11, 12,13,14,14,13,15,16,17,18,18,17,19,20,21,22,22,21,23, }; // fill with data glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*6*2*3, boundingIndexData, GL_STATIC_DRAW); // generate the query object for the occlusion query glGenQueries(1, &chunk.query); // set the center location of the chunk chunk.center = offset + 0.5f*chunksize; // add to container chunks.push_back(chunk); } // "unbind" vao glBindVertexArray(0); // timer query setup // use multiple queries to avoid stalling on getting the results const int querycount = 5; GLuint queries[querycount]; int current_query = 0; glGenQueries(querycount, queries); // we are drawing 3d objects so we want depth testing glEnable(GL_DEPTH_TEST); // camera position and orientation glm::vec3 position; glm::mat4 rotation = glm::mat4(1.0f); running = true; float t = glfwGetTime(); bool occlusion_cull = true; bool space_down = false; // mouse position int mousex, mousey; glfwGetMousePos(&mousex, &mousey); while(running) { // calculate timestep float new_t = glfwGetTime(); float dt = new_t - t; t = new_t; // update mouse differential int tmpx, tmpy; glfwGetMousePos(&tmpx, &tmpy); glm::vec2 mousediff(tmpx-mousex, tmpy-mousey); mousex = tmpx; mousey = tmpy; // find up, forward and right vector glm::mat3 rotation3(rotation); glm::vec3 up = glm::transpose(rotation3)*glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 right = glm::transpose(rotation3)*glm::vec3(1.0f, 0.0f, 0.0f); glm::vec3 forward = glm::transpose(rotation3)*glm::vec3(0.0f, 0.0f,-1.0f); // apply mouse rotation rotation = glm::rotate(rotation, 0.2f*mousediff.x, up); rotation = glm::rotate(rotation, 0.2f*mousediff.y, right); // roll if(glfwGetKey('Q')) { rotation = glm::rotate(rotation, 180.0f*dt, forward); } if(glfwGetKey('E')) { rotation = glm::rotate(rotation,-180.0f*dt, forward); } // movement if(glfwGetKey('W')) { position += 10.0f*dt*forward; } if(glfwGetKey('S')) { position -= 10.0f*dt*forward; } if(glfwGetKey('D')) { position += 10.0f*dt*right; } if(glfwGetKey('A')) { position -= 10.0f*dt*right; } // toggle occlusion culling if(glfwGetKey(GLFW_KEY_SPACE) && !space_down) { occlusion_cull = !occlusion_cull; } space_down = glfwGetKey(GLFW_KEY_SPACE); // terminate on escape if(glfwGetKey(GLFW_KEY_ESC)) { running = false; } // calculate ViewProjection matrix glm::mat4 Projection = glm::perspective(90.0f, 4.0f / 3.0f, 0.1f, 200.f); glm::mat4 View = rotation*glm::translate(glm::mat4(1.0f), -position); glm::mat4 ViewProjection = Projection*View; // set matrices for both shaders glUseProgram(query_shader_program); glUniformMatrix4fv(QueryViewProjection_location, 1, GL_FALSE, glm::value_ptr(ViewProjection)); glUseProgram(shader_program); glUniformMatrix4fv(DrawViewProjection_location, 1, GL_FALSE, glm::value_ptr(ViewProjection)); // set clear color to sky blue glClearColor(0.5f,0.8f,1.0f,1.0f); // clear glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // sort chunks by distance std::sort(chunks.begin(), chunks.end(), DistancePred(position)); size_t i = 0; float maxdist = chunksize; // start timer query glBeginQuery(GL_TIME_ELAPSED, queries[current_query]); // peel chunks while(i!=chunks.size()) { size_t j = i; if(occlusion_cull) { // start occlusion queries and render for the current slice glDisable(GL_CULL_FACE); // we don't want the queries to actually render something glDepthMask(GL_FALSE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glUseProgram(query_shader_program); for(;j<chunks.size() && glm::distance(chunks[j].center, position)<maxdist;++j) { // frustum culling glm::vec4 projected = ViewProjection*glm::vec4(chunks[j].center,1); if( (glm::distance(chunks[j].center,position) > chunksize) && (std::max(std::abs(projected.x), std::abs(projected.y)) > projected.w+chunksize)) continue; // begin occlusion query glBeginQuery(GL_ANY_SAMPLES_PASSED, chunks[j].query); // draw bounding box glBindVertexArray(chunks[j].bounding_vao); glDrawElements(GL_TRIANGLES, 6*6, GL_UNSIGNED_INT, 0); // end occlusion query glEndQuery(GL_ANY_SAMPLES_PASSED); } j = i; } // render the current slice glEnable(GL_CULL_FACE); // turn rendering back on glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glUseProgram(shader_program); for(;j<chunks.size() && glm::distance(chunks[j].center, position)<maxdist;++j) { // frustum culling glm::vec4 projected = ViewProjection*glm::vec4(chunks[j].center,1); if( (glm::distance(chunks[j].center,position) > chunksize) && (std::max(std::abs(projected.x), std::abs(projected.y)) > projected.w+chunksize)) continue; // begin conditional render if(occlusion_cull) glBeginConditionalRender(chunks[j].query, GL_QUERY_BY_REGION_WAIT); // draw chunk glBindVertexArray(chunks[j].vao); glDrawElements(GL_TRIANGLES, 6*chunks[j].quadcount, GL_UNSIGNED_INT, 0); // end conditional render if(occlusion_cull) glEndConditionalRender(); } i = j; maxdist += 2*chunksize; } // end timer query glEndQuery(GL_TIME_ELAPSED); // display timer query results from querycount frames before if(GL_TRUE == glIsQuery(queries[(current_query+1)%querycount])) { GLuint64 result; glGetQueryObjectui64v(queries[(current_query+1)%querycount], GL_QUERY_RESULT, &result); std::cout << result*1.e-6 << " ms/frame" << std::endl; } // advance query counter current_query = (current_query + 1)%querycount; // check for errors GLenum error = glGetError(); if(error != GL_NO_ERROR) { std::cerr << gluErrorString(error); running = false; } // finally swap buffers glfwSwapBuffers(); } // delete the created objects for(size_t i = 0;i<chunks.size();++i) { glDeleteVertexArrays(1, &chunks[i].vao); glDeleteBuffers(1, &chunks[i].vbo); glDeleteBuffers(1, &chunks[i].ibo); glDeleteVertexArrays(1, &chunks[i].bounding_vao); glDeleteBuffers(1, &chunks[i].bounding_vbo); glDeleteBuffers(1, &chunks[i].bounding_ibo); glDeleteQueries(1, &chunks[i].query); } glDeleteQueries(querycount, queries); glDetachShader(shader_program, vertex_shader); glDetachShader(shader_program, fragment_shader); glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); glDeleteProgram(shader_program); glDetachShader(query_shader_program, query_vertex_shader); glDetachShader(query_shader_program, query_fragment_shader); glDeleteShader(query_vertex_shader); glDeleteShader(query_fragment_shader); glDeleteProgram(query_shader_program); glfwCloseWindow(); glfwTerminate(); return 0; }
void StaticMesh::Create(const char* fileName) { char baseDir[256]; char fileNameWoExt[256]; char tempPath[256]; _splitpath_s(fileName, nullptr, 0, baseDir, sizeof(baseDir), fileNameWoExt, sizeof(baseDir), nullptr, 0); // キャッシュファイル名 snprintf(tempPath, sizeof(tempPath), "%s%s.cache", baseDir, fileNameWoExt); std::ifstream cacheFile(tempPath, std::ios::in | std::ios::binary); if (cacheFile) { /** キャッシュから読み込み **/ // ファイル全体をリード cacheFile.seekg(0, std::fstream::end); uint32_t eofPos = (uint32_t)cacheFile.tellg(); cacheFile.clear(); cacheFile.seekg(0, std::fstream::beg); uint32_t begPos = (uint32_t)cacheFile.tellg(); uint32_t size = eofPos - begPos; std::unique_ptr<uint8_t> cacheData(new uint8_t[size]); cacheFile.read((char*)cacheData.get(), size); // パース const CacheHeader* header = (CacheHeader*)cacheData.get(); const Shape* shapes = (Shape*)(cacheData.get() + header->offsetToShapes); shapes_.resize(header->shapeNum); memcpy(&shapes_[0], shapes, sizeof(Shape) * header->shapeNum); uint32_t vtxStride = ComputeVertexStride(header->vertexAttrs); vertexBuffer_.Create(cacheData.get() + header->offsetToVertices, vtxStride * header->vertexNum, header->vertexAttrs); indexBuffer_.Create(cacheData.get() + header->offsetToIndeces, sizeof(uint32_t) * header->vertexNum, INDEX_BUFFER_STRIDE_U32); const char* materials = (const char*)(cacheData.get() + header->offsetToMaterial); materials_.resize(header->materialNum); std::unordered_map<std::string, uint32_t> textureMap; for (size_t i = 0; i < (uint32_t)materials_.size(); i++) { const char* m = materials + (256 * i); ZeroMemory(&materials_[i], sizeof(materials_[i])); // テクスチャ検索 if (strlen(m) > 0) { Texture* texture = nullptr; auto iter = textureMap.find(m); if (iter != textureMap.end()) { texture = textures_[iter->second]; } else { texture = new Texture(); snprintf(tempPath, sizeof(tempPath), "%s%s", baseDir, m); texture->LoadFromFile(tempPath); textures_.push_back(texture); uint32_t index = (uint32_t)textures_.size() - 1; textureMap[m] = index; } materials_[i].albedo = texture; } } } else { /** キャッシュがなかったらobjを読み込み **/ tinyobj::attrib_t attrib; std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::material_t> materials; Printf("Loading %s\n", fileName); std::string err; if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, fileName, baseDir, true)) { if (!err.empty()) { Printf(err.c_str()); } Printf("Failed to load/parse .obj.\n"); return; } //Printf("# of vertices : %d\n", (attrib.vertices.size() / 3)); //Printf("# of normals : %d\n", (attrib.normals.size() / 3)); //Printf("# of texcoords : %d\n", (attrib.texcoords.size() / 2)); //Printf("# of shapes : %d\n", shapes.size()); //Printf("# of materials : %d\n", materials.size()); // 現状はすべてのシェイプで頂点構造が一致している前提で処理しているため1つの頂点バッファにすべて入っている // TODO:tangent, bitangent計算 uint32_t vtxAttrs = VERTEX_ATTR_FLAG_POSITION; vtxAttrs |= (attrib.normals.size() > 0) ? VERTEX_ATTR_FLAG_NORMAL : 0; vtxAttrs |= (attrib.texcoords.size() > 0) ? VERTEX_ATTR_FLAG_TEXCOORD0 : 0; uint32_t vtxStride = ComputeVertexStride(vtxAttrs); // 全インデックス数を計算 uint32_t totalIndexNum = 0; for (auto& shape : shapes) { totalIndexNum += static_cast<uint32_t>(shape.mesh.indices.size()); } // 頂点をインデックス展開するためトータルインデックス数分の頂点バッファを確保 std::unique_ptr<uint8_t> vertexData(new uint8_t[vtxStride * totalIndexNum]); std::unique_ptr<uint8_t> indexData(new uint8_t[sizeof(uint32_t) * totalIndexNum]); uint32_t currentIndex = 0; uint32_t* currentIndexBufferPtr = reinterpret_cast<uint32_t*>(indexData.get()); for (uint32_t i = 0; i < shapes.size(); i++) { auto& shape = shapes[i]; Assert(shape.mesh.num_face_vertices.size() == shape.mesh.material_ids.size()); // For each face uint32_t currentMaterial = 0xffffffff; Shape currentShape; for (size_t f = 0; f < shape.mesh.num_face_vertices.size(); f++) { Assert(shape.mesh.num_face_vertices[f] == 3); // 三角形化済みのはず // マテリアルの切り替わり判定 if (currentMaterial != shape.mesh.material_ids[f]) { if (currentMaterial != 0xffffffff) { currentShape.indexCount = currentIndex - currentShape.indexStart; shapes_.push_back(currentShape); } currentMaterial = shape.mesh.material_ids[f]; currentShape.materialIndex = currentMaterial; currentShape.indexStart = currentIndex; currentShape.indexCount = 0; } // For each vertex in the face uint32_t ptrOffset = 0; uint8_t* currentVertexBufferPtr = vertexData.get() + (vtxStride * currentIndex); for (size_t v = 0; v < 3; v++) { tinyobj::index_t idx = shape.mesh.indices[(f * 3) + v]; // position memcpy(currentVertexBufferPtr + ptrOffset, &attrib.vertices[idx.vertex_index * 3], 12); ptrOffset += 12; // normal if (vtxAttrs & VERTEX_ATTR_FLAG_NORMAL) { memcpy(currentVertexBufferPtr + ptrOffset, &attrib.normals[idx.normal_index * 3], 12); ptrOffset += 12; } // texcoord if (vtxAttrs & VERTEX_ATTR_FLAG_TEXCOORD0) { float2* uv = reinterpret_cast<float2*>(currentVertexBufferPtr + ptrOffset); uv->x = attrib.texcoords[idx.texcoord_index * 2 + 0]; uv->y = 1.0f - attrib.texcoords[idx.texcoord_index * 2 + 1]; // OpenGL -> DirectX ptrOffset += 8; } currentIndexBufferPtr[currentIndex] = currentIndex; currentIndex++; } } // 最後のマテリアル分追加 currentShape.indexCount = currentIndex - currentShape.indexStart; shapes_.push_back(currentShape); } vertexBuffer_.Create(vertexData.get(), vtxStride * totalIndexNum, vtxAttrs); indexBuffer_.Create(indexData.get(), sizeof(uint32_t) * totalIndexNum, INDEX_BUFFER_STRIDE_U32); // マテリアル materials_.resize(materials.size()); std::unordered_map<std::string, uint32_t> textureMap; for (size_t i = 0; i < (uint32_t)materials_.size(); i++) { auto& m = materials[i]; ZeroMemory(&materials_[i], sizeof(materials_[i])); // テクスチャ検索 if (m.diffuse_texname.size() > 0) { Texture* texture = nullptr; auto iter = textureMap.find(m.diffuse_texname); if (iter != textureMap.end()) { texture = textures_[iter->second]; } else { texture = new Texture(); snprintf(tempPath, sizeof(tempPath), "%s%s", baseDir, m.diffuse_texname.c_str()); texture->LoadFromFile(tempPath); textures_.push_back(texture); uint32_t index = (uint32_t)textures_.size() - 1; textureMap[m.diffuse_texname] = index; } materials_[i].albedo = texture; } } // 読み込み高速化のためのキャッシュデータを生成 { snprintf(tempPath, sizeof(tempPath), "%s%s.cache", baseDir, fileNameWoExt); std::ofstream file(tempPath, std::ios::out | std::ios::binary); CacheHeader header; header.shapeNum = (uint16_t)shapes_.size(); header.materialNum = (uint16_t)materials_.size(); header.vertexAttrs = (uint16_t)vtxAttrs; header.vertexNum = totalIndexNum; header.offsetToShapes = sizeof(CacheHeader); header.offsetToVertices = header.offsetToShapes + sizeof(Shape) * header.shapeNum; header.offsetToIndeces = header.offsetToVertices + (vtxStride * totalIndexNum); header.offsetToMaterial = header.offsetToIndeces + (sizeof(uint32_t) * totalIndexNum); file.write((char*)&header, sizeof(header)); // シェイプ for (auto& s : shapes_) { file.write((char*)&s, sizeof(s)); } // 頂点 file.write((char*)vertexData.get(), vtxStride * totalIndexNum); // インデックス file.write((char*)indexData.get(), sizeof(uint32_t) * totalIndexNum); // マテリアル for (auto& m : materials) { FillMemory(tempPath, sizeof(tempPath), 0); snprintf(tempPath, sizeof(tempPath), "%s", m.diffuse_texname.c_str()); file.write(tempPath, sizeof(tempPath)); } } } }