diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index f8551a3fd..d7c42efee 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -4,6 +4,21 @@ #include +namespace +{ + Ogre::String getComponent (int num) + { + if (num == 0) + return "x"; + else if (num == 1) + return "y"; + else if (num == 2) + return "z"; + else + return "w"; + } +} + namespace MWRender { @@ -54,7 +69,7 @@ namespace MWRender mMaterial->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); - createPass(); + createPass(0, terrain); return Ogre::MaterialManager::getSingleton().getByName(matName); } @@ -72,10 +87,10 @@ namespace MWRender int TerrainMaterial::Profile::getLayersPerPass () const { - return 10; + return 12; } - void TerrainMaterial::Profile::createPass (int index) + void TerrainMaterial::Profile::createPass (int index, const Ogre::Terrain* terrain) { int layerOffset = index * getLayersPerPass(); @@ -86,8 +101,41 @@ namespace MWRender p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); + // global colour map sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); - colourMap->setProperty ("texture_alias", sh::makeProperty(mMaterial->getName() + "_colourMap")); + colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); + colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + // global normal map + sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); + normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); + normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + uint maxLayers = getMaxLayers(terrain); + uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); + uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); + + p->mShaderProperties.setProperty ("num_layers", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numLayers)))); + p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); + + // blend maps + for (uint i = 0; i < numBlendTextures; ++i) + { + sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); + blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(i)))); + blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + } + + // layer maps + for (uint i = 0; i < numLayers; ++i) + { + 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))))); + } } Ogre::MaterialPtr TerrainMaterial::Profile::generateForCompositeMap(const Ogre::Terrain* terrain) @@ -111,7 +159,7 @@ namespace MWRender void TerrainMaterial::Profile::requestOptions(Ogre::Terrain* terrain) { terrain->_setMorphRequired(true); - terrain->_setNormalMapRequired(false); + terrain->_setNormalMapRequired(true); // global normal map terrain->_setLightMapRequired(false); terrain->_setCompositeMapRequired(false); } diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index 2ee0224fd..a9f957442 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -73,7 +73,7 @@ namespace MWRender bool mGlobalColourMap; - void createPass (int index=0); + void createPass (int index, const Ogre::Terrain* terrain); int getLayersPerPass () const; diff --git a/extern/shiny b/extern/shiny index 5cf02ac0c..a83d479c4 160000 --- a/extern/shiny +++ b/extern/shiny @@ -1 +1 @@ -Subproject commit 5cf02ac0c39115fcf7f69eea7a79c9c6ad7dbd71 +Subproject commit a83d479c461feead0356946f841c2c474760f420 diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index bb776d691..34b52caf6 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -5,6 +5,17 @@ #define COLOUR_MAP @shPropertyBool(colour_map) +#define NUM_LAYERS @shPropertyString(num_layers) + + +#define COMPONENT_0 x +#define COMPONENT_1 y +#define COMPONENT_2 z +#define COMPONENT_3 w + +#define IS_FIRST_PASS 1 + + @shAllocatePassthrough(1, depth) @shAllocatePassthrough(2, UV) @@ -41,6 +52,16 @@ #if COLOUR_MAP shSampler2D(colourMap) #endif + + shSampler2D(normalMap) // global normal map + +@shForeach(@shPropertyString(num_blendmaps)) + shSampler2D(blendMap@shIterator) +@shEndForeach + +@shForeach(@shPropertyString(num_layers)) + shSampler2D(diffuseMap@shIterator) +@shEndForeach #if FOG shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) @@ -62,11 +83,36 @@ float depth = @shPassthroughReceive(depth); float2 UV = @shPassthroughReceive(UV); - shOutputColour(0) = float4(1,0,0,1); + float3 normal = shSample(normalMap, UV).rgb * 2 - 1; + + // fetch blendmaps +@shForeach(@shPropertyString(num_blendmaps)) + float4 blendValues@shIterator = shSample(blendMap@shIterator, UV); +@shEndForeach + + float blendAmount; + float3 albedo; +@shForeach(@shPropertyString(num_layers)) + + +#if IS_FIRST_PASS == 1 && @shIterator == 0 + // first layer of first pass doesn't need a blend map + albedo = shSample(diffuseMap0, UV * 5).rgb; +#else + blendAmount = blendValues@shPropertyString(blendmap_index_@shIterator).@shPropertyString(blendmap_component_@shIterator); + + albedo += shSample(diffuseMap@shIterator, UV * 5).rgb * blendAmount; +#endif +@shEndForeach + + shOutputColour(0) = float4(1,1,1,1); #if COLOUR_MAP shOutputColour(0).rgb *= shSample(colourMap, UV).rgb; #endif + + shOutputColour(0).rgb *= albedo; + #if FOG float fogValue = shSaturate((depth - fogParams.y) * fogParams.w);