This class represents a reflective object. It
is responsible for setting up and managing diffuse and reflective
Impostor objects that the reflector reflects and refracts. This
includes updating impostors, linking with reflective impostors, and
creating render targets for the impostors. It is also responsible
for setting up refraction parameters for the refraction shader, and
provides functions for binding Cg parameters.
During rendering, an appropriate shader material is applied
depending on the state of the GUI. Shaders include simple billboard
impostor reflection, depth impostor reflection, and non-pinhole
impostor reflection.
#include <GL/glew.h> #include <GL/glut.h> #include "glext.h" #include "scene.h" #include "CG/cgInit.h" #include "reflector.h" using namespace std; /*-------------------------------------------------------------------------- * Constructor: create materials, etc. *--------------------------------------------------------------------------*/ Reflector::Reflector() { reflectorMesh = NULL; //TODO: automate this in loading script GCRMaterial = new Material("GCR", false); SPOCRMaterial = new Material("SPOCR", false); SPOCRefractMaterial = new Material("SPOCRefract", false); PPCRMaterial = new Material("imposterReflections", false); PPCRefractMaterial = new Material("imposterRefractions", false); BBRMaterial = new Material("environmentMappedReflections", false); PhongMaterial = new Material("phongShading", false); RefractionConstrMaterial = new Material("RefractionConstruction", false); lightInterfaceType = ReflectorType; normalsRT = NULL; refractedRaysRT = NULL; clearColor = Vex3(100 / 255.0f, 149 / 255.0f, 237 / 255.0f); reflectorMeshIsMorpher = false; renderSPOCRays = false; RaysN = 0; VertsN = 0; impostorIndex = 0; } /*-------------------------------------------------------------------------- * Release memory *--------------------------------------------------------------------------*/ Reflector::~Reflector() { if(reflectorMesh) delete reflectorMesh; reflectiveImposters.clear(); diffuseImposters.clear(); if(normalsRT) delete normalsRT; if(refractedRaysRT) delete refractedRaysRT; //materials unloaded by material manager } /*-------------------------------------------------------------------------- * Set the reference mesh that will be a reflector *--------------------------------------------------------------------------*/ void Reflector::SetReferenceMesh(TriangleMesh *mesh) { reflectorMesh = mesh; refractionParams.objectScale = reflectorMesh->scaleFactor; if(!strcmp(typeid(*reflectorMesh).name(), "class MorphedMesh")) reflectorMeshIsMorpher = true; } /*-------------------------------------------------------------------------- * Add a diffuse or reflective impostor to this reflectors list of impostors *--------------------------------------------------------------------------*/ void Reflector::AddImposter(ImposterType imposterType, TriangleMesh *mesh) { Imposter *imposter = new Imposter(); imposter->SetReferenceMesh(mesh); imposter->imposterType = imposterType; if(mesh->isReflector) { reflectiveImposters.push_back(imposter); } else { diffuseImposters.push_back(imposter); } } /*-------------------------------------------------------------------------- * Update the diffuse/reflective impostors for this reflector *--------------------------------------------------------------------------*/ void Reflector::UpdateImposters(RenderMode renderMode) { for(unsigned int i = 0; i < diffuseImposters.size(); i++) { if(diffuseImposters[i]->hasMoved) { diffuseImposters[i]->UpdateImposter(reflectorMesh->GetCenter(), renderMode); if(diffuseImposters[i]->refMeshIsMorpher) diffuseImposters[i]->hasMoved = true; else diffuseImposters[i]->hasMoved = false; } } Material *oldMaterial; PhongMaterial->active = true; for(unsigned int i = 0; i < reflectiveImposters.size(); i++) { if(reflectiveImposters[i]->hasMoved) { //disable reflective material oldMaterial = reflectiveImposters[i]->referenceMesh->material; reflectiveImposters[i]->referenceMesh->material = PhongMaterial; reflectiveImposters[i]->UpdateImposter(reflectorMesh->GetCenter(), renderMode); reflectiveImposters[i]->hasMoved = false; reflectiveImposters[i]->referenceMesh->material = oldMaterial; } } } /*-------------------------------------------------------------------------- * Link this reflector with the reflective impostor at specified index *--------------------------------------------------------------------------*/ void Reflector::LinkReflectiveImposterWithReflector(int index, Reflector* reflector) { reflectiveImposters[index]->reflectorMeshLink = reflector; } /*-------------------------------------------------------------------------- * Create the render targets for this reflector. These are used for refraction *--------------------------------------------------------------------------*/ void Reflector::CreateRenderTargets() { normalsRT = new RenderTarget(); normalsRT->currentConfig = RenderTarget::verifiedFBOconfig; normalsRT->currentFBO = RenderTarget::verifiedFBOdata; normalsRT->currentConfig.colorBits = NormalsRTBitsN; normalsRT->currentConfig.colorFormat = NormalsRTFormat; normalsRT->currentConfig.width = RenderTargetResolution; normalsRT->currentConfig.height = RenderTargetResolution; //no multisampling normalsRT->currentConfig.coverageSamples = 0; normalsRT->currentConfig.depthSamples = 0; refractedRaysRT = new RenderTarget(); refractedRaysRT->currentConfig = RenderTarget::verifiedFBOconfig; refractedRaysRT->currentFBO = RenderTarget::verifiedFBOdata; refractedRaysRT->currentConfig.colorBits = RefractedRayRTBitsN; refractedRaysRT->currentConfig.colorFormat = RefractedRayRTFormat; refractedRaysRT->currentConfig.width = RenderTargetResolution; refractedRaysRT->currentConfig.height = RenderTargetResolution; //no multisampling refractedRaysRT->currentConfig.coverageSamples = 0; refractedRaysRT->currentConfig.depthSamples = 0; //check to see if the configurations are valid if(!RenderTarget::CreateFBO(normalsRT->currentConfig, normalsRT->currentFBO)) { cerr << "ERROR: error creating render target!" << endl; } if(!RenderTarget::CreateFBO(refractedRaysRT->currentConfig, refractedRaysRT->currentFBO)) { cerr << "ERROR: error creating render target!" << endl; } //create the render targets for the impostors //these render targets are sampled by the reflector in a reflection shader for(unsigned int i = 0; i < diffuseImposters.size(); i++) { diffuseImposters[i]->CreateRenderTarget(); } for(unsigned int i = 0; i < reflectiveImposters.size(); i++) { reflectiveImposters[i]->CreateRenderTarget(); } } /*-------------------------------------------------------------------------- * Draw all the impostors. For testing only. * Draws their billboarded quad or their visible mesh geometry(if PPC/SPOC) *--------------------------------------------------------------------------*/ void Reflector::RenderImposters(RenderMode renderMode) { for(unsigned int i = 0; i < diffuseImposters.size(); i++) { if(diffuseImposters[i]->imposterMesh) diffuseImposters[i]->imposterMesh->RenderHW(renderMode); else diffuseImposters[i]->RenderHW(renderMode); break; } for(unsigned int i = 0; i < reflectiveImposters.size(); i++) { reflectiveImposters[i]->RenderHW(renderMode); } } /*-------------------------------------------------------------------------- * Update the refraciton maps of this reflector. *--------------------------------------------------------------------------*/ void Reflector::UpdateRefractionMaps(RenderMode renderMode) { //set the current reflector to be used when setting parameters in cgInit scene->currReflector = this; Material *oldMaterial = reflectorMesh->material; //1st pass: render the depth and normals of the back faces reflectorMesh->material = PhongMaterial; reflectorMesh->material->active = true; glCullFace( GL_FRONT ); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, normalsRT->currentConfig.width, normalsRT->currentConfig.height); normalsRT->BeginRender(clearColor, 0); reflectorMesh->RenderHW(renderMode); normalsRT->EndRender(); glPopAttrib(); glCullFace( GL_BACK ); //2nd pass: compute the final refracted ray reflectorMesh->material = RefractionConstrMaterial; reflectorMesh->material->active = true; //set the vertex distances used for thickness glClientActiveTexture(GL_TEXTURE0); glTexCoordPointer(1, GL_FLOAT, 0, reflectorMesh->vertexDistances); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, refractedRaysRT->currentConfig.width, refractedRaysRT->currentConfig.height); refractedRaysRT->BeginRender(clearColor, 0); reflectorMesh->RenderHW(renderMode); refractedRaysRT->EndRender(); glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glPopAttrib(); reflectorMesh->material = oldMaterial; scene->currReflector = 0; } /*-------------------------------------------------------------------------- * Draw the geometry assigned to this reflector *--------------------------------------------------------------------------*/ void Reflector::RenderHW(RenderMode renderMode) { //set the current reflector to be used when setting parameters in cgInit scene->currReflector = this; Material *oldMaterial = reflectorMesh->material; if(lightInterfaceType == ReflectorType) { //get the current type of impostor from the GUI int imposterType = scene->GetImposterTypeFromGUI(0); switch(imposterType) { case imposterTypeBB: reflectorMesh->material = BBRMaterial; break; case imposterTypePPC: reflectorMesh->material = PPCRMaterial; break; case imposterTypeSPOC: reflectorMesh->material = SPOCRMaterial; break; case imposterTypeSPOC2: reflectorMesh->material = SPOCRMaterial; break; case imposterTypeGC: reflectorMesh->material = GCRMaterial; break; default: cout << "Error: No applicable material can be applied!" << endl; break; } } else { //1st and 2nd passes performed during update //3rd pass: finally render the refractor with the PHC or SPOC impostors int imposterType = scene->GetImposterTypeFromGUI(0); switch(imposterType) { case imposterTypeBB: reflectorMesh->material = BBRMaterial; break; case imposterTypePPC: reflectorMesh->material = PPCRefractMaterial; break; case imposterTypeSPOC: reflectorMesh->material = SPOCRefractMaterial; break; case imposterTypeSPOC2: reflectorMesh->material = SPOCRefractMaterial; break; default: cout << "Error: No applicable material can be applied!" << endl; break; } } reflectorMesh->material->active = true; reflectorMesh->RenderHW(renderMode); reflectorMesh->material = oldMaterial; scene->currReflector = 0; } /*-------------------------------------------------------------------------- * Binds the vertices of type VertexType to the cgParam *--------------------------------------------------------------------------*/ void Reflector::CGBindImposterVerts(CGparameter *cgParam, VertexType type, int index, bool diffuse) { switch(type) { case Quad: { static float verts[4 * 3]; int k = 0; if(diffuse) { for(int i = 0; i < 4; i++) { verts[k++] = diffuseImposters[index]->imposterVerts[i].x; verts[k++] = diffuseImposters[index]->imposterVerts[i].y; verts[k++] = diffuseImposters[index]->imposterVerts[i].z; } } else { for(int i = 0; i < 4; i++) { verts[k++] = reflectiveImposters[index]->imposterVerts[i].x; verts[k++] = reflectiveImposters[index]->imposterVerts[i].y; verts[k++] = reflectiveImposters[index]->imposterVerts[i].z; } } cgGLSetParameterArray3f(*cgParam, 0, 0, verts); break; } case BoundingVolume: { static float verts[8 * 3]; int k = 0; if(diffuse) { for(int i = 0; i < 8; i++) { verts[k++] = diffuseImposters[index]->boundingVolume[i].x; verts[k++] = diffuseImposters[index]->boundingVolume[i].y; verts[k++] = diffuseImposters[index]->boundingVolume[i].z; } } else { for(int i = 0; i < 8; i++) { verts[k++] = reflectiveImposters[index]->boundingVolume[i].x; verts[k++] = reflectiveImposters[index]->boundingVolume[i].y; verts[k++] = reflectiveImposters[index]->boundingVolume[i].z; } } cgGLSetParameterArray3f(*cgParam, 0, 0, verts); break; } } } /*-------------------------------------------------------------------------- * Binds a float of type FloatType to the cgParam *--------------------------------------------------------------------------*/ void Reflector::CGBindImposterFloat(CGparameter *cgParam, FloatType type, int index, bool diffuse) { float value = 0; switch(type) { case CamProp_f: { if(diffuse) value = diffuseImposters[index]->view->phc->Getf(); else value = reflectiveImposters[index]->view->phc->Getf(); break; } case NearZ: { if(diffuse) value = diffuseImposters[index]->nearZ; else value = reflectiveImposters[index]->nearZ; break; } case FarZ: { if(diffuse) value = diffuseImposters[index]->farZ; else value = reflectiveImposters[index]->farZ; break; } case IsReflective: { if(!diffuse) { value = 1.0f; } break; } default: break; } cgGLSetParameter1f(*cgParam, value); } /*-------------------------------------------------------------------------- * Binds a vector of type VectorType to the cgParam *--------------------------------------------------------------------------*/ void Reflector::CGBindImposterVector(CGparameter *cgParam, VectorType type, int index, bool diffuse) { Vex3 vector; switch(type) { case Normal: { if(diffuse) vector = diffuseImposters[index]->GetNormal(); else vector = reflectiveImposters[index]->GetNormal(); break; } case Tangent: { if(diffuse) vector = diffuseImposters[index]->GetTangent(); else vector = reflectiveImposters[index]->GetTangent(); break; } case CamProp_C: { if(diffuse) vector = diffuseImposters[index]->view->phc->GetC(); else vector = reflectiveImposters[index]->view->phc->GetC(); break; } case CamProp_a: { if(diffuse) vector = diffuseImposters[index]->view->phc->_a; else vector = reflectiveImposters[index]->view->phc->_a; break; } case CamProp_b: { if(diffuse) vector = diffuseImposters[index]->view->phc->_b; else vector = reflectiveImposters[index]->view->phc->_b; break; } case CamProp_c: { if(diffuse) vector = diffuseImposters[index]->view->phc->_c; else vector = reflectiveImposters[index]->view->phc->_c; break; } default: break; } cgGLSetParameter3f(*cgParam, vector.x, vector.y, vector.z); } /*-------------------------------------------------------------------------- * Binds the near and far points to the cg parameters *--------------------------------------------------------------------------*/ void Reflector::CGBindImposterNearFarP(CGparameter *cgParam1, CGparameter *cgParam2, int index, bool diffuse) { Vex3 nearp, farp; if(diffuse) { nearp = diffuseImposters[index]->nearPoint; farp = diffuseImposters[index]->farPoint; } else { nearp = reflectiveImposters[index]->nearPoint; farp = reflectiveImposters[index]->farPoint; } cgGLSetParameter3f(*cgParam1, nearp.x, nearp.y, nearp.z); cgGLSetParameter3f(*cgParam2, farp.x, farp.y, farp.z); } /*-------------------------------------------------------------------------- * Binds the texture of the render target to the cgParam *--------------------------------------------------------------------------*/ void Reflector::CGBindImposterTex(CGparameter *cgParam, RenderTargetType type, int index, bool diffuse) { switch(type) { case Tex: { if(diffuse) cgGLSetTextureParameter(*cgParam, diffuseImposters[index]->renderTarget->GetTextureID()); else cgGLSetTextureParameter(*cgParam, reflectiveImposters[index]->renderTarget->GetTextureID()); break; } case DepthTex: { if(diffuse) cgGLSetTextureParameter(*cgParam, diffuseImposters[index]->renderTarget->GetDepthTexID()); else cgGLSetTextureParameter(*cgParam, reflectiveImposters[index]->renderTarget->GetDepthTexID()); break; } } } /*-------------------------------------------------------------------------- * Binds a matrix of type MatrixType to the cgParam *--------------------------------------------------------------------------*/ void Reflector::CGBindImposterMatrix(CGparameter* cgParam, MatrixType type, int index, bool diffuse) { double* matrix; switch(type) { case MVP: { if(diffuse) matrix = diffuseImposters[index]->mvp; else matrix = reflectiveImposters[index]->mvp; break; } case InvMVP: { if(diffuse) matrix = diffuseImposters[index]->invMVP; else matrix = reflectiveImposters[index]->invMVP; break; } } cgGLSetMatrixParameterdc(*cgParam, matrix); } /*-------------------------------------------------------------------------- * Updates the impostors if a request is sent from the GUI *--------------------------------------------------------------------------*/ bool Reflector::RequestUpdateIfNeeded(ImposterType *newTypes) { bool ret = false; for (unsigned int i = 0; i < diffuseImposters.size(); i++) { if (diffuseImposters[i]->imposterType != newTypes[0]) { diffuseImposters[i]->imposterType = newTypes[0]; diffuseImposters[i]->hasMoved = true; ret = true; } } for (unsigned int i = 0; i < reflectiveImposters.size(); i++) { if (reflectiveImposters[i]->imposterType != newTypes[0]) { reflectiveImposters[i]->imposterType = newTypes[0]; reflectiveImposters[i]->hasMoved = true; ret = true; } } return ret; } /*-------------------------------------------------------------------------- * Image-space Refraction Params *--------------------------------------------------------------------------*/ //param = float[4] void RefractionParams::GetLocal1(float *param) { // local1 = { 2*f*n, f-n, f+n, <unused> } // f = distance to the OpenGL far plane // n = distance to the OpwnGL near plane float znear = scene->frameBuffer->phc->hither; float zfar = scene->frameBuffer->phc->yon; param[0] = 2 * zfar * znear; param[1] = zfar - znear; param[2] = zfar + znear; param[3] = 0.0f; } //param = float[4] void RefractionParams::GetLocal2(float *param) { // local2 = { n_i/n_t, (n_i/n_t)^2, <unused>, <unused> } // n_i = index of refraction of external material (air) // n_t = index of refraction of internal material param[0] = index_1 / index_2; param[1] = param[0] * param[0]; param[2] = 0.0f; param[3] = 0.0f; } //param = float[4] void RefractionParams::GetLocal3(float *param) { // local3 = { n_t/n_i, (n_t/n_i)^2, objectSize, sqrt( 1 - (n_i/n_t)^2 ) } param[0] = index_1 / index_2; param[1] = param[0] * param[0]; param[2] = objectScale; param[3] = sqrtf( 1 - param[1] ); }
morphedMesh.cpp , morphedMesh.h
This is a simple class that morphs from one mesh to another. It decides whether to use hardware vertex morphing vs. software vertex morphing. If no destination mesh is set, then a destination mesh is computed from the bounding sphere of the source mesh.
#include <GL/glew.h> #include <GL/glut.h> #include "glext.h" #include "morphedMesh.h" #include "scene.h" /*-------------------------------------------------------------------------- * Constructor *--------------------------------------------------------------------------*/ MorphedMesh::MorphedMesh() : TriangleMesh() { dstMeshVerts = 0; dstMeshNormals = 0; srcVerts = 0; srcNormals = 0; hardwareVertexMorph = true; useExistingData = false; dstVertexBuffer = 0; dstNormalBuffer = 0; } /*-------------------------------------------------------------------------- * Destructor: delete vertex and normal buffers *--------------------------------------------------------------------------*/ MorphedMesh::~MorphedMesh() { if(!useExistingData) { if(dstMeshVerts) delete[] dstMeshVerts; if(dstMeshNormals) delete[] dstMeshNormals; } if(!hardwareVertexMorph) { if(srcVerts) delete[] srcVerts; if(srcNormals) delete[] srcNormals; } //vertices and normals deleted by parent } /*-------------------------------------------------------------------------- * LoadDstMesh: Sets the destination mesh on this morphed mesh. * @dst - destination mesh, must contain the same amount of vertices as this * mesh (which will act as the source) * @hwVertexMorphing - whether or not to use hardware vertex morphing * * If the dst mesh is NULL, compute the destination vertices on the bounding * sphere of the source mesh (this). * If this mesh is using a VBO, copy the data into buffer objects *--------------------------------------------------------------------------*/ void MorphedMesh::LoadDstMesh(TriangleMesh *dst, bool hwVertexMorphing) { hardwareVertexMorph = hwVertexMorphing; //if dst, then just use its vertices and normals //else, manually compute the destination vertices on the bounding sphere if(dst) { this->dstMeshVerts = dst->vertices; this->dstMeshNormals = dst->normals; useExistingData = true; } else { ComputeBoundingSphere(); this->dstMeshVerts = new Vex3[this->verticesN]; this->dstMeshNormals = new Vex3[this->verticesN]; float r = 0.0f; Vex3 direction; float newRadius = radius; for(int i = 0; i < verticesN; i++) { direction = vertices[i] - center; r = direction.Length(); dstMeshVerts[i] = vertices[i] + direction.UnitVector() * (newRadius - r); } //compute normals from the dst verts OutputNormals(this->dstMeshNormals, this->dstMeshVerts); } //if no hw vertex morph, copy vertices and normals into src buffers if(!hardwareVertexMorph) { srcVerts = new Vex3[this->verticesN]; srcNormals = new Vex3[this->verticesN]; memcpy(srcVerts, vertices, sizeof(float) * 3 * verticesN); memcpy(srcNormals, normals, sizeof(float) * 3 * verticesN); } //copy data into VBOs if(useVBO) { //------create the vertex buffer--------// glGenBuffersARB(1, &dstVertexBuffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstVertexBuffer); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float) * 3 * verticesN, (float*)this->dstMeshVerts, GL_STATIC_DRAW_ARB); //------create the normal buffer--------// glGenBuffersARB(1, &dstNormalBuffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstNormalBuffer); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float) * 3 * verticesN, (float*)this->dstMeshNormals, GL_STATIC_DRAW_ARB); //unbind the buffer glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } } /*-------------------------------------------------------------------------- * RenderHW: Renders the morphing mesh. Interpolates in software or hardware * @renderMode - type of rendering mode to use (e.g. wireframe, solid) *--------------------------------------------------------------------------*/ void MorphedMesh::RenderHW(RenderMode renderMode) { //if no mesh provided, default to the bounding sphere if(dstMeshVerts == NULL) { LoadDstMesh(NULL, true); } if(hardwareVertexMorph) { if(useVBO) { //enable destination vertices glClientActiveTexture(GL_TEXTURE0); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstVertexBuffer); glTexCoordPointer(3, GL_FLOAT, 0, NULL); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //enable destination normals glClientActiveTexture(GL_TEXTURE1); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstNormalBuffer); glTexCoordPointer(3, GL_FLOAT, 0, NULL); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } else { //enable destination vertices glClientActiveTexture(GL_TEXTURE0); glTexCoordPointer(3, GL_FLOAT, 0, (float*) dstMeshVerts); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //enable destination normals glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(3, GL_FLOAT, 0, (float*) dstMeshNormals); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } } else //no hw vertex blending, manually find the interoplated vertices { float blend = 0.0f; if(scene->cameraPath->PathLength() > 0) blend = (float)scene->cameraPath->PathIndex() / (float)scene->cameraPath->PathLength(); for(int i = 0; i < verticesN; i++) { vertices[i] = srcVerts[i] + (dstMeshVerts[i] - srcVerts[i]) * blend; normals[i] = srcNormals[i] + (dstMeshNormals[i] - srcNormals[i]) * blend; } } TriangleMesh::RenderHW(renderMode); //disable texcoord arrays if(hardwareVertexMorph) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } }