void fgOglRender( vector<FgOglRendModel> rms, FgMat44F oglMvm, // MVM in column-major layout. FgVect6D frustum, const Fg3dRenderOptions & rend, FgValid<uint> bgImgName, FgVect2UI bgImgDims) { CHECKOGLERROR; glClearColor(rend.backgroundColor[0],rend.backgroundColor[1],rend.backgroundColor[2],1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (bgImgName.valid()) renderBgImg(bgImgName.val(),bgImgDims,false); if (rend.twoSided) glDisable(GL_CULL_FACE); // The OGL default else { glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(frustum[0],frustum[1],frustum[2],frustum[3],frustum[4],frustum[5]); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLoadMatrixf(oglMvm.dataPtr()); // Using offsets creates cracks in facet rendering so only use when necessary: bool useOffsets = (rend.wireframe || rend.markedVerts || rend.surfPoints); glEnable(GL_LIGHTING); if (rend.facets) { if (useOffsets) glPolygonOffset(1.0,1.0); // Move the surface behind the wireframe. rendSurfaces(rms,rend,false); // Opaque pass if (useOffsets) glPolygonOffset(0.0,0.0); } if (rend.wireframe) { glPolygonOffset(1.0,1.0); drawWires(rms); glPolygonOffset(0.0,0.0); } if (rend.allVerts) drawVerts(rms); if (rend.markedVerts) drawMarkedVerts(rms); if (rend.surfPoints) drawPoints(rms); if (rend.facets) { if (useOffsets) glPolygonOffset(1.0,1.0); rendSurfaces(rms,rend,true); // Transparent pass if (useOffsets) glPolygonOffset(0.0,0.0); } if (bgImgName.valid()) renderBgImg(bgImgName.val(),bgImgDims,true); CHECKOGLERROR; }
static FgOpt<MeshesSurfPoint> intersect( FgVect2UI winSize, FgVect2I pos, FgMat44F toOics, // Transforms frustum to [-1,1] cube (depth & y inverted) const vector<Fg3dMesh> & meshes, const vector<FgVerts> & vertss) { MeshesSurfPoint ret; FgValid<float> minDepth; FgVect2D pnt(pos); FgMat32F oics(-1,1,1,-1,0,1); FgMat32F rcs(-0.5f,winSize[0]-0.5f,-0.5f,winSize[1]-0.5f,0,1); FgAffineCw3F oicsToRcs(oics,rcs); FgMat44F invXform = oicsToRcs.asAffine().asHomogenous() * toOics; for (size_t mm=0; mm<meshes.size(); ++mm) { const Fg3dMesh & mesh = meshes[mm]; const FgVerts & verts = vertss[mm]; FgVerts pvs(verts.size()); for (size_t ii=0; ii<pvs.size(); ++ii) { FgVect4F v = invXform * fgAsHomogVec(verts[ii]); pvs[ii] = v.subMatrix<3,1>(0,0) / v[3]; } for (size_t ss=0; ss<mesh.surfaces.size(); ++ss) { const Fg3dSurface & surf = mesh.surfaces[ss]; for (size_t tt=0; tt<surf.numTriEquivs(); ++tt) { FgVect3UI tri = surf.getTriEquiv(uint(tt)); FgVect3F t0 = pvs[tri[0]], t1 = pvs[tri[1]], t2 = pvs[tri[2]]; FgVect2D v0 = FgVect2D(t0.subMatrix<2,1>(0,0)), v1 = FgVect2D(t1.subMatrix<2,1>(0,0)), v2 = FgVect2D(t2.subMatrix<2,1>(0,0)); if (fgPointInTriangle(pnt,v0,v1,v2) == -1) { // CC winding FgOpt<FgVect3D> vbc = fgBarycentricCoords(pnt,v0,v1,v2); if (vbc.valid()) { FgVect3D bc = vbc.val(); // Depth value range for unclipped polys is [-1,1]. These correspond to the // negative inverse depth values of the frustum. // Only an approximation to the depth value but who cares: double dep = fgDot(bc,FgVect3D(t0[2],t1[2],t2[2])); if (!minDepth.valid() || (dep < minDepth.val())) { // OGL prj inverts depth minDepth = dep; ret.meshIdx = mm; ret.surfIdx = ss; ret.surfPnt.triEquivIdx = uint(tt); ret.surfPnt.weights = FgVect3F(bc); } } } } } } if (minDepth.valid()) return FgOpt<MeshesSurfPoint>(ret); return FgOpt<MeshesSurfPoint>(); }
void Fg3dMesh::addDeltaMorph(const FgMorph & morph) { FgValid<size_t> idx = findDeltaMorph(morph.name); if (idx.valid()) { fgout << fgnl << "WARNING: Overwriting existing morph " + morph.name.as_ascii(); deltaMorphs[idx.val()] = morph; } else deltaMorphs.push_back(morph); }
void Fg3dMesh::addTargMorph(const FgIndexedMorph & morph) { FGASSERT(fgMax(morph.baseInds) < verts.size()); FgValid<size_t> idx = findTargMorph(morph.name); if (idx.valid()) { fgout << fgnl << "WARNING: Overwriting existing morph " + morph.name.as_ascii(); targetMorphs[idx.val()] = morph; } else targetMorphs.push_back(morph); }
static void drawSurfaces( const Fg3dMesh & mesh, const FgVerts & verts, const Fg3dNormals & norms, const vector<FgOglSurf> & images, const Fg3dRenderOptions & rend, bool transparency) // Opaque or transparent pass ? { FGASSERT(mesh.surfaces.size() == images.size()); // Get the modelview matrix, remove the translational component, // and adjust it so that it converts the result from OICS to OXCS // for sphere mapping. FgMat44F mvm,prj; glGetFloatv(GL_MODELVIEW_MATRIX,&mvm[0]); glGetFloatv(GL_PROJECTION_MATRIX,&prj[0]); mvm = mvm.transpose(); prj = prj.transpose() * mvm; FgAffine3F trans(mvm.subMatrix<3,3>(0,0)); //FgVectF2 bnds(numeric_limits<float>::max(),numeric_limits<float>::min()); //for (size_t ii=0; ii<verts.size(); ++ii) { // FgVect4F v = prj * fgAsHomogVec(verts[ii]); // float d = v[2] / v[3]; // fgSetIfLess(bnds[0],d); // fgSetIfGreater(bnds[1],d); } //FG_HI1(bnds); FgAffine3F oicsToOxcs(FgVect3F(1.0f)); oicsToOxcs.postScale(0.5f); trans = oicsToOxcs * trans; for (uint ss=0; ss<mesh.surfaces.size(); ++ss) { if (!images[ss].visible) continue; if (images[ss].transparency != transparency) continue; FgValid<uint> texName; if (rend.useTexture && (ss < images.size()) && (images[ss].valid())) texName = images[ss].name.val(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); glEnable(GL_LIGHTING); const Fg3dSurface & surf = mesh.surfaces[ss]; bool doTex = (texName.valid() && (surf.hasUvIndices())); if (doTex) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,GLuint(texName.val())); // If texture is on, we use two-pass rendering for true spectral and // we also use the per-object spectral surface properties. If texture // mode is off, all objects are rendered the same and in a single pass. GLfloat white[] = {1.0f, 1.0f, 1.0f, 1.0f}, black[] = {0.0f, 0.0f, 0.0f, 1.0f}; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,white); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,white); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,black); } else { glDisable(GL_TEXTURE_2D); GLfloat grey[] = {0.8f, 0.8f, 0.8f, 1.0f}, black[] = {0.0f, 0.0f, 0.0f, 1.0f}, *clr = grey; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,clr); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,clr); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,black); } // More bins slows things down without helping since depth sort is only approximate anyway: const size_t numBins = 10000; FgAffine1F depToBin(FgVectF2(1,-1),FgVectF2(0,numBins)); vector<vector<Tri> > tris(numBins); for (uint ii=0; ii<surf.numTris(); ii++) { Tri tri; FgVect3UI triInds = surf.getTri(ii); for (uint kk=0; kk<3; ++kk) tri.v[kk] = verts[triInds[kk]]; if (rend.flatShaded) for (uint kk=0; kk<3; ++kk) tri.n[kk] = norms.facet[ss].tri[ii]; else for (uint kk=0; kk<3; ++kk) tri.n[kk] = norms.vert[triInds[kk]]; if (doTex) { FgVect3UI texInds = surf.tris.uvInds[ii]; for (uint kk=0; kk<3; ++kk) tri.u[kk] = mesh.uvs[texInds[kk]]; } insertTri(tris,tri,prj,depToBin); } // Surface rasterization is done purely with triangles since some OGL drivers // can't handle quads: for (uint ii=0; ii<surf.numQuads(); ii++) { Tri tri0,tri1; FgVect4UI quadInds = surf.getQuad(ii); for (uint kk=0; kk<3; ++kk) { tri0.v[kk] = verts[quadInds[kk]]; tri1.v[kk] = verts[quadInds[(kk+2)%4]]; } if (rend.flatShaded) { for (uint kk=0; kk<3; ++kk) { tri0.n[kk] = norms.facet[ss].quad[ii]; tri1.n[kk] = norms.facet[ss].quad[ii]; } } else { for (uint kk=0; kk<3; ++kk) { tri0.n[kk] = norms.vert[quadInds[kk]]; tri1.n[kk] = norms.vert[quadInds[(kk+2)%4]]; } } if (doTex) { FgVect4UI texInds = surf.quads.uvInds[ii]; for (uint kk=0; kk<3; ++kk) { tri0.u[kk] = mesh.uvs[texInds[kk]]; tri1.u[kk] = mesh.uvs[texInds[(kk+2)%4]]; } } insertTri(tris,tri0,prj,depToBin); insertTri(tris,tri1,prj,depToBin); } glShadeModel(GL_SMOOTH); drawTris(tris); // Specular pass: if (rend.shiny) { for (size_t ii=0; ii<tris.size(); ++ii) { vector<Tri> & trs = tris[ii]; for (size_t jj=0; jj<trs.size(); ++jj) { Tri & t = trs[jj]; for (uint kk=0; kk<3; ++kk) { FgVect3F tt = trans * t.n[kk]; t.u[kk] = FgVect2F(tt[0],tt[1]); } } } // No need to write depth buffer twice and we don't want it written in the // case of alpha textures: glDepthMask(0); glBlendFunc(GL_ONE,GL_ONE); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,s_specMapName); glColor3f(1.0f,1.0f,1.0f); glDisable(GL_LIGHTING); drawTris(tris); glDepthMask(1); // Restore state } glDisable(GL_BLEND); } }