basic shadows

actorid
scrawl 13 years ago
parent 62908c9ef5
commit 2a4fcf42a3

@ -15,7 +15,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
renderinginterface localmap occlusionquery terrain terrainmaterial water renderinginterface localmap occlusionquery terrain terrainmaterial water shadows shaderhelper
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

@ -362,6 +362,7 @@ void OMW::Engine::go()
addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "water");
addResourcesDirectory(mResDir / "gbuffer"); addResourcesDirectory(mResDir / "gbuffer");
addResourcesDirectory(mResDir / "shadows");
// Create the window // Create the window
mOgre->createWindow("OpenMW"); mOgre->createWindow("OpenMW");

@ -225,7 +225,9 @@ void LocalMap::render(const float x, const float y,
vp->setShadowsEnabled(false); vp->setShadowsEnabled(false);
vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setBackgroundColour(ColourValue(0, 0, 0));
vp->setVisibilityMask(RV_Map); vp->setVisibilityMask(RV_Map);
vp->setMaterialScheme("Map");
// use fallback techniques without shadows and without mrt
vp->setMaterialScheme("Fallback");
rtt->update(); rtt->update();

@ -193,6 +193,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics);
sg->setCastShadows(true);
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
mRenderer.getScene()->destroyEntity(ent); mRenderer.getScene()->destroyEntity(ent);

@ -60,6 +60,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
mBBQueryTotal = mRendering->getScene()->createBillboardSet(1); mBBQueryTotal = mRendering->getScene()->createBillboardSet(1);
mBBQueryTotal->setCastShadows(false);
mBBQueryTotal->setDefaultDimensions(150, 150); mBBQueryTotal->setDefaultDimensions(150, 150);
mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->createBillboard(Vector3::ZERO);
mBBQueryTotal->setMaterialName("QueryTotalPixels"); mBBQueryTotal->setMaterialName("QueryTotalPixels");
@ -67,6 +68,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBNodeReal->attachObject(mBBQueryTotal); mBBNodeReal->attachObject(mBBQueryTotal);
mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1);
mBBQueryVisible->setCastShadows(false);
mBBQueryVisible->setDefaultDimensions(150, 150); mBBQueryVisible->setDefaultDimensions(150, 150);
mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->createBillboard(Vector3::ZERO);
mBBQueryVisible->setMaterialName("QueryVisiblePixels"); mBBQueryVisible->setMaterialName("QueryVisiblePixels");
@ -75,6 +77,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1);
/// \todo ideally this should occupy exactly 1 pixel on the screen /// \todo ideally this should occupy exactly 1 pixel on the screen
mBBQuerySingleObject->setCastShadows(false);
mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003); mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003);
mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->createBillboard(Vector3::ZERO);
mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels");

@ -14,6 +14,10 @@
#include <components/esm/loadstat.hpp> #include <components/esm/loadstat.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "shadows.hpp"
#include "shaderhelper.hpp"
#include "localmap.hpp"
#include "water.hpp"
using namespace MWRender; using namespace MWRender;
using namespace Ogre; using namespace Ogre;
@ -21,11 +25,9 @@ using namespace Ogre;
namespace MWRender { namespace MWRender {
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment) RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment)
:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0) :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mSunEnabled(0)
{ {
mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5);
mTerrainManager = new TerrainManager(mRendering.getScene(),
environment);
mWater = 0; mWater = 0;
@ -86,6 +88,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode(); Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
cameraPitchNode->attachObject(mRendering.getCamera()); cameraPitchNode->attachObject(mRendering.getCamera());
mShadows = new Shadows(&mRendering);
mShaderHelper = new ShaderHelper(this);
mTerrainManager = new TerrainManager(mRendering.getScene(), this,
environment);
//mSkyManager = 0; //mSkyManager = 0;
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
@ -412,6 +420,7 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
{ {
if (!mSunEnabled) return;
mSun->setDiffuseColour(colour); mSun->setDiffuseColour(colour);
mSun->setSpecularColour(colour); mSun->setSpecularColour(colour);
mTerrainManager->setDiffuse(colour); mTerrainManager->setDiffuse(colour);
@ -425,12 +434,21 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
void RenderingManager::sunEnable() void RenderingManager::sunEnable()
{ {
if (mSun) mSun->setVisible(true); // Don't disable the light, as the shaders assume the first light to be directional.
//if (mSun) mSun->setVisible(true);
mSunEnabled = true;
} }
void RenderingManager::sunDisable() void RenderingManager::sunDisable()
{ {
if (mSun) mSun->setVisible(false); // Don't disable the light, as the shaders assume the first light to be directional.
//if (mSun) mSun->setVisible(false);
mSunEnabled = false;
if (mSun)
{
mSun->setDiffuseColour(ColourValue(0,0,0));
mSun->setSpecularColour(ColourValue(0,0,0));
}
} }
void RenderingManager::setSunDirection(const Ogre::Vector3& direction) void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
@ -475,4 +493,9 @@ const bool RenderingManager::useMRT()
return Settings::Manager::getBool("shader", "Water"); return Settings::Manager::getBool("shader", "Water");
} }
Shadows* RenderingManager::getShadows()
{
return mShadows;
}
} // namespace } // namespace

@ -25,8 +25,6 @@
#include "objects.hpp" #include "objects.hpp"
#include "actors.hpp" #include "actors.hpp"
#include "player.hpp" #include "player.hpp"
#include "water.hpp"
#include "localmap.hpp"
#include "occlusionquery.hpp" #include "occlusionquery.hpp"
namespace Ogre namespace Ogre
@ -45,7 +43,10 @@ namespace MWWorld
namespace MWRender namespace MWRender
{ {
class Shadows;
class ShaderHelper;
class LocalMap;
class Water;
class RenderingManager: private RenderingInterface { class RenderingManager: private RenderingInterface {
@ -114,6 +115,8 @@ class RenderingManager: private RenderingInterface {
bool occlusionQuerySupported() { return mOcclusionQuery->supported(); }; bool occlusionQuerySupported() { return mOcclusionQuery->supported(); };
OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; }; OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; };
Shadows* getShadows();
void setGlare(bool glare); void setGlare(bool glare);
void skyEnable (); void skyEnable ();
void skyDisable (); void skyDisable ();
@ -149,6 +152,8 @@ class RenderingManager: private RenderingInterface {
void setAmbientMode(); void setAmbientMode();
bool mSunEnabled;
SkyManager* mSkyManager; SkyManager* mSkyManager;
OcclusionQuery* mOcclusionQuery; OcclusionQuery* mOcclusionQuery;
@ -180,6 +185,10 @@ class RenderingManager: private RenderingInterface {
MWRender::Debugging *mDebugging; MWRender::Debugging *mDebugging;
MWRender::LocalMap* mLocalMap; MWRender::LocalMap* mLocalMap;
MWRender::Shadows* mShadows;
MWRender::ShaderHelper* mShaderHelper;
}; };
} }

@ -0,0 +1,308 @@
#include "shaderhelper.hpp"
#include "renderingmanager.hpp"
#include "shadows.hpp"
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreHighLevelGpuProgram.h>
#include <OgreGpuProgramParams.h>
#include <components/settings/settings.hpp>
using namespace Ogre;
using namespace MWRender;
ShaderHelper::ShaderHelper(RenderingManager* rend)
{
mRendering = rend;
applyShaders();
}
void ShaderHelper::applyShaders()
{
if (!Settings::Manager::getBool("shaders", "Objects")) return;
bool mrt = RenderingManager::useMRT();
bool shadows = Settings::Manager::getBool("enabled", "Shadows");
bool split = Settings::Manager::getBool("split", "Shadows");
// shader for normal rendering
createShader(mrt, shadows, split, "main");
// fallback shader without mrt and without shadows
// (useful for reflection and for minimap)
createShader(false, false, false, "main_fallback");
}
void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool split, const std::string& name)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
const int numsplits = 3;
// the number of lights to support.
// when rendering an object, OGRE automatically picks the lights that are
// closest to the object being rendered. unfortunately this mechanism does
// not work perfectly for objects batched together (they will all use the same
// lights). to work around this, we are simply pushing the maximum number
// of lights here in order to minimize disappearing lights.
int num_lights = Settings::Manager::getInt("num lights", "Objects");
{
// vertex
HighLevelGpuProgramPtr vertex;
if (!mgr.getByName(name+"_vp").isNull())
mgr.remove(name+"_vp");
vertex = mgr.createProgram(name+"_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
vertex->setParameter("profiles", "vs_4_0 vs_2_x vp40 arbvp1");
vertex->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream;
outStream <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" float4 normal : NORMAL, \n"
" float4 colour : COLOR, \n"
" in float2 uv : TEXCOORD0, \n"
" out float2 oUV : TEXCOORD0, \n"
" out float4 oPosition : POSITION, \n"
" out float4 oPositionObjSpace : TEXCOORD1, \n"
" out float4 oNormal : TEXCOORD2, \n"
" out float oDepth : TEXCOORD3, \n"
" out float4 oVertexColour : TEXCOORD4, \n";
if (shadows && !split) outStream <<
" out float4 oLightSpacePos0 : TEXCOORD5, \n"
" uniform float4x4 worldMatrix, \n"
" uniform float4x4 texViewProjMatrix0, \n";
else
{
for (int i=0; i<numsplits; ++i)
{
outStream <<
" out float4 oLightSpacePos"<<i<<" : TEXCOORD"<<i+5<<", \n"
" uniform float4x4 texViewProjMatrix"<<i<<", \n";
}
outStream <<
" uniform float4x4 worldMatrix, \n";
}
outStream <<
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oVertexColour = colour; \n"
" oUV = uv; \n"
" oNormal = normal; \n"
" oPosition = mul( worldViewProj, position ); \n"
" oDepth = oPosition.z; \n"
" oPositionObjSpace = position; \n";
if (shadows && !split) outStream <<
" oLightSpacePos0 = mul(texViewProjMatrix0, mul(worldMatrix, position)); \n";
else
{
outStream <<
" float4 wPos = mul(worldMatrix, position); \n";
for (int i=0; i<numsplits; ++i)
{
outStream <<
" oLightSpacePos"<<i<<" = mul(texViewProjMatrix"<<i<<", wPos); \n";
}
}
outStream <<
"}";
vertex->setSource(outStream.str());
vertex->load();
vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
if (shadows)
{
vertex->getDefaultParameters()->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX);
if (!split)
vertex->getDefaultParameters()->setNamedAutoConstant("texViewProjMatrix0", GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, 0);
else
{
for (int i=0; i<numsplits; ++i)
{
vertex->getDefaultParameters()->setNamedAutoConstant("texViewProjMatrix"+StringConverter::toString(i), GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
}
}
}
}
{
// fragment
HighLevelGpuProgramPtr fragment;
if (!mgr.getByName(name+"_fp").isNull())
mgr.remove(name+"_fp");
fragment = mgr.createProgram(name+"_fp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
fragment->setParameter("profiles", "ps_4_0 ps_2_x fp40 arbfp1");
fragment->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType outStream;
if (shadows) outStream <<
"float depthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n"
"{ \n"
" shadowMapPos /= shadowMapPos.w; \n"
" float3 o = float3(offset.xy, -offset.x) * 0.3f; \n"
" float c = (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left \n"
" c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right \n"
" c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left \n"
" c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right \n"
" return c / 4; \n"
"} \n";
outStream <<
"void main_fp( \n"
" in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n"
" uniform sampler2D texture : register(s0), \n"
" float4 positionObjSpace : TEXCOORD1, \n"
" float4 normal : TEXCOORD2, \n"
" float iDepth : TEXCOORD3, \n"
" float4 vertexColour : TEXCOORD4, \n"
" uniform float4 fogColour, \n"
" uniform float4 fogParams, \n";
if (shadows) outStream <<
" uniform float4 shadowFar_fadeStart, \n";
if (shadows && !split) outStream <<
" uniform sampler2D shadowMap : register(s1), \n"
" float4 lightSpacePos0 : TEXCOORD5, \n"
" uniform float4 invShadowmapSize0, \n";
else
{
outStream <<
" uniform float4 pssmSplitPoints, \n";
for (int i=0; i<numsplits; ++i)
{
outStream <<
" uniform sampler2D shadowMap"<<i<<" : register(s"<<i+1<<"), \n"
" float4 lightSpacePos"<<i<<" : TEXCOORD"<<i+5<<", \n"
" uniform float4 invShadowmapSize"<<i<<", \n";
}
}
if (mrt) outStream <<
" out float4 oColor1 : COLOR1, \n"
" uniform float far, \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" uniform float4 lightDiffuse"<<i<<", \n"
" uniform float4 lightPositionObjSpace"<<i<<", \n"
" uniform float4 lightAttenuation"<<i<<", \n";
}
outStream <<
" uniform float4 lightAmbient, \n"
" uniform float4 ambient, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" float4 tex = tex2D(texture, uv); \n"
" float d; \n"
" float attn; \n"
" float3 lightDir; \n"
" float3 lightColour = float3(0, 0, 0); \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" lightDir = lightPositionObjSpace"<<i<<".xyz - (positionObjSpace.xyz * lightPositionObjSpace"<<i<<".w); \n"
// pre-multiply light color with attenuation factor
" d = length( lightDir ); \n"
" attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
" lightDiffuse"<<i<<" *= attn; \n";
if (i == 0 && shadows)
{
outStream <<
" float shadow; \n";
if (!split) outStream <<
" shadow = depthShadow(shadowMap, lightSpacePos0, invShadowmapSize0.xy); \n";
else
{
for (int j=0; j<numsplits; ++j)
{
std::string channel;
if (j==0) channel = "x";
else if (j==1) channel = "y";
else if (j==2) channel = "z";
if (j==0)
outStream << " if (iDepth <= pssmSplitPoints." << channel << ") \n";
else if (j < numsplits - 1)
outStream << " else if (iDepth <= pssmSplitPoints." << channel << ") \n";
else
outStream << " else \n";
outStream <<
" { \n"
" shadow = depthShadow(shadowMap" << j << ", lightSpacePos" << j << ", invShadowmapSize" << j << ".xy); \n"
" } \n";
}
}
outStream <<
" float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n"
" float fade = 1-((iDepth - shadowFar_fadeStart.y) / fadeRange); \n"
" shadow = (iDepth > shadowFar_fadeStart.x) ? 1 : ((iDepth > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); \n"
" lightColour.xyz += shadow * lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
}
else outStream <<
" lightColour.xyz += lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
}
outStream <<
" float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n"
" float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n"
" oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour, fogValue); \n"
" oColor.a = tex.a * diffuse.a * vertexColour.a; \n";
if (mrt) outStream <<
" oColor1 = float4(iDepth / far, 0, 0, (oColor.a == 1)); \n"; // only write to MRT if alpha is 1
outStream <<
"}";
fragment->setSource(outStream.str());
fragment->load();
for (int i=0; i<num_lights; ++i)
{
fragment->getDefaultParameters()->setNamedAutoConstant("lightPositionObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i);
fragment->getDefaultParameters()->setNamedAutoConstant("lightDiffuse"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i);
fragment->getDefaultParameters()->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i);
}
fragment->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
if (shadows)
{
fragment->getDefaultParameters()->setNamedConstant("shadowFar_fadeStart", Vector4(mRendering->getShadows()->getShadowFar(), mRendering->getShadows()->getFadeStart()*mRendering->getShadows()->getShadowFar(), 0, 0));
for (int i=0; i < (split ? numsplits : 1); ++i)
{
fragment->getDefaultParameters()->setNamedAutoConstant("invShadowmapSize" + StringConverter::toString(i), GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i+1);
}
if (split)
{
Vector4 splitPoints;
const PSSMShadowCameraSetup::SplitPointList& splitPointList = mRendering->getShadows()->getPSSMSetup()->getSplitPoints();
// Populate from split point 1, not 0, since split 0 isn't useful (usually 0)
for (int i = 1; i < numsplits; ++i)
{
splitPoints[i-1] = splitPointList[i];
}
fragment->getDefaultParameters()->setNamedConstant("pssmSplitPoints", splitPoints);
}
}
if (mrt)
fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
}
}

@ -0,0 +1,29 @@
#ifndef GAME_SHADERHELPER_H
#define GAME_SHADERHELPER_H
#include <string>
namespace MWRender
{
class RenderingManager;
///
/// \brief manages the main shader
///
class ShaderHelper
{
public:
ShaderHelper(RenderingManager* rend);
void applyShaders();
///< apply new settings
private:
RenderingManager* mRendering;
void createShader(const bool mrt, const bool shadows, const bool split, const std::string& name);
};
}
#endif

@ -0,0 +1,175 @@
#include "shadows.hpp"
#include <components/settings/settings.hpp>
#include <openengine/ogre/renderer.hpp>
#include <OgreSceneManager.h>
#include <OgreColourValue.h>
#include <OgreShadowCameraSetupLiSPSM.h>
#include <OgreShadowCameraSetupPSSM.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreOverlayContainer.h>
#include <OgreOverlayManager.h>
#include "renderconst.hpp"
using namespace Ogre;
using namespace MWRender;
Shadows::Shadows(OEngine::Render::OgreRenderer* rend) :
mShadowFar(1000), mFadeStart(0.9)
{
mRendering = rend;
mSceneMgr = mRendering->getScene();
recreate();
}
void Shadows::recreate()
{
bool enabled = Settings::Manager::getBool("enabled", "Shadows");
// Split shadow maps are currently disabled because the terrain cannot cope with them
// (Too many texture units) Solution would be a multi-pass terrain material
bool split = Settings::Manager::getBool("split", "Shadows");
//const bool split = false;
if (!enabled)
{
mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
return;
}
int texsize = Settings::Manager::getInt("texture size", "Shadows");
mSceneMgr->setShadowTextureSize(texsize);
mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED);
// no point light shadows, i'm afraid. might revisit this with Deferred Shading
mSceneMgr->setShadowTextureCountPerLightType(Light::LT_POINT, 0);
mSceneMgr->setShadowTextureCountPerLightType(Light::LT_DIRECTIONAL, split ? 3 : 1);
mSceneMgr->setShadowTextureCount(split ? 3 : 1);
mSceneMgr->setShadowTextureSelfShadow(true);
mSceneMgr->setShadowCasterRenderBackFaces(true);
mSceneMgr->setShadowTextureCasterMaterial("depth_shadow_caster");
mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R);
mSceneMgr->setShadowDirLightTextureOffset(0.9);
mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000);
mSceneMgr->setShowDebugShadows(true);
mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows");
mSceneMgr->setShadowFarDistance(mShadowFar);
mFadeStart = Settings::Manager::getFloat("fade start", "Shadows");
ShadowCameraSetupPtr shadowCameraSetup;
if (split)
{
mPSSMSetup = new PSSMShadowCameraSetup();
mPSSMSetup->setSplitPadding(5);
mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar);
const Real adjustFactors[3] = {64, 64, 64};
for (int i=0; i < 3; ++i)
{
mPSSMSetup->setOptimalAdjustFactor(i, adjustFactors[i]);
/*if (i==0)
mSceneMgr->setShadowTextureConfig(i, texsize, texsize, Ogre::PF_FLOAT32_R);
else if (i ==1)
mSceneMgr->setShadowTextureConfig(i, texsize/2, texsize/2, Ogre::PF_FLOAT32_R);
else if (i ==2)
mSceneMgr->setShadowTextureConfig(i, texsize/4, texsize/4, Ogre::PF_FLOAT32_R);*/
}
shadowCameraSetup = ShadowCameraSetupPtr(mPSSMSetup);
}
else
{
LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup();
lispsmSetup->setOptimalAdjustFactor(2);
//lispsmSetup->setCameraLightDirectionThreshold(Degree(0));
//lispsmSetup->setUseAggressiveFocusRegion(false);
shadowCameraSetup = ShadowCameraSetupPtr(lispsmSetup);
}
mSceneMgr->setShadowCameraSetup(shadowCameraSetup);
// Set visibility mask for the shadow render textures
int visibilityMask = RV_Actors * Settings::Manager::getBool("actor shadows", "Shadows")
+ (RV_Statics + RV_StaticsSmall) * Settings::Manager::getBool("statics shadows", "Shadows")
+ RV_Misc * Settings::Manager::getBool("misc shadows", "Shadows");
for (int i = 0; i < (split ? 3 : 1); ++i)
{
TexturePtr shadowTexture = mSceneMgr->getShadowTexture(i);
Viewport* vp = shadowTexture->getBuffer()->getRenderTarget()->getViewport(0);
vp->setVisibilityMask(visibilityMask);
}
// --------------------------------------------------------------------------------------------------------------------
// --------------------------- Debug overlays to display the content of shadow maps -----------------------------------
// --------------------------------------------------------------------------------------------------------------------
/*
OverlayManager& mgr = OverlayManager::getSingleton();
Overlay* overlay;
// destroy if already exists
if (overlay = mgr.getByName("DebugOverlay"))
mgr.destroy(overlay);
overlay = mgr.create("DebugOverlay");
for (size_t i = 0; i < (split ? 3 : 1); ++i) {
TexturePtr tex = mRendering->getScene()->getShadowTexture(i);
// Set up a debug panel to display the shadow
if (MaterialManager::getSingleton().resourceExists("Ogre/DebugTexture" + StringConverter::toString(i)))
MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i));
MaterialPtr debugMat = MaterialManager::getSingleton().create(
"Ogre/DebugTexture" + StringConverter::toString(i),
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName());
t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
OverlayContainer* debugPanel;
// destroy container if exists
try
{
if (debugPanel =
static_cast<OverlayContainer*>(
mgr.getOverlayElement("Ogre/DebugTexPanel" + StringConverter::toString(i)
)))
mgr.destroyOverlayElement(debugPanel);
}
catch (Ogre::Exception&) {}
debugPanel = (OverlayContainer*)
(OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + StringConverter::toString(i)));
debugPanel->_setPosition(0.8, i*0.25);
debugPanel->_setDimensions(0.2, 0.24);
debugPanel->setMaterialName(debugMat->getName());
debugPanel->show();
overlay->add2D(debugPanel);
overlay->show();
}
*/
}
PSSMShadowCameraSetup* Shadows::getPSSMSetup()
{
return mPSSMSetup;
}
float Shadows::getShadowFar() const
{
return mShadowFar;
}
float Shadows::getFadeStart() const
{
return mFadeStart;
}

@ -0,0 +1,39 @@
#ifndef GAME_SHADOWS_H
#define GAME_SHADOWS_H
// forward declares
namespace Ogre
{
class SceneManager;
class PSSMShadowCameraSetup;
}
namespace OEngine{
namespace Render{
class OgreRenderer;
}
}
namespace MWRender
{
class Shadows
{
public:
Shadows(OEngine::Render::OgreRenderer* rend);
void recreate();
Ogre::PSSMShadowCameraSetup* getPSSMSetup();
float getShadowFar() const;
float getFadeStart() const;
protected:
OEngine::Render::OgreRenderer* mRendering;
Ogre::SceneManager* mSceneMgr;
Ogre::PSSMShadowCameraSetup* mPSSMSetup;
float mShadowFar;
float mFadeStart;
};
}
#endif

@ -102,6 +102,7 @@ void BillboardObject::init(const String& textureName,
mNode->setPosition(finalPosition); mNode->setPosition(finalPosition);
mNode->attachObject(mBBSet); mNode->attachObject(mBBSet);
mBBSet->createBillboard(0,0,0); mBBSet->createBillboard(0,0,0);
mBBSet->setCastShadows(false);
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
mMaterial->removeAllTechniques(); mMaterial->removeAllTechniques();
@ -450,6 +451,7 @@ void SkyManager::create()
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setVisibilityFlags(RV_Sky);
night1_ent->setCastShadows(false);
mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight = mRootNode->createChildSceneNode();
mAtmosphereNight->attachObject(night1_ent); mAtmosphereNight->attachObject(night1_ent);
@ -525,6 +527,7 @@ void SkyManager::create()
// Atmosphere (day) // Atmosphere (day)
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif"); Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
atmosphere_ent->setCastShadows(false);
ModVertexAlpha(atmosphere_ent, 0); ModVertexAlpha(atmosphere_ent, 0);
@ -596,6 +599,7 @@ void SkyManager::create()
SceneNode* clouds_node = mRootNode->createChildSceneNode(); SceneNode* clouds_node = mRootNode->createChildSceneNode();
clouds_node->attachObject(clouds_ent); clouds_node->attachObject(clouds_ent);
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
clouds_ent->setCastShadows(false);
// Clouds vertex shader // Clouds vertex shader
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
@ -677,6 +681,8 @@ void SkyManager::create()
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mCloudMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("textures\\tx_sky_cloudy.dds");
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
mCreated = true; mCreated = true;
@ -766,12 +772,14 @@ void SkyManager::disable()
void SkyManager::setMoonColour (bool red) void SkyManager::setMoonColour (bool red)
{ {
if (!mCreated) return;
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784) mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
: ColourValue(1.0, 1.0, 1.0)); : ColourValue(1.0, 1.0, 1.0));
} }
void SkyManager::setCloudsOpacity(float opacity) void SkyManager::setCloudsOpacity(float opacity)
{ {
if (!mCreated) return;
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity)); mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity));
} }
@ -927,11 +935,13 @@ void SkyManager::setThunder(const float factor)
void SkyManager::setMasserFade(const float fade) void SkyManager::setMasserFade(const float fade)
{ {
if (!mCreated) return;
mMasser->setVisibility(fade); mMasser->setVisibility(fade);
} }
void SkyManager::setSecundaFade(const float fade) void SkyManager::setSecundaFade(const float fade)
{ {
if (!mCreated) return;
mSecunda->setVisibility(fade); mSecunda->setVisibility(fade);
} }

@ -7,7 +7,8 @@
#include "terrainmaterial.hpp" #include "terrainmaterial.hpp"
#include "terrain.hpp" #include "terrain.hpp"
#include "renderconst.hpp" #include "renderconst.hpp"
#include "shadows.hpp"
#include <components/settings/settings.hpp>
using namespace Ogre; using namespace Ogre;
@ -16,8 +17,8 @@ namespace MWRender
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
TerrainManager::TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& evn) : TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& evn) :
mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)) mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend)
{ {
TerrainMaterialGeneratorPtr matGen; TerrainMaterialGeneratorPtr matGen;
@ -48,9 +49,19 @@ namespace MWRender
mActiveProfile->setLayerSpecularMappingEnabled(false); mActiveProfile->setLayerSpecularMappingEnabled(false);
mActiveProfile->setLayerNormalMappingEnabled(false); mActiveProfile->setLayerNormalMappingEnabled(false);
mActiveProfile->setLayerParallaxMappingEnabled(false); mActiveProfile->setLayerParallaxMappingEnabled(false);
mActiveProfile->setReceiveDynamicShadowsEnabled(false);
//composite maps lead to a drastic reduction in loading time so are bool shadows = Settings::Manager::getBool("enabled", "Shadows");
mActiveProfile->setReceiveDynamicShadowsEnabled(shadows);
mActiveProfile->setReceiveDynamicShadowsDepth(shadows);
if (Settings::Manager::getBool("split", "Shadows"))
mActiveProfile->setReceiveDynamicShadowsPSSM(mRendering->getShadows()->getPSSMSetup());
else
mActiveProfile->setReceiveDynamicShadowsPSSM(0);
mActiveProfile->setShadowFar(mRendering->getShadows()->getShadowFar());
mActiveProfile->setShadowFadeStart(mRendering->getShadows()->getFadeStart());
//composite maps lead to a drastic increase in loading time so are
//disabled //disabled
mActiveProfile->setCompositeMapEnabled(false); mActiveProfile->setCompositeMapEnabled(false);

@ -24,7 +24,7 @@ namespace MWRender{
*/ */
class TerrainManager{ class TerrainManager{
public: public:
TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& env); TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& env);
virtual ~TerrainManager(); virtual ~TerrainManager();
void setDiffuse(const Ogre::ColourValue& diffuse); void setDiffuse(const Ogre::ColourValue& diffuse);
@ -37,6 +37,7 @@ namespace MWRender{
Ogre::TerrainGroup mTerrainGroup; Ogre::TerrainGroup mTerrainGroup;
const MWWorld::Environment& mEnvironment; const MWWorld::Environment& mEnvironment;
RenderingManager* mRendering;
Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile; Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile;

@ -86,6 +86,7 @@ namespace Ogre
, mPSSM(0) , mPSSM(0)
, mDepthShadows(false) , mDepthShadows(false)
, mLowLodShadows(false) , mLowLodShadows(false)
, mShadowFar(1300)
{ {
} }
@ -101,6 +102,24 @@ namespace Ogre
terrain->_setNormalMapRequired(true); terrain->_setNormalMapRequired(true);
terrain->_setLightMapRequired(mLightmapEnabled, true); terrain->_setLightMapRequired(mLightmapEnabled, true);
terrain->_setCompositeMapRequired(mCompositeMapEnabled); terrain->_setCompositeMapRequired(mCompositeMapEnabled);
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setShadowFar(float far)
{
if (mShadowFar != far)
{
mShadowFar = far;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setShadowFadeStart(float fadestart)
{
if (mShadowFadeStart != fadestart)
{
mShadowFadeStart = fadestart;
mParent->_markChanged();
}
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setLayerNormalMappingEnabled(bool enabled) void TerrainMaterialGeneratorB::SM2Profile::setLayerNormalMappingEnabled(bool enabled)
@ -462,6 +481,7 @@ namespace Ogre
StringUtil::StrStreamType sourceStr; StringUtil::StrStreamType sourceStr;
generateFragmentProgramSource(prof, terrain, tt, sourceStr); generateFragmentProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str()); ret->setSource(sourceStr.str());
ret->load(); ret->load();
defaultFpParams(prof, terrain, tt, ret); defaultFpParams(prof, terrain, tt, ret);
@ -533,8 +553,8 @@ namespace Ogre
GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i); GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
params->setNamedAutoConstant("depthRange" + StringConverter::toString(i), //params->setNamedAutoConstant("depthRange" + StringConverter::toString(i),
GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i); //GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i);
} }
} }
} }
@ -567,6 +587,7 @@ namespace Ogre
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
{ {
params->setNamedConstant("shadowFar_fadeStart", Vector4(prof->mShadowFar, prof->mShadowFadeStart * prof->mShadowFar, 0, 0));
uint numTextures = 1; uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM()) if (prof->getReceiveDynamicShadowsPSSM())
{ {
@ -732,7 +753,7 @@ namespace Ogre
ret->unload(); ret->unload();
} }
ret->setParameter("profiles", "vs_3_0 vs_2_0 arbvp1"); ret->setParameter("profiles", "vs_3_0 vs_2_0 vp40 arbvp1");
ret->setParameter("entry_point", "main_vp"); ret->setParameter("entry_point", "main_vp");
return ret; return ret;
@ -790,9 +811,9 @@ namespace Ogre
outStream << outStream <<
"out float4 oPos : POSITION,\n" "out float4 oPos : POSITION,\n"
"out float4 oPosObj : TEXCOORD0 \n"; "out float4 oPosObj : COLOR \n";
uint texCoordSet = 1; uint texCoordSet = 0;
outStream << outStream <<
", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n"; ", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n";
@ -818,8 +839,8 @@ namespace Ogre
if (fog) if (fog)
{ {
outStream << outStream <<
", uniform float4 fogParams\n" ", uniform float4 fogParams\n";
", out float fogVal : COLOR\n"; //", out float fogVal : COLOR\n";
} }
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
@ -831,7 +852,7 @@ namespace Ogre
if (texCoordSet > 8) if (texCoordSet > 8)
{ {
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"Requested options require too many texture coordinate sets! Try reducing the number of layers.", "Requested options require too many texture coordinate sets! Try reducing the number of layers. requested: " + StringConverter::toString(texCoordSet),
__FUNCTION__); __FUNCTION__);
} }
@ -917,9 +938,9 @@ namespace Ogre
outStream << outStream <<
"void main_fp(\n" "void main_fp(\n"
"float4 position : TEXCOORD0,\n"; "float4 position : COLOR,\n";
uint texCoordSet = 1; uint texCoordSet = 0;
outStream << outStream <<
"float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n"; "float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n";
@ -948,8 +969,8 @@ namespace Ogre
if (fog) if (fog)
{ {
outStream << outStream <<
"uniform float3 fogColour, \n" "uniform float3 fogColour, \n";
"float fogVal : COLOR,\n"; //"float fogVal : COLOR,\n";
} }
uint currentSamplerIdx = 0; uint currentSamplerIdx = 0;
@ -1046,6 +1067,7 @@ namespace Ogre
" float4 outputCol;\n" " float4 outputCol;\n"
" float shadow = 1.0;\n" " float shadow = 1.0;\n"
" float2 uv = uvMisc.xy;\n" " float2 uv = uvMisc.xy;\n"
" float fogVal = position.w; \n"
// base colour // base colour
" outputCol = float4(0,0,0,1);\n"; " outputCol = float4(0,0,0,1);\n";
@ -1257,13 +1279,15 @@ namespace Ogre
if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR)
{ {
outStream << outStream <<
" fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n"; " float fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n";
} }
else else
{ {
outStream << outStream <<
" fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n"; " float fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n";
} }
outStream <<
" oPosObj.w = fogVal; \n";
} }
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
@ -1364,7 +1388,7 @@ namespace Ogre
outStream << outStream <<
"// Simple PCF \n" "// Simple PCF \n"
"// Number of samples in one dimension (square for total samples) \n" "// Number of samples in one dimension (square for total samples) \n"
"#define NUM_SHADOW_SAMPLES_1D 2.0 \n" "#define NUM_SHADOW_SAMPLES_1D 1.0 \n"
"#define SHADOW_FILTER_SCALE 1 \n" "#define SHADOW_FILTER_SCALE 1 \n"
"#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n" "#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n"
@ -1377,27 +1401,17 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
"float calcDepthShadow(sampler2D shadowMap, float4 uv, float invShadowMapSize) \n" "float calcDepthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n"
"{ \n"
" // 4-sample PCF \n"
" float shadow = 0.0; \n"
" float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n"
" for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n"
" for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n"
" { \n" " { \n"
" float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n" " shadowMapPos = shadowMapPos / shadowMapPos.w; \n"
" // manually project and assign derivatives \n" " float2 uv = shadowMapPos.xy; \n"
" // to avoid gradient issues inside loops \n" " float3 o = float3(offset, -offset.x) * 0.3f; \n"
" newUV = newUV / newUV.w; \n" " // Note: We using 2x2 PCF. Good enough and is alot faster. \n"
" float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n" " float c = (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.xy).r) ? 1 : 0; // top left \n"
" if (depth >= 1 || depth >= uv.z)\n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.xy).r) ? 1 : 0; // bottom right \n"
" shadow += 1.0;\n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.zy).r) ? 1 : 0; // bottom left \n"
" } \n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.zy).r) ? 1 : 0; // top right \n"
" return c / 4; \n"
" shadow /= SHADOW_SAMPLES; \n"
" return shadow; \n"
" } \n"; " } \n";
} }
else else
@ -1436,7 +1450,7 @@ namespace Ogre
{ {
outStream << "\n "; outStream << "\n ";
for (uint i = 0; i < numTextures; ++i) for (uint i = 0; i < numTextures; ++i)
outStream << "float invShadowmapSize" << i << ", "; outStream << "float2 invShadowmapSize" << i << ", ";
} }
outStream << "\n" outStream << "\n"
" float4 pssmSplitPoints, float camDepth) \n" " float4 pssmSplitPoints, float camDepth) \n"
@ -1458,7 +1472,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
" shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << "); \n"; " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << ".xy); \n";
} }
else else
{ {
@ -1520,8 +1534,8 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
// make linear // make linear
outStream << //outStream <<
"oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n"; // "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n";
} }
} }
@ -1538,6 +1552,8 @@ namespace Ogre
// in semantics & params // in semantics & params
uint numTextures = 1; uint numTextures = 1;
outStream <<
", uniform float4 shadowFar_fadeStart \n";
if (prof->getReceiveDynamicShadowsPSSM()) if (prof->getReceiveDynamicShadowsPSSM())
{ {
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
@ -1554,7 +1570,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
", uniform float inverseShadowmapSize" << i << " \n"; ", uniform float4 inverseShadowmapSize" << i << " \n";
} }
} }
@ -1589,7 +1605,7 @@ namespace Ogre
{ {
outStream << "\n "; outStream << "\n ";
for (uint i = 0; i < numTextures; ++i) for (uint i = 0; i < numTextures; ++i)
outStream << "inverseShadowmapSize" << i << ", "; outStream << "inverseShadowmapSize" << i << ".xy, ";
} }
outStream << "\n" << outStream << "\n" <<
" pssmSplitPoints, camDepth);\n"; " pssmSplitPoints, camDepth);\n";
@ -1600,7 +1616,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
" float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0);"; " float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0.xy);";
} }
else else
{ {
@ -1610,6 +1626,10 @@ namespace Ogre
} }
outStream << outStream <<
" float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n"
" float fade = 1-((uvMisc.z - shadowFar_fadeStart.y) / fadeRange); \n"
" rtshadow = (uvMisc.z > shadowFar_fadeStart.x) ? 1 : ((uvMisc.z > shadowFar_fadeStart.y) ? 1-((1-rtshadow)*fade) : rtshadow); \n"
" rtshadow = (1-(1-rtshadow)*0.6); \n" // make the shadow a little less intensive
" shadow = min(shadow, rtshadow);\n"; " shadow = min(shadow, rtshadow);\n";
} }

@ -73,6 +73,9 @@ namespace Ogre
void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain); void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain);
void requestOptions(Terrain* terrain); void requestOptions(Terrain* terrain);
void setShadowFar(float far);
void setShadowFadeStart(float fadestart);
/** Whether to support normal mapping per layer in the shader (default true). /** Whether to support normal mapping per layer in the shader (default true).
*/ */
bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; } bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; }
@ -245,6 +248,8 @@ namespace Ogre
bool mDepthShadows; bool mDepthShadows;
bool mLowLodShadows; bool mLowLodShadows;
bool mSM3Available; bool mSM3Available;
float mShadowFar;
float mShadowFadeStart;
bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const; bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const;

@ -31,6 +31,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mWater = mSceneManager->createEntity("water"); mWater = mSceneManager->createEntity("water");
mWater->setVisibilityFlags(RV_Water); mWater->setVisibilityFlags(RV_Water);
mWater->setRenderQueueGroup(RQG_Water); mWater->setRenderQueueGroup(RQG_Water);
mWater->setCastShadows(false);
mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water")
+ RV_Statics * Settings::Manager::getBool("reflect statics", "Water") + RV_Statics * Settings::Manager::getBool("reflect statics", "Water")
@ -42,6 +43,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
mWaterNode->setPosition(0, mTop, 0); mWaterNode->setPosition(0, mTop, 0);
mReflectionCamera = mSceneManager->createCamera("ReflectionCamera");
if(!(cell->data.flags & cell->Interior)) if(!(cell->data.flags & cell->Interior))
{ {
mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY)); mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY));
@ -51,17 +54,20 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
// Create rendertarget for reflection // Create rendertarget for reflection
int rttsize = Settings::Manager::getInt("rtt size", "Water"); int rttsize = Settings::Manager::getInt("rtt size", "Water");
TexturePtr tex;
if (Settings::Manager::getBool("shader", "Water")) if (Settings::Manager::getBool("shader", "Water"))
{ {
TexturePtr tex = TextureManager::getSingleton().createManual("WaterReflection", tex = TextureManager::getSingleton().createManual("WaterReflection",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET);
RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
Viewport* vp = rtt->addViewport(mCamera); Viewport* vp = rtt->addViewport(mReflectionCamera);
vp->setOverlaysEnabled(false); vp->setOverlaysEnabled(false);
vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f));
vp->setShadowsEnabled(false); vp->setShadowsEnabled(false);
vp->setVisibilityMask( mVisibilityFlags ); vp->setVisibilityMask( mVisibilityFlags );
// use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain)
//vp->setMaterialScheme("Fallback");
rtt->addListener(this); rtt->addListener(this);
rtt->setActive(true); rtt->setActive(true);
@ -74,6 +80,55 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mWater->setMaterial(mMaterial); mWater->setMaterial(mMaterial);
mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water");
// ----------------------------------------------------------------------------------------------
// ---------------------------------- reflection debug overlay ----------------------------------
// ----------------------------------------------------------------------------------------------
/*
if (Settings::Manager::getBool("shader", "Water"))
{
OverlayManager& mgr = OverlayManager::getSingleton();
Overlay* overlay;
// destroy if already exists
if (overlay = mgr.getByName("ReflectionDebugOverlay"))
mgr.destroy(overlay);
overlay = mgr.create("ReflectionDebugOverlay");
if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture"))
MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture");
MaterialPtr debugMat = MaterialManager::getSingleton().create(
"Ogre/ReflectionDebugTexture",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName());
t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
OverlayContainer* debugPanel;
// destroy container if exists
try
{
if (debugPanel =
static_cast<OverlayContainer*>(
mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel"
)))
mgr.destroyOverlayElement(debugPanel);
}
catch (Ogre::Exception&) {}
debugPanel = (OverlayContainer*)
(OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel"));
debugPanel->_setPosition(0, 0.55);
debugPanel->_setDimensions(0.3, 0.3);
debugPanel->setMaterialName(debugMat->getName());
debugPanel->show();
overlay->add2D(debugPanel);
overlay->show();
}
*/
} }
void Water::setActive(bool active) void Water::setActive(bool active)
@ -162,6 +217,12 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
{ {
mReflectionCamera->setOrientation(mCamera->getDerivedOrientation());
mReflectionCamera->setPosition(mCamera->getDerivedPosition());
mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance());
mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance());
mReflectionCamera->setAspectRatio(mCamera->getAspectRatio());
mReflectionCamera->setFOVy(mCamera->getFOVy());
if (evt.source == mReflectionTarget) if (evt.source == mReflectionTarget)
{ {
mWater->setVisible(false); mWater->setVisible(false);
@ -174,8 +235,8 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
mSky->setSkyPosition(pos); mSky->setSkyPosition(pos);
mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f);
mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop));
mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop));
} }
} }
@ -187,8 +248,8 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
{ {
mSky->resetSkyPosition(); mSky->resetSkyPosition();
mSky->scaleSky(1); mSky->scaleSky(1);
mCamera->disableReflection(); mReflectionCamera->disableCustomNearClipPlane();
mCamera->disableCustomNearClipPlane(); mReflectionCamera->disableReflection();
} }
} }

@ -39,6 +39,8 @@ namespace MWRender {
void createMaterial(); void createMaterial();
Ogre::MaterialPtr mMaterial; Ogre::MaterialPtr mMaterial;
Ogre::Camera* mReflectionCamera;
Ogre::RenderTarget* mReflectionTarget; Ogre::RenderTarget* mReflectionTarget;
bool mUnderwaterEffect; bool mUnderwaterEffect;

@ -291,6 +291,42 @@ void NIFLoader::createMaterial(const String &name,
else else
warn("Unhandled alpha setting for texture " + texName); warn("Unhandled alpha setting for texture " + texName);
} }
else
{
material->getTechnique(0)->setShadowCasterMaterial("depth_shadow_caster_noalpha");
}
}
if (Settings::Manager::getBool("enabled", "Shadows"))
{
bool split = Settings::Manager::getBool("split", "Shadows");
const int numsplits = 3;
for (int i = 0; i < (split ? numsplits : 1); ++i)
{
TextureUnitState* tu = material->getTechnique(0)->getPass(0)->createTextureUnitState();
tu->setName("shadowMap" + StringConverter::toString(i));
tu->setContentType(TextureUnitState::CONTENT_SHADOW);
tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
tu->setTextureBorderColour(ColourValue::White);
}
}
if (Settings::Manager::getBool("shaders", "Objects"))
{
material->getTechnique(0)->getPass(0)->setVertexProgram("main_vp");
material->getTechnique(0)->getPass(0)->setFragmentProgram("main_fp");
}
// Create a fallback technique without shadows and without mrt
Technique* tech2 = material->createTechnique();
tech2->setSchemeName("Fallback");
Pass* pass2 = tech2->createPass();
pass2->createTextureUnitState(texName);
pass2->setVertexColourTracking(TVC_DIFFUSE);
if (Settings::Manager::getBool("shaders", "Objects"))
{
pass2->setVertexProgram("main_fallback_vp");
pass2->setFragmentProgram("main_fallback_fp");
} }
// Add material bells and whistles // Add material bells and whistles
@ -299,151 +335,6 @@ void NIFLoader::createMaterial(const String &name,
material->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha); material->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha);
material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]); material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]);
material->setShininess(glossiness); material->setShininess(glossiness);
if (Settings::Manager::getBool("shaders", "Objects"))
{
bool mrt = Settings::Manager::getBool("shader", "Water");
// Create shader for the material
// vertex
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
HighLevelGpuProgramPtr vertex;
if (mgr.getByName("main_vp").isNull())
{
vertex = mgr.createProgram("main_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
vertex->setParameter("profiles", "vs_4_0 vs_2_x vp40 arbvp1");
vertex->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream;
outStream <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" float4 normal : NORMAL, \n"
" float4 colour : COLOR, \n"
" in float2 uv : TEXCOORD0, \n"
" out float2 oUV : TEXCOORD0, \n"
" out float4 oPosition : POSITION, \n"
" out float4 oPositionObjSpace : TEXCOORD1, \n"
" out float4 oNormal : TEXCOORD2, \n"
" out float oDepth : TEXCOORD3, \n"
" out float4 oVertexColour : TEXCOORD4, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oVertexColour = colour; \n"
" oUV = uv; \n"
" oNormal = normal; \n"
" oPosition = mul( worldViewProj, position ); \n"
" oDepth = oPosition.z; \n"
" oPositionObjSpace = position; \n"
"}";
vertex->setSource(outStream.str());
vertex->load();
vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
}
else
vertex = mgr.getByName("main_vp");
material->getTechnique(0)->getPass(0)->setVertexProgram(vertex->getName());
// the number of lights to support.
// when rendering an object, OGRE automatically picks the lights that are
// closest to the object being rendered. unfortunately this mechanism does
// not work perfectly for objects batched together (they will all use the same
// lights). to work around this, we are simply pushing the maximum number
// of lights here in order to minimize disappearing lights.
int num_lights = Settings::Manager::getInt("num lights", "Objects");
// fragment
HighLevelGpuProgramPtr fragment;
if (mgr.getByName("main_fp").isNull())
{
fragment = mgr.createProgram("main_fp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
fragment->setParameter("profiles", "ps_4_0 ps_2_x fp40 arbfp1");
fragment->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType outStream;
outStream <<
"void main_fp( \n"
" in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n"
" uniform sampler2D texture : TEXUNIT0, \n"
" float4 positionObjSpace : TEXCOORD1, \n"
" float4 normal : TEXCOORD2, \n"
" float iDepth : TEXCOORD3, \n"
" float4 vertexColour : TEXCOORD4, \n"
" uniform float4 fogColour, \n"
" uniform float4 fogParams, \n";
if (mrt) outStream <<
" out float4 oColor1 : COLOR1, \n"
" uniform float far, \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" uniform float4 lightDiffuse"<<i<<", \n"
" uniform float4 lightPositionObjSpace"<<i<<", \n"
" uniform float4 lightAttenuation"<<i<<", \n";
}
outStream <<
" uniform float4 lightAmbient, \n"
" uniform float4 ambient, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" float4 tex = tex2D(texture, uv); \n"
" float d; \n"
" float attn; \n"
" float3 lightColour = float3(0, 0, 0); \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" float3 lightDir"<<i<<" = lightPositionObjSpace"<<i<<".xyz - (positionObjSpace.xyz * lightPositionObjSpace"<<i<<".w); \n"
// pre-multiply light color with attenuation factor
" d = length( lightDir"<<i<<" ); \n"
" attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
" lightDiffuse"<<i<<" *= attn; \n"
" lightColour.xyz += lit(dot(normalize(lightDir"<<i<<"), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
}
outStream <<
" float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n"
" float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n"
" oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour, fogValue); \n"
" oColor.a = tex.a * diffuse.a * vertexColour.a; \n";
if (mrt) outStream <<
" oColor1 = float4(iDepth / far, 0, 0, (oColor.a == 1)); \n"; // only write to MRT if alpha is 1
outStream <<
"}";
fragment->setSource(outStream.str());
fragment->load();
for (int i=0; i<num_lights; ++i)
{
fragment->getDefaultParameters()->setNamedAutoConstant("lightPositionObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i);
fragment->getDefaultParameters()->setNamedAutoConstant("lightDiffuse"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i);
fragment->getDefaultParameters()->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i);
}
fragment->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
if (mrt)
fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
}
else
fragment = mgr.getByName("main_fp");
material->getTechnique(0)->getPass(0)->setFragmentProgram(fragment->getName());
}
} }
// Takes a name and adds a unique part to it. This is just used to // Takes a name and adds a unique part to it. This is just used to

@ -11,3 +11,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.cg "${OpenMW_BINARY_DIR}/
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.cg "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.cg "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.material "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.material" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.material "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.material" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.compositor "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.compositor" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.compositor "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.compositor" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shadows/depthshadowcaster.material "${OpenMW_BINARY_DIR}/resources/shadows/depthshadowcaster.material" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shadows/depthshadowcaster.cg "${OpenMW_BINARY_DIR}/resources/shadows/depthshadowcaster.cg" COPYONLY)

@ -18,6 +18,32 @@ anisotropy = 4
# Number of texture mipmaps to generate # Number of texture mipmaps to generate
num mipmaps = 5 num mipmaps = 5
[Shadows]
# Shadows are only supported when object shaders are on!
enabled = false
# Split the shadow maps, allows for a larger shadow distance
# Warning: enabling this will cause some terrain textures to disappear due to
# hitting the texture unit limit of the terrain material
split = false
# Increasing shadow distance will lower the shadow quality.
# Uses "shadow distance" or "split shadow distance" depending on "split" setting.
shadow distance = 1300
# This one shouldn't be too low, otherwise you'll see artifacts. Use at least 2x max viewing distance.
split shadow distance = 14000
# Size of the shadow textures, higher means higher quality
texture size = 1024
# Turn on/off various shadow casters
actor shadows = true
misc shadows = true
statics shadows = true
# Fraction of the total shadow distance after which the shadow starts to fade out
fade start = 0.8
[HUD] [HUD]
# FPS counter # FPS counter
# 0: not visible # 0: not visible
@ -64,15 +90,10 @@ num lights = 8
shader = true shader = true
rtt size = 512 rtt size = 512
reflect terrain = true reflect terrain = true
reflect statics = false reflect statics = false
reflect small statics = false reflect small statics = false
reflect actors = true reflect actors = true
reflect misc = false reflect misc = false
# Enable underwater effect. It is not resource intensive, so only disable it if you have problems. # Enable underwater effect. It is not resource intensive, so only disable it if you have problems.

@ -0,0 +1,51 @@
void main_vp(
float4 position : POSITION,
float2 uv : TEXCOORD0,
out float4 oPosition : POSITION,
out float2 oDepth : TEXCOORD0,
out float2 oUv : TEXCOORD1,
uniform float4x4 wvpMat)
{
// this is the view space position
oPosition = mul(wvpMat, position);
// depth info for the fragment.
oDepth.x = oPosition.z;
oDepth.y = oPosition.w;
// clamp z to zero. seem to do the trick. :-/
oPosition.z = max(oPosition.z, 0);
oUv = uv;
}
void main_fp(
float2 depth : TEXCOORD0,
float2 uv : TEXCOORD1,
uniform sampler2D texture1 : register(s0),
out float4 oColour : COLOR)
{
float finalDepth = depth.x / depth.y;
// use alpha channel of the first texture
float alpha = tex2D(texture1, uv).a;
// discard if alpha is less than 0.5
clip((alpha >= 0.5) ? 1 : -1);
oColour = float4(finalDepth, finalDepth, finalDepth, 1);
}
void main_fp_noalpha(
float2 depth : TEXCOORD0,
float2 uv : TEXCOORD1,
out float4 oColour : COLOR)
{
float finalDepth = depth.x / depth.y;
oColour = float4(finalDepth, finalDepth, finalDepth, 1);
}

@ -0,0 +1,67 @@
vertex_program depth_shadow_caster_vs cg
{
source depthshadowcaster.cg
profiles vs_1_1 arbvp1
entry_point main_vp
default_params
{
param_named_auto wvpMat worldviewproj_matrix
}
}
fragment_program depth_shadow_caster_ps cg
{
source depthshadowcaster.cg
profiles ps_2_0 arbfp1
entry_point main_fp
default_params
{
}
}
fragment_program depth_shadow_caster_ps_noalpha cg
{
source depthshadowcaster.cg
profiles ps_2_0 arbfp1
entry_point main_fp_noalpha
default_params
{
}
}
material depth_shadow_caster
{
technique
{
pass
{
vertex_program_ref depth_shadow_caster_vs
{
}
fragment_program_ref depth_shadow_caster_ps
{
}
}
}
}
material depth_shadow_caster_noalpha
{
technique
{
pass
{
vertex_program_ref depth_shadow_caster_vs
{
}
fragment_program_ref depth_shadow_caster_ps_noalpha
{
}
}
}
}

@ -92,7 +92,7 @@ material Water
} }
technique technique
{ {
scheme Map scheme Fallback
pass pass
{ {
cull_hardware none cull_hardware none

Loading…
Cancel
Save