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;
}
Пример #2
0
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>();
}
Пример #3
0
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);
}
Пример #4
0
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);
    }
}