Ogre SkyBox构建、渲染

来源:互联网 发布:测脸型的软件 编辑:程序博客网 时间:2024/05/16 08:39

1. SkyBox的构建过程

OgreSceneManager.cpp

/** Enables / disables a 'sky box' i.e. a 6-sided box at constant            distance from the camera representing the sky.            @remarks                You could create a sky box yourself using the standard mesh and                entity methods, but this creates a plane which the camera can                never get closer or further away from - it moves with the camera.                (NB you could create this effect by creating a world box which                was attached to the same SceneNode as the Camera too, but this                would only apply to a single camera whereas this skybox applies                to any camera using this scene manager).            @par                The material you use for the skybox can either contain layers                which are single textures, or they can be cubic textures, i.e.                made up of 6 images, one for each plane of the cube. See the                TextureUnitState class for more information.            @param                enable True to enable the skybox, false to disable it            @param                materialName The name of the material the box will use            @param                distance Distance in world coorinates from the camera to                each plane of the box. The default is normally OK.            @param                drawFirst If true, the box is drawn before all other                geometry in the scene, without updating the depth buffer.                This is the safest rendering method since all other objects                will always appear in front of the sky. However this is not                the most efficient way if most of the sky is often occluded                by other objects. If this is the case, you can set this                parameter to false meaning it draws <em>after</em> all other                geometry which can be an optimisation - however you must                ensure that the distance value is large enough that no                objects will 'poke through' the sky box when it is rendered.            @param                orientation Optional parameter to specify the orientation                of the box. By default the 'top' of the box is deemed to be                in the +y direction, and the 'front' at the -z direction.                You can use this parameter to rotate the sky if you want.            @param groupName                The name of the resource group to which to assign the plane mesh.        */void SceneManager::setSkyBox(                             bool enable,                             const String& materialName,                             Real distance,                             bool drawFirst,                             const Quaternion& orientation,                             const String& groupName){_setSkyBox(enable, materialName, distance, static_cast<uint8>(drawFirst?RENDER_QUEUE_SKIES_EARLY: RENDER_QUEUE_SKIES_LATE), orientation, groupName);}

SkyBox实际实现代码:

//-----------------------------------------------------------------------void SceneManager::_setSkyBox(                             bool enable,                             const String& materialName,                             Real distance,                             uint8 renderQueue,                             const Quaternion& orientation,                             const String& groupName){ // 是否启用SkyBox if (enable)    {        MaterialPtr m = MaterialManager::getSingleton().getByName(materialName, groupName);        if (m.isNull())        {            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,                 "Sky box material '" + materialName + "' not found.",                "SceneManager::setSkyBox");        }        // Ensure loaded        m->load();        if (!m->getBestTechnique() ||             !m->getBestTechnique()->getNumPasses())        {        // 材质没有Technique或是获取Pass个数为零,使用默认设置的材质        LogManager::getSingleton().logMessage(                "Warning, skybox material " + materialName + " is not supported, defaulting.");            m = MaterialManager::getSingleton().getDefaultSettings();        }    // 确定纹理单元的类型是普通纹理还是3D纹理        bool t3d = false;        Pass* pass = m->getBestTechnique()->getPass(0);        if (pass->getNumTextureUnitStates() > 0 && pass->getTextureUnitState(0)->is3D())            t3d = true;        // 设置SkyBox的渲染顺序        mSkyBoxRenderQueue = renderQueue;        // Create node         if (!mSkyBoxNode)        {              // 创建SkyBox挂载的SceneNode节点              // SkyBoxNode不挂载在场景树的任何节点上,而是在SceneManager::_queueSkiesForRendering(Camera *cam),               // 设置SkyBoxNode的坐标为Camera的坐标,保证Camera与SkyBoxNode的坐标一致                          mSkyBoxNode = createSceneNode("SkyBoxNode");        }        // Create object        if (!mSkyBoxObj)        {      // 创建SkyBox对象,设置不投影,将对象挂载到SkyBox上      mSkyBoxObj = OGRE_NEW ManualObject("SkyBox");            mSkyBoxObj->setCastShadows(false);            mSkyBoxNode->attachObject(mSkyBoxObj);        }        else        {      // 若已存在SkyBox对象,清除原对象的内容      if (!mSkyBoxObj->isAttached())            {                mSkyBoxNode->attachObject(mSkyBoxObj);            }            mSkyBoxObj->clear();        }            // 设置SkyBox的渲染队列组        mSkyBoxObj->setRenderQueueGroup(mSkyBoxRenderQueue);        if (t3d)        {        // 纹理单元是否为3D图片?        mSkyBoxObj->begin(materialName);        }        MaterialManager& matMgr = MaterialManager::getSingleton();        // Set up the box (6 planes)        for (uint16 i = 0; i < 6; ++i)        {            Plane plane;            String meshName;            Vector3 middle;            Vector3 up, right;            switch(i)            {            case BP_FRONT:                middle = Vector3(0, 0, -distance);                up = Vector3::UNIT_Y * distance;                right = Vector3::UNIT_X * distance;                break;            case BP_BACK:                middle = Vector3(0, 0, distance);                up = Vector3::UNIT_Y * distance;                right = Vector3::NEGATIVE_UNIT_X * distance;                break;            case BP_LEFT:                middle = Vector3(-distance, 0, 0);                up = Vector3::UNIT_Y * distance;                right = Vector3::NEGATIVE_UNIT_Z * distance;                break;            case BP_RIGHT:                middle = Vector3(distance, 0, 0);                up = Vector3::UNIT_Y * distance;                right = Vector3::UNIT_Z * distance;                break;            case BP_UP:                middle = Vector3(0, distance, 0);                up = Vector3::UNIT_Z * distance;                right = Vector3::UNIT_X * distance;                break;            case BP_DOWN:                middle = Vector3(0, -distance, 0);                up = Vector3::NEGATIVE_UNIT_Z * distance;                right = Vector3::UNIT_X * distance;                break;            }            // Modify by orientation            middle = orientation * middle;            up = orientation * up;            right = orientation * right;                        if (t3d)            {                // 3D cubic texture                 // Note UVs mirrored front/back                // I could save a few vertices here by sharing the corners                // since 3D coords will function correctly but it's really not worth                // making the code more complicated for the sake of 16 verts                // top left                Vector3 pos;                pos = middle + up - right;                mSkyBoxObj->position(pos);                mSkyBoxObj->textureCoord(pos.normalisedCopy() * Vector3(1,1,-1));                // bottom left                pos = middle - up - right;                mSkyBoxObj->position(pos);                mSkyBoxObj->textureCoord(pos.normalisedCopy() * Vector3(1,1,-1));                // bottom right                pos = middle - up + right;                mSkyBoxObj->position(pos);                mSkyBoxObj->textureCoord(pos.normalisedCopy() * Vector3(1,1,-1));                // top right                pos = middle + up + right;                mSkyBoxObj->position(pos);                mSkyBoxObj->textureCoord(pos.normalisedCopy() * Vector3(1,1,-1));                uint16 base = i * 4;                                       // 根据六个面上的点构建每个面,并获取纹理UV坐标,构建各个面        mSkyBoxObj->quad(base, base+1, base+2, base+3);            }            else // !t3d            {                // If we're using 6 separate images, have to create 6 materials, one for each frame                // Used to use combined material but now we're using queue we can't split to change frame                // This doesn't use much memory because textures aren't duplicated                String matName = mName + "SkyBoxPlane" + StringConverter::toString(i);                MaterialPtr boxMat = matMgr.getByName(matName, groupName);                if (boxMat.isNull())                {                    // Create new by clone                    boxMat = m->clone(matName);                    boxMat->load();                }                else                {                    // Copy over existing                    m->copyDetailsTo(boxMat);                    boxMat->load();                }                // Make sure the material doesn't update the depth buffer        // 天空总是处于其它物体的背后,不需要重写、检查深度值,SkyBox的颜色总是被覆盖的        boxMat->setDepthWriteEnabled(false);                // Set active frame                Material::TechniqueIterator ti = boxMat->getSupportedTechniqueIterator();                while (ti.hasMoreElements())                {                    Technique* tech = ti.getNext();                    if (tech->getPass(0)->getNumTextureUnitStates() > 0)                    {                        TextureUnitState* t = tech->getPass(0)->getTextureUnitState(0);                        // Also clamp texture, don't wrap (otherwise edges can get filtered)                        t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);            /** Changes the active frame in an animated or multi-image texture.            @remarks            An animated texture (or a cubic texture where the images are not combined for 3D use) is made up of            a number of frames. This method sets the active frame.            @note            Applies to both fixed-function and programmable pipeline.            */            t->setCurrentFrame(i);                    }                }                // section per material                mSkyBoxObj->begin(matName, RenderOperation::OT_TRIANGLE_LIST, groupName);                // top left                mSkyBoxObj->position(middle + up - right);                mSkyBoxObj->textureCoord(0,0);                // bottom left                mSkyBoxObj->position(middle - up - right);                mSkyBoxObj->textureCoord(0,1);                // bottom right                mSkyBoxObj->position(middle - up + right);                mSkyBoxObj->textureCoord(1,1);                // top right                mSkyBoxObj->position(middle + up + right);                mSkyBoxObj->textureCoord(1,0);                                mSkyBoxObj->quad(0, 1, 2, 3);                mSkyBoxObj->end();            }        } // for each plane        if (t3d)        {            mSkyBoxObj->end();        }    }    mSkyBoxEnabled = enable;    mSkyBoxGenParameters.skyBoxDistance = distance;}

SkyBox渲染:
也是在OgreSceneManager::_renderScene()中的_renderVisibleObjects()中进行

OgreSceneManager::_renderScene -----> OgreSceneManager::_renderVisibleObjects()  -----> OgreSceneManager::renderVisibleObjectsDefaultSequence() ----->

OgreSceneManager::_renderQueueGroupObjects() -----> OgreSceneManager::renderBasicQueueGroupObjects() /* No shadows, ordinary pass */  -----> OgreSceneManager::renderObjects(pPriorityGrp->getSolidsBasic(), 0m, true, true); -----> OgreQueuedRenderableCollection::acceptVisitor() -----> OgreQueuedRenderableCollection::acceptVisitorGrouped() -----> OgreSceneManager::SceneMgrQueuedRenderableVisitor::visit(Ogre::Renderable *r) ----->

OgreSceneManager::renderSingleObject() -----> D3D9RenderSystem::_render(const RenderOperation &op);


原创粉丝点击