#include "OgreDepthShadowMapRenderingRun.h" #include "OgreIlluminationManager.h" OgreDepthShadowMapRenderingRun::OgreDepthShadowMapRenderingRun(OgreSharedRuns* sharedRuns, String name, Light* light, unsigned int resolutionX, unsigned int resolutionY, String materialName ) :DepthShadowMapRenderingRun(resolutionX, resolutionY) , OgreRenderingRun(1, 1) , RenderingRun(1, 1) { this->light = light; this->sharedRuns = sharedRuns; this->name = name; this->blurredname = name + "blurred"; this->materialName = materialName; lightFarPlane = 0; createDepthMap(); } void OgreDepthShadowMapRenderingRun::createDepthMap() { if(light->getType() == Light::LT_POINT) { depthMapTexture = createCubeRenderTexture(name, light->getPosition(), resolutionX,PF_FLOAT16_RGBA,0,ColourValue::White); if(OgreIlluminationManager::getSingleton().getBlurShadowMap(light->getType())) blurredDepthMapTexture = createCubeRenderTexture(blurredname, light->getPosition(), resolutionX,PF_FLOAT16_RGBA,0,ColourValue::White); } else { TexturePtr texPtr = Ogre::TextureManager::getSingleton().createManual(name, "default", TEX_TYPE_2D, resolutionX, resolutionY, 0, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET); depthMapTexture = texPtr.getPointer(); depthMapCamera = Root::getSingleton()._getCurrentSceneManager()->createCamera(name + "_CAMERA"); //add viewport to rendertarget HardwarePixelBuffer* hpb = (depthMapTexture->getBuffer()).getPointer(); RenderTarget* rt = hpb->getRenderTarget(); Viewport* v = rt->addViewport(depthMapCamera); v->setBackgroundColour(ColourValue::White); v->setOverlaysEnabled(false); rt->setAutoUpdated(false); if(OgreIlluminationManager::getSingleton().getBlurShadowMap(light->getType())) { texPtr = Ogre::TextureManager::getSingleton().createManual(blurredname, "default", TEX_TYPE_2D, resolutionX, resolutionY, 0, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET); blurredDepthMapTexture = texPtr.getPointer(); hpb = (blurredDepthMapTexture->getBuffer()).getPointer(); rt = hpb->getRenderTarget(); v = rt->addViewport(depthMapCamera); v->setOverlaysEnabled(false); rt->setAutoUpdated(false); } } } bool OgreDepthShadowMapRenderingRun::renderableQueued (Renderable *rend, uint8 groupID, ushort priority, Technique **ppTech) { OgreTechniqueGroup* TG = (OgreTechniqueGroup*) rend->getRenderTechniqueGroup(); if(TG) { String materialToSet = materialName; String triggeredMaterial = TG->getMaterialNameForTrigger(triggerName); if(triggeredMaterial != "")//a trigger is associated materialToSet = triggeredMaterial; Technique* techn = ((Material*)MaterialManager::getSingleton().getByName( materialToSet ).getPointer())->getTechnique(0); *ppTech = techn; } return true; } void OgreDepthShadowMapRenderingRun::updateFrame(unsigned long frameNum) { refreshLight(frameNum); RenderQueue* rq = Root::getSingleton()._getCurrentSceneManager()->getRenderQueue(); rq->setRenderableListener(this); if(light->getType() == Light::LT_POINT) { for(int i = 0; i < 6 ; i++) updateDepthCubeFace(i); //restoreMaterials(); } else { updateDepthMap(); } rq->setRenderableListener(0); } void OgreDepthShadowMapRenderingRun::updateDepthCubeFace(int facenum) { Vector3 lightpos = light->getDerivedPosition(); RenderTarget* rt = depthMapTexture->getBuffer(facenum, 0).getPointer()->getRenderTarget(); Camera* cam = rt->getViewport(0)->getCamera(); cam->setFarClipDistance(lightFarPlane); cam->setPosition(lightpos); //setMaterialForVisibles(materialName, cam, true, false, triggerName); rt->update(); // restoreMaterials(); //rt->writeContentsToFile("shadowmap_" + StringConverter::toString(facenum) + ".dds"); if(OgreIlluminationManager::getSingleton().getBlurShadowMap(light->getType())) { rt = blurredDepthMapTexture->getBuffer(facenum, 0).getPointer()->getRenderTarget(); Material* mat = (Material*) MaterialManager::getSingleton().getByName("GameTools/BlurCubeFace").getPointer(); mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(depthMapTexture->getName()); mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("face", facenum); renderFullscreenQuad("GameTools/BlurCubeFace", rt); //rt->writeContentsToFile("shadowmap_blurred_" + StringConverter::toString(facenum) + ".dds"); } } void OgreDepthShadowMapRenderingRun::updateDepthMap() { RenderTarget* rt = depthMapTexture->getBuffer().getPointer()->getRenderTarget(); Viewport* vp = rt->getViewport(0); //setMaterialForVisibles(materialName, depthMapCamera, true, false, triggerName); rt->update(); //restoreMaterials(); if(OgreIlluminationManager::getSingleton().getBlurShadowMap(light->getType())) { rt = blurredDepthMapTexture->getBuffer().getPointer()->getRenderTarget(); Material* mat = (Material*) MaterialManager::getSingleton().getByName("GameTools/Blur").getPointer(); mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(depthMapTexture->getName()); renderFullscreenQuad("GameTools/Blur", rt); } //rt->writeContentsToFile("shadowmap1.dds"); //depthMapTexture->(); } const String& OgreDepthShadowMapRenderingRun::getDepthMapTextureName() { if(OgreIlluminationManager::getSingleton().getBlurShadowMap(light->getType())) return blurredname; return name; } void OgreDepthShadowMapRenderingRun::refreshLight(unsigned long frameNum) { if(light!= 0) { bool uselispsm = OgreIlluminationManager::getSingleton().getUseLISPSM(light->getType()); bool usefocusing = OgreIlluminationManager::getSingleton().getFocusingShadowMap(light->getType()); if(light->getType() == Light::LT_DIRECTIONAL) { triggerName = "ILLUM_TRIGGER_SM_DIRECTIONAL"; Camera* viewcam = OgreIlluminationManager::getSingleton().getMainCamera(); OgreFocusingMapRenderingRun* frun = (OgreFocusingMapRenderingRun*) OgreIlluminationManager::getSingleton().getGlobalRun(ILLUMRUN_FOCUSING_MAP)->asOgreRenderingRun(); frun->setCameraMatrices(viewcam->getViewMatrix(), viewcam->getProjectionMatrix()); Vector3 lightpos = light->getDerivedPosition(); Vector3 lightdir = light->getDerivedDirection(); lightdir.normalise(); Vector3 min; Vector3 max; if(uselispsm) { Camera* maincam = OgreIlluminationManager::getSingleton().getMainCamera(); Vector3 viewdir = maincam->getDirection(); viewdir.normalise(); Vector3 campos = maincam->getPosition(); float nearclip = maincam->getNearClipDistance(); float dotprod = viewdir.dotProduct(lightdir); float sinGamma = sqrt(1.0 - dotprod * dotprod); Vector3 left = lightdir.crossProduct(viewdir); left.normalise(); Vector3 up = left.crossProduct(lightdir); up.normalise(); //left = lightdir.crossProduct(up); left.normalise(); Matrix4 viewMatrix( left.x, left.y, left.z, 0, up.x, up.y, up.z, 0, lightdir.x, lightdir.y, lightdir.z, 0, 0, 0, 0, 1); frun->setLightMatrix(viewMatrix); OgreIlluminationManager::getSingleton().updateGlobalRun( ILLUMRUN_FOCUSING_MAP, frameNum); frun->getMinMax(min, max); float n; float f; float d = abs(max.y - min.y); float z_n = nearclip / sinGamma; float one_min_singamma = (1 - sinGamma); float fact = d * pow(one_min_singamma, 2); float z_f = z_n + d * sinGamma * fact; n = (z_n + sqrt(z_f * z_n)) / sinGamma; ///n = 100000; f = n + d; Vector3 pos = campos - up * (n - nearclip); Matrix4 newViewMatrix( left.x, left.y, left.z, -left.dotProduct(pos), up.x, up.y, up.z, -up.dotProduct(pos), -lightdir.x, -lightdir.y, -lightdir.z, lightdir.dotProduct(pos), 0, 0, 0, 1); Matrix4 lispMat = Matrix4::IDENTITY; lispMat[1][1] = f / (f - n); lispMat[1][3] = f * n / (f - n); lispMat[3][1] = 1; lispMat[3][3] = 0; depthMapCamera->setCustomProjectionMatrix(true, Matrix4::IDENTITY); depthMapCamera->setCustomViewMatrix(true, lispMat * newViewMatrix); } else { depthMapCamera->setCustomProjectionMatrix(true, Matrix4::IDENTITY); depthMapCamera->setCustomViewMatrix(false); depthMapCamera->setPosition(lightpos); depthMapCamera->setDirection(lightdir); } Matrix4 lightMatrix = depthMapCamera->getViewMatrix(); frun->setLightMatrix(lightMatrix); OgreIlluminationManager::getSingleton().updateGlobalRun( ILLUMRUN_FOCUSING_MAP, frameNum); frun->getMinMax(min, max); Vector3 scale = (max - min); scale *= 1.5; // just for safety if(uselispsm) scale.z += 1; else scale.z += 1000; //TODO: get scene bounding box to set z scale Matrix4 projection = Matrix4::IDENTITY; Matrix4 trans = Matrix4::IDENTITY; trans.setTrans(Vector3(-(max.x + min.x) / 2.0, -(max.y + min.y) / 2.0, -(max.z + min.z) / 2.0)); Matrix4 scaleM = Matrix4::IDENTITY; scaleM.setScale(Vector3(2.0 / scale.x, 2.0 / scale.y, -2.0 / scale.z)); projection = scaleM * trans; depthMapCamera->setCustomProjectionMatrix(true, projection); } else if(light->getType() == Light::LT_SPOTLIGHT) { triggerName = "ILLUM_TRIGGER_SM_SPOT"; Camera* viewcam = OgreIlluminationManager::getSingleton().getMainCamera(); OgreFocusingMapRenderingRun* frun = (OgreFocusingMapRenderingRun*) OgreIlluminationManager::getSingleton().getGlobalRun(ILLUMRUN_FOCUSING_MAP)->asOgreRenderingRun(); frun->setCameraMatrices(viewcam->getViewMatrix(), viewcam->getProjectionMatrix()); Vector3 lightpos = light->getDerivedPosition(); Vector3 lightdir = light->getDerivedDirection(); lightdir.normalise(); Radian lightangle = light->getSpotlightOuterAngle(); Vector3 min; Vector3 max; if(uselispsm) { Camera* maincam = OgreIlluminationManager::getSingleton().getMainCamera(); Vector3 viewdir = maincam->getDirection(); viewdir.normalise(); Vector3 campos = maincam->getPosition(); float nearclip = maincam->getNearClipDistance(); float dotprod = viewdir.dotProduct(lightdir); float sinGamma = sqrt(1.0 - dotprod * dotprod); Vector3 left = lightdir.crossProduct(viewdir); Vector3 up = left.crossProduct(lightdir); up.normalise(); //left = lightdir.crossProduct(up); left.normalise(); depthMapCamera->setCustomProjectionMatrix(false); depthMapCamera->setProjectionType(PT_PERSPECTIVE); depthMapCamera->setFOVy(lightangle); depthMapCamera->setAspectRatio(1); depthMapCamera->setNearClipDistance(0.1); depthMapCamera->setFarClipDistance(1.0); Matrix4 projMatrix = depthMapCamera->getProjectionMatrixWithRSDepth(); Matrix4 viewMatrix( left.x, left.y, left.z, 0, up.x, up.y, up.z, 0, -lightdir.x, -lightdir.y, -lightdir.z, 0, 0, 0, 0, 1); frun->setLightMatrix(projMatrix * viewMatrix); OgreIlluminationManager::getSingleton().updateGlobalRun( ILLUMRUN_FOCUSING_MAP, frameNum); frun->getMinMax(min, max); float n; float f; float d = abs(max.y - min.y); float z_n = nearclip / sinGamma; float one_min_singamma = (1 - sinGamma); float fact = d * pow(one_min_singamma, 2); float z_f = z_n + d * sinGamma * fact; n = (z_n + sqrt(z_f * z_n)) / sinGamma; ///n = 100000; f = n + d; Vector3 pos = campos - up * (n - nearclip); Matrix4 newViewMatrix( left.x, left.y, left.z, -left.dotProduct(pos), up.x, up.y, up.z, -up.dotProduct(pos), -lightdir.x, -lightdir.y, -lightdir.z, lightdir.dotProduct(pos), 0, 0, 0, 1); Matrix4 lispMat = Matrix4::IDENTITY; lispMat[1][1] = f / (f - n); lispMat[1][3] = f * n / (f - n); lispMat[3][1] = 1; lispMat[3][3] = 0; depthMapCamera->setCustomProjectionMatrix(true, Matrix4::IDENTITY); depthMapCamera->setCustomViewMatrix(true, lispMat * projMatrix * newViewMatrix); } else { depthMapCamera->setCustomProjectionMatrix(false); depthMapCamera->setCustomViewMatrix(false); depthMapCamera->setPosition(lightpos); depthMapCamera->setDirection(lightdir); depthMapCamera->setProjectionType(PT_PERSPECTIVE); depthMapCamera->setFOVy(lightangle); depthMapCamera->setAspectRatio(1); depthMapCamera->setNearClipDistance(OgreIlluminationManager::getSingleton().getAreaLightRadius()); depthMapCamera->setFarClipDistance(1.0); } if(!usefocusing) { lightFarPlane = light->getAttenuationRange(); depthMapCamera->setFarClipDistance(lightFarPlane); } else { Matrix4 lightMatrix = depthMapCamera->getViewMatrix(); frun->setLightMatrix(lightMatrix); OgreIlluminationManager::getSingleton().updateGlobalRun( ILLUMRUN_FOCUSING_MAP, frameNum); frun->getMinMax(min, max); if(min.z < 0) { float farP= -1.5 * min.z; if(farP < 0.2) farP = 0.2; depthMapCamera->setFarClipDistance(farP); lightFarPlane = farP; Vector3 scale = (max - min); scale *= 1.5; // just for safety Matrix4 projection = Matrix4::IDENTITY; Matrix4 trans = Matrix4::IDENTITY; trans.setTrans(Vector3(-(max.x + min.x) / 2.0, -(max.y + min.y) / 2.0, 0)); Matrix4 scaleM = Matrix4::IDENTITY; scaleM.setScale(Vector3(2.0 / scale.x, 2.0 / scale.y, 1)); projection = scaleM * trans; depthMapCamera->setCustomProjectionMatrix(true, projection * depthMapCamera->getProjectionMatrix()); } } } else//point light { lightFarPlane = light->getAttenuationRange(); triggerName = "ILLUM_TRIGGER_SM_POINT"; //no other adjustment needed } } } Matrix4 OgreDepthShadowMapRenderingRun::getLightViewMatrix() { Camera* cam = depthMapCamera; if(light->getType() == Light::LT_POINT) cam = depthMapTexture->getBuffer(4, 0).getPointer()->getRenderTarget()->getViewport(0)->getCamera(); return cam->getViewMatrix(); } Matrix4 OgreDepthShadowMapRenderingRun::getLightViewProjMatrix() { Camera* cam = depthMapCamera; if(light->getType() == Light::LT_POINT) cam = depthMapTexture->getBuffer(4, 0).getPointer()->getRenderTarget()->getViewport(0)->getCamera(); return cam->getProjectionMatrixWithRSDepth() * cam->getViewMatrix(); } void OgreDepthShadowMapRenderingRun::freeAllResources() { this->blurredDepthMapTexture = 0; this->depthMapTexture = 0; TextureManager::getSingleton().remove(name); TextureManager::getSingleton().remove(blurredname); Root::getSingleton()._getCurrentSceneManager()->destroyCamera(name + "_CAMERA"); }