/////////////////////////////////////////////////////////////////////////////////////////////////// // Calculate the tangent basis for a triangle on the surface of a model // This vector is needed for most normal mapping shaders void m3dCalculateTangentBasis(M3DVector3f vTangent, const M3DVector3f vTriangle[3], const M3DVector2f vTexCoords[3], const M3DVector3f N) { M3DVector3f dv2v1, dv3v1; float dc2c1t, dc2c1b, dc3c1t, dc3c1b; float M; m3dSubtractVectors3(dv2v1, vTriangle[1], vTriangle[0]); m3dSubtractVectors3(dv3v1, vTriangle[2], vTriangle[0]); dc2c1t = vTexCoords[1][0] - vTexCoords[0][0]; dc2c1b = vTexCoords[1][1] - vTexCoords[0][1]; dc3c1t = vTexCoords[2][0] - vTexCoords[0][0]; dc3c1b = vTexCoords[2][1] - vTexCoords[0][1]; M = (dc2c1t * dc3c1b) - (dc3c1t * dc2c1b); M = 1.0f / M; m3dScaleVector3(dv2v1, dc3c1b); m3dScaleVector3(dv3v1, dc2c1b); m3dSubtractVectors3(vTangent, dv2v1, dv3v1); m3dScaleVector3(vTangent, M); // This potentially changes the direction of the vector m3dNormalizeVector3(vTangent); M3DVector3f B; m3dCrossProduct3(B, N, vTangent); m3dCrossProduct3(vTangent, B, N); m3dNormalizeVector3(vTangent); }
///////////////////////////////////////////////////////////////// // Add a triangle to the mesh. This searches the current list for identical // (well, almost identical - these are floats you know...) verts. If one is found, it // is added to the index array. If not, it is added to both the index array and the vertex // array grows by one as well. void GLTriangleBatch::AddTriangle(M3DVector3f verts[3], M3DVector3f vNorms[3], M3DVector2f vTexCoords[3]) { const float e = 0.00001f; // How small a difference to equate // First thing we do is make sure the normals are unit length! // It's almost always a good idea to work with pre-normalized normals m3dNormalizeVector3(vNorms[0]); m3dNormalizeVector3(vNorms[1]); m3dNormalizeVector3(vNorms[2]); // Search for match - triangle consists of three verts for(GLuint iVertex = 0; iVertex < 3; iVertex++) { GLuint iMatch = 0; for(iMatch = 0; iMatch < nNumVerts; iMatch++) { // If the vertex positions are the same if(m3dCloseEnough(pVerts[iMatch][0], verts[iVertex][0], e) && m3dCloseEnough(pVerts[iMatch][1], verts[iVertex][1], e) && m3dCloseEnough(pVerts[iMatch][2], verts[iVertex][2], e) && // AND the Normal is the same... m3dCloseEnough(pNorms[iMatch][0], vNorms[iVertex][0], e) && m3dCloseEnough(pNorms[iMatch][1], vNorms[iVertex][1], e) && m3dCloseEnough(pNorms[iMatch][2], vNorms[iVertex][2], e) && // And Texture is the same... m3dCloseEnough(pTexCoords[iMatch][0], vTexCoords[iVertex][0], e) && m3dCloseEnough(pTexCoords[iMatch][1], vTexCoords[iVertex][1], e)) { // Then add the index only pIndexes[nNumIndexes] = iMatch; nNumIndexes++; break; } } // No match for this vertex, add to end of list if(iMatch == nNumVerts && nNumVerts < nMaxIndexes && nNumIndexes < nMaxIndexes) { memcpy(pVerts[nNumVerts], verts[iVertex], sizeof(M3DVector3f)); memcpy(pNorms[nNumVerts], vNorms[iVertex], sizeof(M3DVector3f)); memcpy(pTexCoords[nNumVerts], vTexCoords[iVertex], sizeof(M3DVector2f)); pIndexes[nNumIndexes] = nNumVerts; nNumIndexes++; nNumVerts++; } } }
void normal(float result[], const float A[], const float B[], const float C[]) { float C_min_B[3], A_min_B[3]; m3dSubtractVectors3(C_min_B, C, B); m3dSubtractVectors3(A_min_B, A, B); m3dCrossProduct3(result, C_min_B, A_min_B); m3dNormalizeVector3(result); }
void draw_icosahedron_smooth(int n_faces, float *vertices, int *faces) { float normal[3]; for(int i = 0; i < n_faces; ++i) { for(int j=0 ; j < 3 ; ++j) { m3dCopyVector3(normal, vertices + 3 * faces[i * 3 + j]); m3dNormalizeVector3(normal); draw_trinagle_face(vertices + 3 * faces[3 * i], vertices + 3 * faces[3 * i + 1], vertices + 3 * faces[3 * i + 2], normal, 0.0f, 1.0f, 0.0f); } } }
//---------------------------------------------------- void TriangleFace(M3DVector3f a, M3DVector3f b, M3DVector3f c) { M3DVector3f normal, bMa, cMa; m3dSubtractVectors3(bMa, b, a); m3dSubtractVectors3(cMa, c, a); m3dCrossProduct3(normal, bMa, cMa); m3dNormalizeVector3(normal); glVertexAttrib3fv(GLT_ATTRIBUTE_NORMAL, normal); glVertex3fv(a); glVertex3fv(b); glVertex3fv(c); }
void MouseMoveEvent(int x, int y) { if (isStartTrackBall) { GLfloat theta; M3DVector3f p1, p2, n; int width = glutGet(GLUT_WINDOW_WIDTH); int height = glutGet(GLUT_WINDOW_HEIGHT); MousePtToSphereVec(p1, mMouseX, mMouseY, width, height); MousePtToSphereVec(p2, x, y, width, height); mMouseX = x; mMouseY = y; m3dNormalizeVector3(p1); m3dNormalizeVector3(p2); theta = acos(m3dDotProduct3(p1, p2)) ; //theta = m3dGetAngleBetweenVectors3(p1, p2); m3dCrossProduct3(n, p1, p2); m3dNormalizeVector3(n); M3DMatrix44f tempRotation; m3dLoadIdentity44(tempRotation); GLfloat dis = m3dGetDistance3(p1, p2); if (dis != 0.0f) { m3dRotationMatrix44(tempRotation, theta, m3dGetVectorX(n), m3dGetVectorY(n), m3dGetVectorZ(n)); } m3dMatrixMultiply44(mRotation, tempRotation, mRotation); glutPostRedisplay(); } }
//---------------------------------------------------- void drawSmoothTriangles(int n_faces, float *vertices, int *faces) { M3DVector3f normal; for (int i = 0; i < n_faces; i++) { glBegin(GL_TRIANGLES); for(int j=0;j<3;++j) { m3dCopyVector3(normal,vertices+3*faces[i*3+j]); m3dNormalizeVector3(normal); glVertexAttrib3fv(GLT_ATTRIBUTE_NORMAL, normal); glVertex3fv(vertices+3*faces[i*3+j]); } glEnd(); } }
void Camerak::moveBackward() { M3DVector3f temp; Vec3 thisMove; cam.GetOrigin(temp); lastPos.fromM3D(temp); cam.GetForwardVector(temp); temp[1] = 0; m3dNormalizeVector3(temp); thisMove.fromM3D(temp); thisMove*= movement_rate; move-=thisMove; }
// Ditto above, but for doubles void m3dGetPlaneEquation(M3DVector4d planeEq, const M3DVector3d p1, const M3DVector3d p2, const M3DVector3d p3) { // Get two vectors... do the cross product M3DVector3d v1, v2; // V1 = p3 - p1 v1[0] = p3[0] - p1[0]; v1[1] = p3[1] - p1[1]; v1[2] = p3[2] - p1[2]; // V2 = P2 - p1 v2[0] = p2[0] - p1[0]; v2[1] = p2[1] - p1[1]; v2[2] = p2[2] - p1[2]; // Unit normal to plane - Not sure which is the best way here m3dCrossProduct3(planeEq, v1, v2); m3dNormalizeVector3(planeEq); // Back substitute to get D planeEq[3] = -(planeEq[0] * p3[0] + planeEq[1] * p3[1] + planeEq[2] * p3[2]); }
// Draw a cylinder. Much like gluCylinder void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks) { float fRadiusStep = (topRadius - baseRadius) / float(numStacks); GLfloat fStepSizeSlice = (3.1415926536f * 2.0f) / float(numSlices); M3DVector3f vVertex[4]; M3DVector3f vNormal[4]; M3DVector2f vTexture[4]; cylinderBatch.BeginMesh(numSlices * numStacks * 6); GLfloat ds = 1.0f / float(numSlices); GLfloat dt = 1.0f / float(numStacks); GLfloat s; GLfloat t; for (int i = 0; i < numStacks; i++) { if(i == 0) t = 0.0f; else t = float(i) * dt; float tNext; if(i == (numStacks - 1)) tNext = 1.0f; else tNext = float(i+1) * dt; float fCurrentRadius = baseRadius + (fRadiusStep * float(i)); float fNextRadius = baseRadius + (fRadiusStep * float(i+1)); float theyta; float theytaNext; float fCurrentZ = float(i) * (fLength / float(numStacks)); float fNextZ = float(i+1) * (fLength / float(numStacks)); float zNormal = 0.0f; if(!m3dCloseEnough(baseRadius - topRadius, 0.0f, 0.00001f)) { // Rise over run... zNormal = (baseRadius - topRadius); } for (int j = 0; j < numSlices; j++) { if(j == 0) s = 0.0f; else s = float(j) * ds; float sNext; if(j == (numSlices -1)) sNext = 1.0f; else sNext = float(j+1) * ds; theyta = fStepSizeSlice * float(j); if(j == (numSlices - 1)) theytaNext = 0.0f; else theytaNext = fStepSizeSlice * (float(j+1)); // Inner First vVertex[1][0] = cos(theyta) * fCurrentRadius; // X vVertex[1][1] = sin(theyta) * fCurrentRadius; // Y vVertex[1][2] = fCurrentZ; // Z vNormal[1][0] = vVertex[1][0]; // Surface Normal, same for everybody vNormal[1][1] = vVertex[1][1]; vNormal[1][2] = zNormal; m3dNormalizeVector3(vNormal[1]); vTexture[1][0] = s; // Texture Coordinates, I have no idea... vTexture[1][1] = t; // Outer First vVertex[0][0] = cos(theyta) * fNextRadius; // X vVertex[0][1] = sin(theyta) * fNextRadius; // Y vVertex[0][2] = fNextZ; // Z if(!m3dCloseEnough(fNextRadius, 0.0f, 0.00001f)) { vNormal[0][0] = vVertex[0][0]; // Surface Normal, same for everybody vNormal[0][1] = vVertex[0][1]; // For cones, tip is tricky vNormal[0][2] = zNormal; m3dNormalizeVector3(vNormal[0]); } else memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); vTexture[0][0] = s; // Texture Coordinates, I have no idea... vTexture[0][1] = tNext; // Inner second vVertex[3][0] = cos(theytaNext) * fCurrentRadius; // X vVertex[3][1] = sin(theytaNext) * fCurrentRadius; // Y vVertex[3][2] = fCurrentZ; // Z vNormal[3][0] = vVertex[3][0]; // Surface Normal, same for everybody vNormal[3][1] = vVertex[3][1]; vNormal[3][2] = zNormal; m3dNormalizeVector3(vNormal[3]); vTexture[3][0] = sNext; // Texture Coordinates, I have no idea... vTexture[3][1] = t; // Outer second vVertex[2][0] = cos(theytaNext) * fNextRadius; // X vVertex[2][1] = sin(theytaNext) * fNextRadius; // Y vVertex[2][2] = fNextZ; // Z if(!m3dCloseEnough(fNextRadius, 0.0f, 0.00001f)) { vNormal[2][0] = vVertex[2][0]; // Surface Normal, same for everybody vNormal[2][1] = vVertex[2][1]; vNormal[2][2] = zNormal; m3dNormalizeVector3(vNormal[2]); } else memcpy(vNormal[2], vNormal[3], sizeof(M3DVector3f)); vTexture[2][0] = sNext; // Texture Coordinates, I have no idea... vTexture[2][1] = tNext; cylinderBatch.AddTriangle(vVertex, vNormal, vTexture); // Rearrange for next triangle memcpy(vVertex[0], vVertex[1], sizeof(M3DVector3f)); memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); memcpy(vTexture[0], vTexture[1], sizeof(M3DVector2f)); memcpy(vVertex[1], vVertex[3], sizeof(M3DVector3f)); memcpy(vNormal[1], vNormal[3], sizeof(M3DVector3f)); memcpy(vTexture[1], vTexture[3], sizeof(M3DVector2f)); cylinderBatch.AddTriangle(vVertex, vNormal, vTexture); } } cylinderBatch.End(); }
// Draw a torus (doughnut) at z = fZVal... torus is in xy plane void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor) { double majorStep = 2.0f*M3D_PI / numMajor; double minorStep = 2.0f*M3D_PI / numMinor; int i, j; torusBatch.BeginMesh(numMajor * (numMinor+1) * 6); for (i=0; i<numMajor; ++i) { double a0 = i * majorStep; double a1 = a0 + majorStep; GLfloat x0 = (GLfloat) cos(a0); GLfloat y0 = (GLfloat) sin(a0); GLfloat x1 = (GLfloat) cos(a1); GLfloat y1 = (GLfloat) sin(a1); M3DVector3f vVertex[4]; M3DVector3f vNormal[4]; M3DVector2f vTexture[4]; for (j=0; j<=numMinor; ++j) { double b = j * minorStep; GLfloat c = (GLfloat) cos(b); GLfloat r = minorRadius * c + majorRadius; GLfloat z = minorRadius * (GLfloat) sin(b); // First point vTexture[0][0] = (float)(i)/(float)(numMajor); vTexture[0][1] = (float)(j)/(float)(numMinor); vNormal[0][0] = x0*c; vNormal[0][1] = y0*c; vNormal[0][2] = z/minorRadius; m3dNormalizeVector3(vNormal[0]); vVertex[0][0] = x0 * r; vVertex[0][1] = y0 * r; vVertex[0][2] = z; // Second point vTexture[1][0] = (float)(i+1)/(float)(numMajor); vTexture[1][1] = (float)(j)/(float)(numMinor); vNormal[1][0] = x1*c; vNormal[1][1] = y1*c; vNormal[1][2] = z/minorRadius; m3dNormalizeVector3(vNormal[1]); vVertex[1][0] = x1*r; vVertex[1][1] = y1*r; vVertex[1][2] = z; // Next one over b = (j+1) * minorStep; c = (GLfloat) cos(b); r = minorRadius * c + majorRadius; z = minorRadius * (GLfloat) sin(b); // Third (based on first) vTexture[2][0] = (float)(i)/(float)(numMajor); vTexture[2][1] = (float)(j+1)/(float)(numMinor); vNormal[2][0] = x0*c; vNormal[2][1] = y0*c; vNormal[2][2] = z/minorRadius; m3dNormalizeVector3(vNormal[2]); vVertex[2][0] = x0 * r; vVertex[2][1] = y0 * r; vVertex[2][2] = z; // Fourth (based on second) vTexture[3][0] = (float)(i+1)/(float)(numMajor); vTexture[3][1] = (float)(j+1)/(float)(numMinor); vNormal[3][0] = x1*c; vNormal[3][1] = y1*c; vNormal[3][2] = z/minorRadius; m3dNormalizeVector3(vNormal[3]); vVertex[3][0] = x1*r; vVertex[3][1] = y1*r; vVertex[3][2] = z; torusBatch.AddTriangle(vVertex, vNormal, vTexture); // Rearrange for next triangle memcpy(vVertex[0], vVertex[1], sizeof(M3DVector3f)); memcpy(vNormal[0], vNormal[1], sizeof(M3DVector3f)); memcpy(vTexture[0], vTexture[1], sizeof(M3DVector2f)); memcpy(vVertex[1], vVertex[3], sizeof(M3DVector3f)); memcpy(vNormal[1], vNormal[3], sizeof(M3DVector3f)); memcpy(vTexture[1], vTexture[3], sizeof(M3DVector2f)); torusBatch.AddTriangle(vVertex, vNormal, vTexture); } } torusBatch.End(); }
/////////////////////////////////////////////////////////////////////////////// // Render a frame. The owning framework is responsible for buffer swaps, // flushes, etc. void RenderScene(void) { static CStopWatch animationTimer; float yRot = animationTimer.GetElapsedSeconds() * 60.0f; M3DVector3f vCameraPos; M3DVector3f vCameraForward; M3DVector3f vMirrorPos; M3DVector3f vMirrorForward; cameraFrame.GetOrigin(vCameraPos); cameraFrame.GetForwardVector(vCameraForward); // Set position of mirror frame (camera) vMirrorPos[0] = 0.0; vMirrorPos[1] = 0.1f; vMirrorPos[2] = -6.0f; // view pos is actually behind mirror mirrorFrame.SetOrigin(vMirrorPos); // Calculate direction of mirror frame (camera) // Because the position of the mirror is known relative to the origin // find the direction vector by adding the mirror offset to the vector // of the viewer-origin vMirrorForward[0] = vCameraPos[0]; vMirrorForward[1] = vCameraPos[1]; vMirrorForward[2] = (vCameraPos[2] + 5); m3dNormalizeVector3(vMirrorForward); mirrorFrame.SetForwardVector(vMirrorForward); // first render from the mirrors perspective glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName); glDrawBuffers(1, fboBuffs); glViewport(0, 0, mirrorTexWidth, mirrorTexHeight); // Draw scene from the perspective of the mirror camera modelViewMatrix.PushMatrix(); M3DMatrix44f mMirrorView; mirrorFrame.GetCameraMatrix(mMirrorView); modelViewMatrix.MultMatrix(mMirrorView); // Flip the mirror camera horizontally for the reflection modelViewMatrix.Scale(-1.0f, 1.0f, 1.0f); glBindTexture(GL_TEXTURE_2D, textures[0]); // Marble glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0); floorBatch.Draw(); DrawWorld(yRot); // Now draw a cylinder representing the viewer M3DVector4f vLightTransformed; modelViewMatrix.GetMatrix(mMirrorView); m3dTransformVector4(vLightTransformed, vLightPos, mMirrorView); modelViewMatrix.Translate(vCameraPos[0],vCameraPos[1]-0.8f,vCameraPos[2]-1.0f); modelViewMatrix.Rotate(-90.0f, 1.0f, 0.0f, 0.0f); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, modelViewMatrix.GetMatrix(), transformPipeline.GetProjectionMatrix(), vLightTransformed, vBlue, 0); cylinderBatch.Draw(); modelViewMatrix.PopMatrix(); // Reset FBO. Draw world again from the real cameras perspective glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffers(1, windowBuff); glViewport(0, 0, screenWidth, screenHeight); modelViewMatrix.PushMatrix(); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); glBindTexture(GL_TEXTURE_2D, textures[0]); // Marble glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0); floorBatch.Draw(); DrawWorld(yRot); // Now draw the mirror surfaces modelViewMatrix.PushMatrix(); modelViewMatrix.Translate(0.0f, -0.4f, -5.0f); if(vCameraPos[2] > -5.0) { glBindTexture(GL_TEXTURE_2D, mirrorTexture); // Reflection shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0); } else { // If the camera is behind the mirror, just draw black shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack); } mirrorBatch.Draw(); shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGrey); mirrorBorderBatch.Draw(); modelViewMatrix.PopMatrix(); modelViewMatrix.PopMatrix(); // Do the buffer Swap glutSwapBuffers(); // Do it again glutPostRedisplay(); }
void Display() { static CStopWatch timer; GLfloat yRot = timer.GetElapsedSeconds() * 60.0; M3DVector3f vCameraPosition; M3DVector3f vCameraForward; M3DVector3f vMirrorPosition; M3DVector3f vMirrorForward; void movingCylinder(); cameraFrame.GetOrigin(vCameraPosition); cameraFrame.GetForwardVector(vCameraForward); vMirrorPosition[0] = 0.0f; vMirrorPosition[1] = 0.1f; vMirrorPosition[2] = -20.0f; mirrorFrame.SetOrigin(vMirrorPosition); vMirrorForward[0] = vCameraPosition[0]; vMirrorForward[1] = vCameraPosition[1]; vMirrorForward[2] = (vCameraPosition[2] + 20); m3dNormalizeVector3(vMirrorForward); mirrorFrame.SetForwardVector(vMirrorForward); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fboName); glDrawBuffers(1,fboBuffers); glViewport(0,0,mirrorWidth,mirrorHeight); modelViewMatrix.PushMatrix(); M3DMatrix44f mMirrorView; mirrorFrame.GetCameraMatrix(mMirrorView); modelViewMatrix.MultMatrix(mMirrorView); modelViewMatrix.Scale(-1.0f,1.0f,1.0f); glBindTexture(GL_TEXTURE_2D,textures[0]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite,0); floorBatch.Draw(); drawSun(); drawTorus(yRot); modelViewMatrix.PopMatrix(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0); glDrawBuffers(1,windowBuffer); glViewport(0,0,mirrorWidth,mirrorHeight); modelViewMatrix.PushMatrix(); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); modelViewMatrix.PushMatrix(); glBindTexture(GL_TEXTURE_2D,mirrorTexture); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(),0); mirrorFrontBatch.Draw(); modelViewMatrix.PopMatrix(); modelViewMatrix.PushMatrix(); glBindTexture(GL_TEXTURE_2D,textures[0]); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite,0); floorBatch.Draw(); drawSun(); drawTorus(yRot); modelViewMatrix.PopMatrix(); modelViewMatrix.PopMatrix(); //control to moving cylinder movingCylinder(); glutSwapBuffers(); glutPostRedisplay(); }