ogre 阴影技术分析记录
来源:互联网 发布:vscode移除文件夹 编辑:程序博客网 时间:2024/06/04 19:20
—-未完,待续
阴影技术,一般分为 基于 shadow volume 的和基于shadow map的。
shadow volume 原理是 通过模型EdgeData 计算阴影空间
shadow map原理是在灯光下,计算出物体在地面的区域,设定好颜色,动态纹理(阴影纹理)的形式叠加到接收阴影的物体上。
过程如下:
在场景管理器渲染开始时,创建阴影纹理。
mSceneMgr->_renderScene中调用
if (isShadowTechniqueInUse()) { // Prepare shadow materials initShadowVolumeMaterials(); }
跟进initShadowVolumeMaterials();
/* This should have been set in the SceneManager constructor, but if you created the SceneManager BEFORE the Root object, you will need to call SceneManager::_setDestinationRenderSystem manually. */ assert( mDestRenderSystem ); if (mShadowMaterialInitDone) return; if (!mShadowDebugPass) { MaterialPtr matDebug = MaterialManager::getSingleton().getByName("Ogre/Debug/ShadowVolumes"); if (matDebug.isNull()) { // Create ,创建阴影的动态纹理 matDebug = MaterialManager::getSingleton().create( "Ogre/Debug/ShadowVolumes", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME); mShadowDebugPass = matDebug->getTechnique(0)->getPass(0); mShadowDebugPass->setSceneBlending(SBT_ADD); //SBT_ADD将纹理值叠加到场景物体上 mShadowDebugPass->setLightingEnabled(false); mShadowDebugPass->setDepthWriteEnabled(false); TextureUnitState* t = mShadowDebugPass->createTextureUnitState(); t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, ColourValue(0.7, 0.0, 0.2)); mShadowDebugPass->setCullingMode(CULL_NONE); if (mDestRenderSystem->getCapabilities()->hasCapability( RSC_VERTEX_PROGRAM)) //渲染系统支持顶点程序的话就进行 阴影计算的程序 { /*阴影gpu程序初始化,(ogre中自带的阴影gpu程序: "Ogre/ShadowExtrudePointLight", "Ogre/ShadowExtrudePointLightDebug", "Ogre/ShadowExtrudeDirLight", "Ogre/ShadowExtrudeDirLightDebug", "Ogre/ShadowExtrudePointLightFinite", "Ogre/ShadowExtrudePointLightFiniteDebug", "Ogre/ShadowExtrudeDirLightFinite", "Ogre/ShadowExtrudeDirLightFiniteDebug")*/ ShadowVolumeExtrudeProgram::initialise(); // Enable the (infinite) point light extruder for now, just to get some params ,点光源的先打开 mShadowDebugPass->setVertexProgram( ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT]); mShadowDebugPass->setFragmentProgram(ShadowVolumeExtrudeProgram::frgProgramName); mInfiniteExtrusionParams = mShadowDebugPass->getVertexProgramParameters(); mInfiniteExtrusionParams->setAutoConstant(0, GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); mInfiniteExtrusionParams->setAutoConstant(4, GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE); // Note ignored extra parameter - for compatibility with finite extrusion vertex program mInfiniteExtrusionParams->setAutoConstant(5, GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE); } matDebug->compile(); } else { mShadowDebugPass = matDebug->getTechnique(0)->getPass(0); if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) { mInfiniteExtrusionParams = mShadowDebugPass->getVertexProgramParameters(); } } }/********模板阴影的设置*******/ if (!mShadowStencilPass) { MaterialPtr matStencil = MaterialManager::getSingleton().getByName( "Ogre/StencilShadowVolumes"); if (matStencil.isNull()) { // Init matStencil = MaterialManager::getSingleton().create( "Ogre/StencilShadowVolumes", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME); mShadowStencilPass = matStencil->getTechnique(0)->getPass(0); if (mDestRenderSystem->getCapabilities()->hasCapability( RSC_VERTEX_PROGRAM)) { // Enable the finite point light extruder for now, just to get some params mShadowStencilPass->setVertexProgram( ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT_FINITE]); mShadowStencilPass->setFragmentProgram(ShadowVolumeExtrudeProgram::frgProgramName); mFiniteExtrusionParams = mShadowStencilPass->getVertexProgramParameters(); mFiniteExtrusionParams->setAutoConstant(0, GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); mFiniteExtrusionParams->setAutoConstant(4, GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE); // Note extra parameter mFiniteExtrusionParams->setAutoConstant(5, GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE); } matStencil->compile(); // Nothing else, we don't use this like a 'real' pass anyway, // it's more of a placeholder } else { mShadowStencilPass = matStencil->getTechnique(0)->getPass(0); if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) { mFiniteExtrusionParams = mShadowStencilPass->getVertexProgramParameters(); } } } if (!mShadowModulativePass) { MaterialPtr matModStencil = MaterialManager::getSingleton().getByName( "Ogre/StencilShadowModulationPass"); if (matModStencil.isNull()) { // Init matModStencil = MaterialManager::getSingleton().create( "Ogre/StencilShadowModulationPass", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME); mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0); mShadowModulativePass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); mShadowModulativePass->setLightingEnabled(false); mShadowModulativePass->setDepthWriteEnabled(false); mShadowModulativePass->setDepthCheckEnabled(false); TextureUnitState* t = mShadowModulativePass->createTextureUnitState(); t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, mShadowColour); mShadowModulativePass->setCullingMode(CULL_NONE); } else { mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0); } } // Also init full screen quad while we're at it if (!mFullScreenQuad) { mFullScreenQuad = OGRE_NEW Rectangle2D(); mFullScreenQuad->setCorners(-1,1,1,-1); } // Also init shadow caster material for texture shadows /************添加投影材质*******************/ if (!mShadowCasterPlainBlackPass) { MaterialPtr matPlainBlack = MaterialManager::getSingleton().getByName( "Ogre/TextureShadowCaster"); if (matPlainBlack.isNull()) { matPlainBlack = MaterialManager::getSingleton().create( "Ogre/TextureShadowCaster", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME); mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0); // Lighting has to be on, because we need shadow coloured objects // Note that because we can't predict vertex programs, we'll have to // bind light values to those, and so we bind White to ambient // reflectance, and we'll set the ambient colour to the shadow colour mShadowCasterPlainBlackPass->setAmbient(ColourValue::White); mShadowCasterPlainBlackPass->setDiffuse(ColourValue::Black); mShadowCasterPlainBlackPass->setSelfIllumination(ColourValue::Black); mShadowCasterPlainBlackPass->setSpecular(ColourValue::Black); // Override fog mShadowCasterPlainBlackPass->setFog(true, FOG_NONE); // no textures or anything else, we will bind vertex programs // every so often though } else { mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0); } }/***************接收阴影材质通道设置******************/ if (!mShadowReceiverPass) { MaterialPtr matShadRec = MaterialManager::getSingleton().getByName( "Ogre/TextureShadowReceiver"); if (matShadRec.isNull()) { matShadRec = MaterialManager::getSingleton().create( "Ogre/TextureShadowReceiver", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME); mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0); // Don't set lighting and blending modes here, depends on additive / modulative TextureUnitState* t = mShadowReceiverPass->createTextureUnitState(); t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); } else { mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0); } } // Set up spot shadow fade texture (loaded from code data block) /*************点光源产生的衰减阴影材质***************/ TexturePtr spotShadowFadeTex = TextureManager::getSingleton().getByName("spot_shadow_fade.png"); if (spotShadowFadeTex.isNull()) { // Load the manual buffer into an image (don't destroy memory! DataStreamPtr stream( OGRE_NEW MemoryDataStream(SPOT_SHADOW_FADE_PNG, SPOT_SHADOW_FADE_PNG_SIZE, false)); Image img; img.load(stream, "png"); spotShadowFadeTex = TextureManager::getSingleton().loadImage( "spot_shadow_fade.png", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, img, TEX_TYPE_2D); } mShadowMaterialInitDone = true;
本步骤之后,阴影材质、顶点及片段程序已经确定创建完成。之后就是计算了
首先灯光中做必要的计算。
mSceneMgr->_renderScene
->findLightsAffectingFrustum(camera);
在其中,有关阴影计算的有:灯光、相机距离。
然后在调用
prepareShadowTextures(camera, vp);进行其他准备
ensureShadowTexturesCreated(); //确保阴影材质已经创建,若没有则创建,创建纹理、纹理对应的相机、材质,并编译,保存 // Set the illumination stage, prevents recursive calls,照明阶段设置,用于控制阴影产生。先将物体渲染到纹理,再渲染物体 IlluminationRenderStage savedStage = mIlluminationStage; mIlluminationStage = IRS_RENDER_TO_TEXTURE; if (lightList == 0) lightList = &mLightsAffectingFrustum; try { // Determine far shadow distance Real shadowDist = mDefaultShadowFarDist; if (!shadowDist) { // need a shadow distance, make one up shadowDist = cam->getNearClipDistance() * 300; } Real shadowOffset = shadowDist * mShadowTextureOffset; // Precalculate fading info Real shadowEnd = shadowDist + shadowOffset; Real fadeStart = shadowEnd * mShadowTextureFadeStart; Real fadeEnd = shadowEnd * mShadowTextureFadeEnd; // Additive lighting should not use fogging, since it will overbrighten; use border clamp if (!isShadowTechniqueAdditive()) { // set fogging to hide the shadow edge mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White, 0, fadeStart, fadeEnd); } else { // disable fogging explicitly mShadowReceiverPass->setFog(true, FOG_NONE); } // Iterate over the lights we've found, max out at the limit of light textures // Note that the light sorting must now place shadow casting lights at the // start of the light list, therefore we do not need to deal with potential // mismatches in the light<->shadow texture list any more //用灯光计算阴影 LightList::const_iterator i, iend; ShadowTextureList::iterator si, siend; ShadowTextureCameraList::iterator ci; iend = lightList->end(); siend = mShadowTextures.end(); ci = mShadowTextureCameras.begin(); mShadowTextureIndexLightList.clear(); size_t shadowTextureIndex = 0; for (i = lightList->begin(), si = mShadowTextures.begin(); i != iend && si != siend; ++i) { Light* light = *i; // skip light if shadows are disabled if (!light->getCastShadows()) continue; if (mShadowTextureCurrentCasterLightList.empty()) mShadowTextureCurrentCasterLightList.push_back(light); else mShadowTextureCurrentCasterLightList[0] = light; // texture iteration per light. size_t textureCountPerLight = mShadowTextureCountPerType[light->getType()]; for (size_t j = 0; j < textureCountPerLight && si != siend; ++j) { TexturePtr &shadowTex = *si; RenderTarget *shadowRTT = shadowTex->getBuffer()->getRenderTarget(); Viewport *shadowView = shadowRTT->getViewport(0); Camera *texCam = *ci; // rebind camera, incase another SM in use which has switched to its cam shadowView->setCamera(texCam); // Associate main view camera as LOD camera //关联主相机为视相机的lod相机 texCam->setLodCamera(cam); // set base //设置相机的位置和方向(点光源除外) if (light->getType() != Light::LT_POINT) texCam->setDirection(light->getDerivedDirection()); if (light->getType() != Light::LT_DIRECTIONAL) texCam->setPosition(light->getDerivedPosition()); // Use the material scheme of the main viewport // This is required to pick up the correct shadow_caster_material and similar properties. shadowView->setMaterialScheme(vp->getMaterialScheme()); // update shadow cam - light mapping ShadowCamLightMapping::iterator camLightIt = mShadowCamLightMapping.find( texCam ); assert(camLightIt != mShadowCamLightMapping.end()); camLightIt->second = light; if (light->getCustomShadowCameraSetup().isNull()) mDefaultShadowCameraSetup->getShadowCamera(this, cam, vp, light, texCam, j);//获取,设置阴影相机,位置、旋转、远近、FOV、投射方式(方向灯光的相机设置为正交,其他设置为透射) else light->getCustomShadowCameraSetup()->getShadowCamera(this, cam, vp, light, texCam, j); // Setup background colour shadowView->setBackgroundColour(ColourValue::White); // Fire shadow caster update, callee can alter camera settings fireShadowTexturesPreCaster(light, texCam, j); // Update target ,更新阴影材质 shadowRTT->update(); ++si; // next shadow texture ++ci; // next camera } // set the first shadow texture index for this light. mShadowTextureIndexLightList.push_back(shadowTextureIndex); shadowTextureIndex += textureCountPerLight; } } catch (Exception& e) { // we must reset the illumination stage if an exception occurs mIlluminationStage = savedStage; throw e; } // Set the illumination stage, prevents recursive calls mIlluminationStage = savedStage; fireShadowTexturesUpdated( std::min(lightList->size(), mShadowTextures.size())); ShadowTextureManager::getSingleton().clearUnused();
下面是创建阴影纹理的过程(ensureShadowTexturesCreated())
,创建纹理、创建纹理对应的渲染相机、创建材质。
if (mShadowTextureConfigDirty) { destroyShadowTextures(); //获取阴影材质们 ShadowTextureManager::getSingleton().getShadowTextures( mShadowTextureConfigList, mShadowTextures); // clear shadow cam - light mapping mShadowCamLightMapping.clear(); //Used to get the depth buffer ID setting for each RTT size_t __i = 0; // Recreate shadow textures //重新创建阴影材质,根据相机的属性等创建新的 for (ShadowTextureList::iterator i = mShadowTextures.begin(); i != mShadowTextures.end(); ++i, ++__i) { const TexturePtr& shadowTex = *i; // Camera names are local to SM String camName = shadowTex->getName() + "Cam"; // Material names are global to SM, make specific String matName = shadowTex->getName() + "Mat" + getName(); RenderTexture *shadowRTT = shadowTex->getBuffer()->getRenderTarget(); //Set appropriate depth buffer shadowRTT->setDepthBufferPool( mShadowTextureConfigList[__i].depthBufferPoolId ); // Create camera for this texture, but note that we have to rebind // in prepareShadowTextures to coexist with multiple SMs //渲染到纹理的形式,先创建相机,将相机所见内容渲染到动态的阴影纹理上 Camera* cam = createCamera(camName); cam->setAspectRatio((Real)shadowTex->getWidth() / (Real)shadowTex->getHeight()); mShadowTextureCameras.push_back(cam); // Create a viewport, if not there already if (shadowRTT->getNumViewports() == 0) { // Note camera assignment is transient when multiple SMs Viewport *v = shadowRTT->addViewport(cam); v->setClearEveryFrame(true); // remove overlays v->setOverlaysEnabled(false); } // Don't update automatically - we'll do it when required ,设置为非自动更新 shadowRTT->setAutoUpdated(false); // Also create corresponding Material used for rendering this shadow,创建材质 MaterialPtr mat = MaterialManager::getSingleton().getByName(matName); if (mat.isNull()) { mat = MaterialManager::getSingleton().create( matName, ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME); } Pass* p = mat->getTechnique(0)->getPass(0); if (p->getNumTextureUnitStates() != 1 || p->getTextureUnitState(0)->_getTexturePtr(0) != shadowTex) { mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); // create texture unit referring to render target texture TextureUnitState* texUnit = p->createTextureUnitState(shadowTex->getName()); // set projective based on camera,设置基于相机的投射纹理 texUnit->setProjectiveTexturing(!p->hasVertexProgram(), cam); // clamp to border colour texUnit->setTextureAddressingMode(TextureUnitState::TAM_BORDER); texUnit->setTextureBorderColour(ColourValue::White); mat->touch(); //编译 } // insert dummy camera-light combination mShadowCamLightMapping[cam] = 0; // Get null shadow texture if (mShadowTextureConfigList.empty()) { mNullShadowTexture.setNull(); } else { mNullShadowTexture = ShadowTextureManager::getSingleton().getNullShadowTexture( mShadowTextureConfigList[0].format); } } mShadowTextureConfigDirty = false; }
至此,需要阴影所需的计算已准备完毕。已准备的有:
1、投射投影的材质、纹理
2、接收投影的材质、纹理
3、动态阴影纹理,包含其相机设置(根据灯光属性设置的方位、远近、投影模式、颜色)
,在准备的基础上,阴影纹理程序已经更新。
下面的步骤是,在每一帧中将开了投影功能的物体投影到“画布”阴影纹理上。即将计算的出的参数值,设置到vertex、fragment 程序中
_renderQueueGroupObjects->
renderAdditiveStencilShadowedQueueGroupObjects 或
renderModulativeStencilShadowedQueueGroupObjects 或
renderTextureShadowCasterQueueGroupObjects 或
renderAdditiveTextureShadowedQueueGroupObjects 或
renderModulativeTextureShadowedQueueGroupObjects 或
renderBasicQueueGroupObjects
取决于不同的投影策略
以renderAdditiveStencilShadowedQueueGroupObjects 为例,进行跟踪
->renderShadowVolumesToStencil
->renderShadowVolumeObjects
->renderSingleObject (单个物体进行program中参数设置,rend)
- ogre 阴影技术分析记录
- OGRE学习记录-自阴影
- OGRE 阴影技术官方文档
- OGRE--阴影
- OGRE--阴影
- OGRE动态阴影
- OGRE动态阴影
- OGRE 阴影详解
- 记录Ogre
- Ogre纹理阴影与模板阴影
- 阴影技术
- OGRE 基于纹理的阴影
- Ogre阴影实现原理解析
- OGRE 基于纹理的阴影
- ogre shadow(阴影)函数笔记
- OGRE 简明扼要的分析(自己记录看看)
- ogre 模型读入 和 产生 阴影
- ogre 模型读入 和 产生 阴影
- ubuntu14.04部署samba
- 大新闻!微软正考虑添加 Python 为官方的 Excel 脚本语言
- 趣图:我司的开发进程是这样子的
- 刚刚,阿里发布了一个重磅技术炸弹……
- vs code 安装插件出现XHR error 解决办法
- ogre 阴影技术分析记录
- 基于nodejs的oauth2实现以及源码参考
- 面向对象:人生是场修行,短的是旅行,长的是我们一起前行
- 2018 最具就业前景的 7 大编程语言,前三无悬念?
- 趣图:在我电脑好好的啊!
- 主要性能指标剖析图表
- 今日头条前端面经
- Javscript高级程序设计之-Chapter3总结
- JDK1.6安装(完结)