bool Terrain::HeightMapLoad(char* filename, float sx, float sz, float maxy) { //FILE *filePtr; // Point to the current position in the file //BITMAPFILEHEADER bitmapFileHeader; // Structure which stores information about file //BITMAPINFOHEADER bitmapInfoHeader; // Structure which stores information about image int imageSize, index; unsigned char height; // Open the file //filePtr = fopen(filename,"rb"); //if (filePtr == NULL) // return 0; dx = sz; dz = sz; dy = maxy; // Get the width and height (width and length) of the image hminfo.terrainWidth = 145;// bitmapInfoHeader.biWidth; hminfo.terrainHeight = 145;// bitmapInfoHeader.biHeight; // Initialize the heightMap array (stores the vertices of our terrain) hminfo.heightMap = new IntV3[hminfo.terrainWidth * hminfo.terrainHeight]; // We use a greyscale image, so all 3 rgb values are the same, but we only need one for the height // So we use this counter to skip the next two components in the image data (we read R, then skip BG) int k=0; // Read the image data into our heightMap array for(int j=0; j< hminfo.terrainHeight; j++) { for(int i=0; i< hminfo.terrainWidth; i++) { height = rand()%50+1; index = ( hminfo.terrainWidth * (hminfo.terrainHeight - 1 - j)) + i; hminfo.heightMap[index].x = i - (hminfo.terrainWidth - 1)/2; hminfo.heightMap[index].y = height; hminfo.heightMap[index].z = j - (hminfo.terrainHeight - 1)/2; k+=3; } k++; } int cols = hminfo.terrainWidth; int rows = hminfo.terrainHeight; //Create the grid NumVertices = 2 * rows * cols; NumFaces = (rows-1)*(cols-1)*2; v = new struct HeightFieldVertex[NumVertices]; for(DWORD i = 0; i < rows; ++i) { for(DWORD j = 0; j < cols; ++j) { v[i*cols+j].pos.x = hminfo.heightMap[i*cols+j].x * dx; v[i*cols+j].pos.y = (float(hminfo.heightMap[i*cols+j].y)/255.0) * dy; v[i*cols+j].pos.z = hminfo.heightMap[i*cols+j].z * dz; v[i*cols+j].texCoord = D3DXVECTOR2(j, i); } } indices = new DWORD[NumFaces * 3]; k = 0; for(DWORD i = 0; i < rows-1; i++) { for(DWORD j = 0; j < cols-1; j++) { indices[k] = i*cols+j; // Bottom left of quad indices[k+1] = i*cols+j+1; // Bottom right of quad indices[k+2] = (i+1)*cols+j; // Top left of quad indices[k+3] = (i+1)*cols+j; // Top left of quad indices[k+4] = i*cols+j+1; // Bottom right of quad indices[k+5] = (i+1)*cols+j+1; // Top right of quad k += 6; // next quad } } //normals & tangents std::vector<D3DXVECTOR3> tempNormal; //normalized and unnormalized normals D3DXVECTOR3 unnormalized(0.0f, 0.0f, 0.0f); //tangent stuff std::vector<D3DXVECTOR3> tempTangent; D3DXVECTOR3 tangent(0.0f, 0.0f, 0.0f); float tcU1, tcV1, tcU2, tcV2; //Used to get vectors (sides) from the position of the verts float vecX, vecY, vecZ; //Two edges of our triangle D3DXVECTOR3 edge1(0.0f, 0.0f, 0.0f); D3DXVECTOR3 edge2(0.0f, 0.0f, 0.0f); //Compute face normals //And Tangents for(int i = 0; i < NumFaces; ++i) { //Get the vector describing one edge of our triangle (edge 0,2) vecX = v[indices[(i*3)+1]].pos.x - v[indices[(i*3)]].pos.x; vecY = v[indices[(i*3)+1]].pos.y - v[indices[(i*3)]].pos.y; vecZ = v[indices[(i*3)+1]].pos.z - v[indices[(i*3)]].pos.z; edge1 = D3DXVECTOR3(vecX, vecY, vecZ); //Create our first edge //Get the vector describing another edge of our triangle (edge 2,1) vecX = v[indices[(i*3)+2]].pos.x - v[indices[(i*3)]].pos.x; vecY = v[indices[(i*3)+2]].pos.y - v[indices[(i*3)]].pos.y; vecZ = v[indices[(i*3)+2]].pos.z - v[indices[(i*3)]].pos.z; edge2 = D3DXVECTOR3(vecX, vecY, vecZ); //Create our second edge //Cross multiply the two edge vectors to get the un-normalized face normal D3DXVec3Cross(&unnormalized, &edge1, &edge2); tempNormal.push_back(unnormalized); //Find first texture coordinate edge 2d vector tcU1 = v[indices[(i*3)+1]].texCoord.x - v[indices[(i*3)]].texCoord.x; tcV1 = v[indices[(i*3)+1]].texCoord.y - v[indices[(i*3)]].texCoord.y; //Find second texture coordinate edge 2d vector tcU2 = v[indices[(i*3)+2]].texCoord.x - v[indices[(i*3)]].texCoord.x; tcV2 = v[indices[(i*3)+2]].texCoord.y - v[indices[(i*3)]].texCoord.y; //Find tangent using both tex coord edges and position edges tangent.x = (tcV2 * edge1.x - tcV1 * edge2.x) / (tcU1 * tcV2 - tcU2 * tcV1); tangent.y = (tcV2 * edge1.y - tcV1 * edge2.y) / (tcU1 * tcV2 - tcU2 * tcV1); tangent.z = (tcV2 * edge1.z - tcV1 * edge2.z) / (tcU1 * tcV2 - tcU2 * tcV1); tempTangent.push_back(tangent); } //Compute vertex normals (normal Averaging) D3DXVECTOR4 normalSum(0.0f, 0.0f, 0.0f, 0.0f); D3DXVECTOR4 tangentSum(0.0f, 0.0f, 0.0f, 0.0f); int facesUsing = 0; float tX, tY, tZ; //temp axis variables //Go through each vertex for(int i = 0; i < NumVertices; ++i) { //Check which triangles use this vertex for(int j = 0; j < NumFaces; ++j) { if(indices[j*3] == i || indices[(j*3)+1] == i || indices[(j*3)+2] == i) { tX = normalSum.x + tempNormal[j].x; tY = normalSum.y + tempNormal[j].y; tZ = normalSum.z + tempNormal[j].z; normalSum = D3DXVECTOR4(tX, tY, tZ, 0.0f); //If a face is using the vertex, add the unormalized face normal to the normalSum facesUsing++; } } //Get the actual normal by dividing the normalSum by the number of faces sharing the vertex normalSum = normalSum / facesUsing; facesUsing = 0; //Check which triangles use this vertex for(int j = 0; j < NumFaces; ++j) { if(indices[j*3] == i || indices[(j*3)+1] == i || indices[(j*3)+2] == i) { //We can reuse tX, tY, tZ to sum up tangents tX = tangentSum.x + tempTangent[j].x; tY = tangentSum.y + tempTangent[j].y; tZ = tangentSum.z + tempTangent[j].z; tangentSum = D3DXVECTOR4(tX, tY, tZ, 0.0f); //sum up face tangents using this vertex facesUsing++; } } //Get the actual normal by dividing the normalSum by the number of faces sharing the vertex tangentSum = tangentSum / facesUsing; //Normalize the normalSum vector and tangent D3DXVec4Normalize(&normalSum, &normalSum); D3DXVec4Normalize(&tangentSum, &tangentSum); //Store the normal and tangent in our current vertex v[i].normal.x = normalSum.x; v[i].normal.y = normalSum.y; v[i].normal.z = normalSum.z; v[i].tangent.x = tangentSum.x; v[i].tangent.y = tangentSum.y; v[i].tangent.z = tangentSum.z; D3DXVECTOR3 bit; D3DXVec3Cross(&bit, &v[i].normal, &v[i].tangent); v[i].bitangent = -1.0 * bit; //Clear normalSum, tangentSum and facesUsing for next vertex normalSum = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f); tangentSum = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f); facesUsing = 0; } ////terrain AABB //MinX = -1.0 * dx * (hminfo.terrainWidth - 1)/2; //MinY = 0.0; //MinZ = -1.0 * dz * (hminfo.terrainHeight - 1)/2; //MaxX = dx * (hminfo.terrainWidth - 1)/2; //MaxY = dy; //MaxZ = dz * (hminfo.terrainHeight - 1)/2; return true; }
void DrawSmooth::addVBO(unsigned int currentObject) { // Step 1: Create and fill the four arrays (vertex coords, vertex normals, and face indices) // This version: // - each coord/normal will appear one time (one for each corner with unique normal) vector<float> vertices; // (x,y,z) Final size: 3*number of vertices vector<float> normals; // (nx,ny,nz) Final size: 3*number of vertices vector<float> st; // (s,t) Final size: 2*number of vertices vector<float> colors; // (r,g,b) Final size: 3*number of vertices vector<int> indices; // Final size: 3*number of triangles const Object& obj = scene()->objects()[currentObject]; const vector<Face> &faces = obj.faces(); const vector<Vertex> &verts = obj.vertices(); vector<Vector> normalSum(verts.size(), Vector(0, 0, 0)); vector<int> normalCount(verts.size(), 0); for (int i = 0; i < (int)faces.size(); ++i) { const Face &face = faces[i]; const Vector &N = face.normal().normalized(); for (int j = 0; j < face.numVertices(); ++j) { int index = face.vertexIndex(j); ++normalCount[index]; normalSum[index] += N; indices.push_back(index); } } for (int i = 0; i < (int)verts.size(); ++i) { Point P = verts[i].coord(); vertices.push_back(P.x()); vertices.push_back(P.y()); vertices.push_back(P.z()); Vector N = normalSum[i]/normalCount[i]; normals.push_back(N.x()); normals.push_back(N.y()); normals.push_back(N.z()); float r = obj.boundingBox().radius(); float s = Vector::dotProduct((1.0/r)*Vector(1, 0, 1), P); float t = Vector::dotProduct((1.0/r)*Vector(0, 1, 0), P); if (obj.vertices().size() == 81) // plane: special case for /assig models { s = 0.5f*(P.x() + 1.0); t = 0.5f*(P.y() + 1.0); } if (obj.vertices().size() == 386) // cube: special case for /assig models { s = Vector::dotProduct((1.0/2.0)*Vector(1, 0, 1), P); t = Vector::dotProduct((1.0/2.0)*Vector(0, 1, 0), P); } st.push_back(s); st.push_back(t); colors.push_back(abs(N.x())); colors.push_back(abs(N.y())); colors.push_back(abs(N.z())); } // Step 2: Create empty buffers (coords, normals, st, indices) GLuint VAO; glGenVertexArrays(1, &VAO); VAOs.push_back(VAO); glBindVertexArray(VAO); GLuint coordBufferID; glGenBuffers(1, &coordBufferID); coordBuffers.push_back(coordBufferID); GLuint normalBufferID; glGenBuffers(1, &normalBufferID); normalBuffers.push_back(normalBufferID); GLuint colorBufferID; glGenBuffers(1, &colorBufferID); colorBuffers.push_back(colorBufferID); GLuint stBufferID; glGenBuffers(1, &stBufferID); stBuffers.push_back(stBufferID); GLuint indexBufferID; glGenBuffers(1, &indexBufferID); indexBuffers.push_back(indexBufferID); numIndices.push_back(indices.size()); // Step 3: Define VBO data (coords, normals, indices) glBindBuffer(GL_ARRAY_BUFFER, coordBuffers[currentObject]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vertices.size(), &vertices[0], GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // VAO glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, normalBuffers[currentObject]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*normals.size(), &normals[0], GL_STATIC_DRAW); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); // VAO glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[currentObject]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*colors.size(), &colors[0], GL_STATIC_DRAW); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); // VAO glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, stBuffers[currentObject]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*st.size(), &st[0], GL_STATIC_DRAW); glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, 0); // VAO glEnableVertexAttribArray(3); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffers[currentObject]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*indices.size(), &indices[0], GL_STATIC_DRAW); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); }
void Mesh::generateVertexNormals(const float& smoothingAngle) { // calculate the cosine of the angle (in degrees) float cos_angle = cos(smoothingAngle * M_PI / 180.0); // clear any previously cached normals _normals.clear(); int numVerts = _vertices.size()/3; int numFaces = _faceIndices.size()/3; //Here we create a temporary list of face indices for each vertex //That is, a list of lists, where for each vertex, we have a list of //indices of the faces it belongs to std::vector< std::vector<int> > facesPerVertex; std::vector< std::vector<vec3> > faceNormalsPerVertex; for(int i=0; i<numVerts; ++i) { //Create an empty list of face indices std::vector<int> faceList; facesPerVertex.push_back(faceList); //Create an empty list of normals std::vector<vec3> normalList; faceNormalsPerVertex.push_back(normalList); } //First we iterate over all the faces and generate face normals //for each face in our mesh for(int i=0; i<numFaces; ++i) { int vertIndex1 = _faceIndices[3*i]; int vertIndex2 = _faceIndices[3*i+1]; int vertIndex3 = _faceIndices[3*i+2]; //Register that face with index i, is part of the faceLists //for each of the above vertices facesPerVertex[vertIndex1].push_back(i); facesPerVertex[vertIndex2].push_back(i); facesPerVertex[vertIndex3].push_back(i); vec3 faceNormal(_faceNormals[3*i+0], _faceNormals[3*i+1], _faceNormals[3*i+2]); faceNormalsPerVertex[vertIndex1].push_back(faceNormal); faceNormalsPerVertex[vertIndex2].push_back(faceNormal); faceNormalsPerVertex[vertIndex3].push_back(faceNormal); } //Now we have a list of faces per vertex //We also have a list of face normals per vertex //We can now calculate the average normal for(int i=0; i<numVerts; ++i) { std::vector<vec3> normals = faceNormalsPerVertex[i]; vec3 normalSum(0.f, 0.f, 0.f); for(int j=0; j<normals.size(); ++j) { normalSum += normals[j]; } normalSum.normalize(); float* normCoords = normalSum.data(); _normals.push_back(normCoords[0]); _normals.push_back(normCoords[1]); _normals.push_back(normCoords[2]); } }