mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
basic shadows
This commit is contained in:
parent
62908c9ef5
commit
2a4fcf42a3
24 changed files with 953 additions and 219 deletions
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
308
apps/openmw/mwrender/shaderhelper.cpp
Normal file
308
apps/openmw/mwrender/shaderhelper.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
29
apps/openmw/mwrender/shaderhelper.hpp
Normal file
29
apps/openmw/mwrender/shaderhelper.hpp
Normal file
|
@ -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
|
175
apps/openmw/mwrender/shadows.cpp
Normal file
175
apps/openmw/mwrender/shadows.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
39
apps/openmw/mwrender/shadows.hpp
Normal file
39
apps/openmw/mwrender/shadows.hpp
Normal file
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -102,6 +103,24 @@ namespace Ogre
|
||||||
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,28 +1401,18 @@ 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"
|
" { \n"
|
||||||
" // 4-sample PCF \n"
|
" shadowMapPos = shadowMapPos / shadowMapPos.w; \n"
|
||||||
|
" float2 uv = shadowMapPos.xy; \n"
|
||||||
" float shadow = 0.0; \n"
|
" float3 o = float3(offset, -offset.x) * 0.3f; \n"
|
||||||
" float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n"
|
" // Note: We using 2x2 PCF. Good enough and is alot faster. \n"
|
||||||
" for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n"
|
" float c = (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.xy).r) ? 1 : 0; // top left \n"
|
||||||
" for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n"
|
" c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.xy).r) ? 1 : 0; // bottom right \n"
|
||||||
" { \n"
|
" c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.zy).r) ? 1 : 0; // bottom left \n"
|
||||||
" float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n"
|
" c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.zy).r) ? 1 : 0; // top right \n"
|
||||||
" // manually project and assign derivatives \n"
|
" return c / 4; \n"
|
||||||
" // to avoid gradient issues inside loops \n"
|
" } \n";
|
||||||
" newUV = newUV / newUV.w; \n"
|
|
||||||
" float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n"
|
|
||||||
" if (depth >= 1 || depth >= uv.z)\n"
|
|
||||||
" shadow += 1.0;\n"
|
|
||||||
" } \n"
|
|
||||||
|
|
||||||
" shadow /= SHADOW_SAMPLES; \n"
|
|
||||||
|
|
||||||
" return shadow; \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
|
||||||
{
|
{
|
||||||
|
@ -1609,7 +1625,11 @@ 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.
|
||||||
|
|
51
files/shadows/depthshadowcaster.cg
Normal file
51
files/shadows/depthshadowcaster.cg
Normal file
|
@ -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);
|
||||||
|
}
|
67
files/shadows/depthshadowcaster.material
Normal file
67
files/shadows/depthshadowcaster.material
Normal file
|
@ -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…
Reference in a new issue