diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d8aefaaa0..15660ade5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -107,6 +107,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); + sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); applyCompositors(); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 4c8f06030..89d895358 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -69,31 +69,6 @@ namespace MWRender mMaterial->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); - createPass(0, terrain); - - return Ogre::MaterialManager::getSingleton().getByName(matName); - } - - void TerrainMaterial::Profile::setGlobalColourMapEnabled (bool enabled) - { - mGlobalColourMap = enabled; - mParent->_markChanged(); - } - - void TerrainMaterial::Profile::setGlobalColourMap (Ogre::Terrain* terrain, const std::string& name) - { - sh::Factory::getInstance ().setTextureAlias (terrain->getMaterialName () + "_colourMap", name); - } - - int TerrainMaterial::Profile::getLayersPerPass () const - { - return 11; - } - - void TerrainMaterial::Profile::createPass (int index, const Ogre::Terrain* terrain) - { - int layerOffset = index * getLayersPerPass(); - sh::MaterialInstancePass* p = mMaterial->createPass (); p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); @@ -131,11 +106,32 @@ namespace MWRender { sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(i, 0)))); - p->mShaderProperties.setProperty ("blendmap_index_" + Ogre::StringConverter::toString(i), - sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4))))); p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty(new sh::StringValue(getComponent(int((i-1) % 4))))); + sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4)) + "." + getComponent(int((i-1) % 4))))); } + + // shadow + for (uint i = 0; i < 3; ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } + + p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( + Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); + + return Ogre::MaterialManager::getSingleton().getByName(matName); + } + + void TerrainMaterial::Profile::setGlobalColourMapEnabled (bool enabled) + { + mGlobalColourMap = enabled; + mParent->_markChanged(); + } + + void TerrainMaterial::Profile::setGlobalColourMap (Ogre::Terrain* terrain, const std::string& name) + { + sh::Factory::getInstance ().setTextureAlias (terrain->getMaterialName () + "_colourMap", name); } Ogre::MaterialPtr TerrainMaterial::Profile::generateForCompositeMap(const Ogre::Terrain* terrain) @@ -145,7 +141,16 @@ namespace MWRender Ogre::uint8 TerrainMaterial::Profile::getMaxLayers(const Ogre::Terrain* terrain) const { - return 32; + // count the texture units free + Ogre::uint8 freeTextureUnits = 16; + // normalmap + --freeTextureUnits; + // colourmap + --freeTextureUnits; + freeTextureUnits -= 3; // shadow PSSM + + // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) + return static_cast(freeTextureUnits / (1.25f)); } void TerrainMaterial::Profile::updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain) diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index a9f957442..3e31b2a58 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -73,10 +73,6 @@ namespace MWRender bool mGlobalColourMap; - void createPass (int index, const Ogre::Terrain* terrain); - - int getLayersPerPass () const; - }; TerrainMaterial(); diff --git a/extern/shiny b/extern/shiny index a83d479c4..5a9bda601 160000 --- a/extern/shiny +++ b/extern/shiny @@ -1 +1 @@ -Subproject commit a83d479c461feead0356946f841c2c474760f420 +Subproject commit 5a9bda6010413555736479ef03103f764fecb91d diff --git a/files/materials/objects.shader b/files/materials/objects.shader index c343a32b0..eabdb8ca3 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -1,7 +1,5 @@ #include "core.h" -#include "shadows.h" - #define FOG @shGlobalSettingBool(fog) #define MRT @shPropertyNotBool(is_transparent) && @shGlobalSettingBool(mrt_output) @@ -10,6 +8,10 @@ #define SHADOWS_PSSM LIGHTING && @shGlobalSettingBool(shadows_pssm) #define SHADOWS LIGHTING && @shGlobalSettingBool(shadows) +#if SHADOWS || SHADOWS_PSSM +#include "shadows.h" +#endif + #if FOG || MRT || SHADOWS_PSSM #define NEED_DEPTH #endif @@ -110,7 +112,7 @@ shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) - @shForeach(8) + @shForeach(@shGlobalSettingString(num_lights)) shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) @@ -149,32 +151,33 @@ #if LIGHTING float3 normal = normalize(normalPassthrough); - float3 lightDir, diffuse; + float3 lightDir; + float3 diffuse = float3(0,0,0); float d; float3 ambient = materialAmbient.xyz * lightAmbient.xyz; - @shForeach(8) - // shadows only for the first (directional) light -#if @shIterator == 0 - #if SHADOWS + // shadows only for the first (directional) light +#if SHADOWS float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); - #endif - #if SHADOWS_PSSM +#endif +#if SHADOWS_PSSM float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); - #endif +#endif - #if SHADOWS || SHADOWS_PSSM +#if SHADOWS || SHADOWS_PSSM float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; float fade = 1-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); - #endif +#endif - #if !SHADOWS && !SHADOWS_PSSM +#if !SHADOWS && !SHADOWS_PSSM float shadow = 1.0; - #endif #endif + @shForeach(@shGlobalSettingString(num_lights)) + + lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePositionPassthrough.xyz * lightPosObjSpace@shIterator.w); d = length(lightDir); diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 47f81d05d..2b7091838 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,32 +1,70 @@ #include "core.h" +#define IS_FIRST_PASS 1 + #define FOG @shGlobalSettingBool(fog) #define MRT @shGlobalSettingBool(mrt_output) -#define COLOUR_MAP @shPropertyBool(colour_map) +#define LIGHTING @shGlobalSettingBool(lighting) -#define NUM_LAYERS @shPropertyString(num_layers) +#define SHADOWS_PSSM LIGHTING && @shGlobalSettingBool(shadows_pssm) +#define SHADOWS LIGHTING && @shGlobalSettingBool(shadows) +#if SHADOWS || SHADOWS_PSSM +#include "shadows.h" +#endif -#define COMPONENT_0 x -#define COMPONENT_1 y -#define COMPONENT_2 z -#define COMPONENT_3 w +#define COLOUR_MAP @shPropertyBool(colour_map) -#define IS_FIRST_PASS 1 +#define NUM_LAYERS @shPropertyString(num_layers) +#if MRT || FOG || SHADOWS_PSSM +#define NEED_DEPTH 1 +#endif +#if NEED_DEPTH @shAllocatePassthrough(1, depth) +#endif + @shAllocatePassthrough(2, UV) +#if LIGHTING +@shAllocatePassthrough(3, objSpacePosition) +#endif + +#if SHADOWS +@shAllocatePassthrough(4, lightSpacePos0) +#endif +#if SHADOWS_PSSM +@shForeach(3) + @shAllocatePassthrough(4, lightSpacePos@shIterator) +@shEndForeach +#endif + #ifdef SH_VERTEX_SHADER + // ------------------------------------- VERTEX --------------------------------------- + SH_BEGIN_PROGRAM shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) shUniform(float4x4, viewProjMatrix) @shAutoConstant(viewProjMatrix, viewproj_matrix) + shUniform(float2, lodMorph) @shAutoConstant(lodMorph, custom, 1001) + shInput(float2, uv0) + shInput(float2, delta) // lodDelta, lodThreshold + +#if SHADOWS + shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) +#endif + +#if SHADOWS_PSSM + @shForeach(3) + shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) + @shEndForeach +#endif + @shPassthroughVertexOutputs @@ -36,16 +74,54 @@ float4 worldPos = shMatrixMult(worldMatrix, shInputPosition); + // determine whether to apply the LOD morph to this vertex + // we store the deltas against all vertices so we only want to apply + // the morph to the ones which would disappear. The target LOD which is + // being morphed to is stored in lodMorph.y, and the LOD at which + // the vertex should be morphed is stored in uv.w. If we subtract + // the former from the latter, and arrange to only morph if the + // result is negative (it will only be -1 in fact, since after that + // the vertex will never be indexed), we will achieve our aim. + // sign(vertexLOD - targetLOD) == -1 is to morph + float toMorph = -min(0, sign(delta.y - lodMorph.y)); + + // morph + // this assumes XZ terrain alignment + worldPos.y += delta.x * toMorph * lodMorph.x; + shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); +#if NEED_DEPTH @shPassthroughAssign(depth, shOutputPosition.z); +#endif + @shPassthroughAssign(UV, uv0); + +#if LIGHTING + @shPassthroughAssign(objSpacePosition, shInputPosition.xyz); +#endif + +#if SHADOWS + float4 lightSpacePos = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); + @shPassthroughAssign(lightSpacePos0, lightSpacePos); +#endif +#if SHADOWS_PSSM + float4 wPos = shMatrixMult(worldMatrix, shInputPosition); + + float4 lightSpacePos; + @shForeach(3) + lightSpacePos = shMatrixMult(texViewProjMatrix@shIterator, wPos); + @shPassthroughAssign(lightSpacePos@shIterator, lightSpacePos); + @shEndForeach +#endif } #else + // ----------------------------------- FRAGMENT ------------------------------------------ + SH_BEGIN_PROGRAM @@ -55,10 +131,11 @@ shSampler2D(normalMap) // global normal map + @shForeach(@shPropertyString(num_blendmaps)) shSampler2D(blendMap@shIterator) @shEndForeach - + @shForeach(@shPropertyString(num_layers)) shSampler2D(diffuseMap@shIterator) @shEndForeach @@ -76,21 +153,57 @@ #endif +#if LIGHTING + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + @shForeach(@shGlobalSettingString(num_lights)) + shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) + shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) + shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) + @shEndForeach +#endif + + +#if SHADOWS + shSampler2D(shadowMap0) + shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, @shPropertyString(shadowtexture_offset)) +#endif +#if SHADOWS_PSSM + @shForeach(3) + shSampler2D(shadowMap@shIterator) + shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(@shPropertyString(shadowtexture_offset))) + @shEndForeach + shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) +#endif + SH_START_PROGRAM { +#if NEED_DEPTH float depth = @shPassthroughReceive(depth); +#endif + float2 UV = @shPassthroughReceive(UV); +#if LIGHTING + float3 objSpacePosition = @shPassthroughReceive(objSpacePosition); + float3 normal = shSample(normalMap, UV).rgb * 2 - 1; + normal = normalize(normal); +#endif + - // fetch blendmaps + + // Layer calculations @shForeach(@shPropertyString(num_blendmaps)) float4 blendValues@shIterator = shSample(blendMap@shIterator, UV); @shEndForeach - float3 albedo; + float3 albedo = float3(0,0,0); @shForeach(@shPropertyString(num_layers)) @@ -98,9 +211,11 @@ // first layer of first pass doesn't need a blend map albedo = shSample(diffuseMap0, UV * 10).rgb; #else - #define BLEND_AMOUNT blendValues@shPropertyString(blendmap_index_@shIterator).@shPropertyString(blendmap_component_@shIterator) + #define BLEND_AMOUNT blendValues@shPropertyString(blendmap_component_@shIterator) + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, BLEND_AMOUNT); + #endif @shEndForeach @@ -113,6 +228,63 @@ shOutputColour(0).rgb *= albedo; + + + + + // Lighting + +#if LIGHTING + // shadows only for the first (directional) light +#if SHADOWS + float4 lightSpacePos0 = @shPassthroughReceive(lightSpacePos0); + float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); +#endif +#if SHADOWS_PSSM + @shForeach(3) + float4 lightSpacePos@shIterator = @shPassthroughReceive(lightSpacePos@shIterator); + @shEndForeach + + float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depth, pssmSplitPoints); +#endif + +#if SHADOWS || SHADOWS_PSSM + float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; + float fade = 1-((depth - shadowFar_fadeStart.y) / fadeRange); + shadow = (depth > shadowFar_fadeStart.x) ? 1 : ((depth > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); +#endif + +#if !SHADOWS && !SHADOWS_PSSM + float shadow = 1.0; +#endif + + + + float3 lightDir; + float3 diffuse = float3(0,0,0); + float d; + + @shForeach(@shGlobalSettingString(num_lights)) + + lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePosition.xyz * lightPosObjSpace@shIterator.w); + d = length(lightDir); + + + lightDir = normalize(lightDir); + +#if @shIterator == 0 && (SHADOWS || SHADOWS_PSSM) + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow; +#else + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); +#endif + @shEndForeach + + shOutputColour(0).xyz *= (lightAmbient.xyz + diffuse); +#endif + + + + #if FOG float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); diff --git a/files/materials/terrain.shaderset b/files/materials/terrain.shaderset index d31429dbb..4132b8e9c 100644 --- a/files/materials/terrain.shaderset +++ b/files/materials/terrain.shaderset @@ -2,7 +2,7 @@ shader_set terrain_vertex { source terrain.shader type vertex - profiles_cg vs_2_0 arbvp1 + profiles_cg vs_2_0 vp40 arbvp1 profiles_hlsl vs_2_0 } @@ -10,6 +10,6 @@ shader_set terrain_fragment { source terrain.shader type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 profiles_hlsl ps_2_0 }