mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:53:51 +00:00
Add normal, specular & parallax mapping for terrain
This commit is contained in:
parent
9ab8fe1038
commit
69c0bb1723
7 changed files with 251 additions and 29 deletions
|
@ -4,6 +4,8 @@
|
||||||
#include <OgreTechnique.h>
|
#include <OgreTechnique.h>
|
||||||
#include <OgrePass.h>
|
#include <OgrePass.h>
|
||||||
|
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -36,6 +38,8 @@ namespace Terrain
|
||||||
: mShaders(shaders)
|
: mShaders(shaders)
|
||||||
, mShadows(false)
|
, mShadows(false)
|
||||||
, mSplitShadows(false)
|
, mSplitShadows(false)
|
||||||
|
, mNormalMapping(true)
|
||||||
|
, mParallaxMapping(true)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -85,7 +89,7 @@ namespace Terrain
|
||||||
{
|
{
|
||||||
assert(mLayerList.size() == mBlendmapList.size()+1);
|
assert(mLayerList.size() == mBlendmapList.size()+1);
|
||||||
std::vector<Ogre::TexturePtr>::iterator blend = mBlendmapList.begin();
|
std::vector<Ogre::TexturePtr>::iterator blend = mBlendmapList.begin();
|
||||||
for (std::vector<std::string>::iterator layer = mLayerList.begin(); layer != mLayerList.end(); ++layer)
|
for (std::vector<LayerInfo>::iterator layer = mLayerList.begin(); layer != mLayerList.end(); ++layer)
|
||||||
{
|
{
|
||||||
Ogre::Pass* pass = technique->createPass();
|
Ogre::Pass* pass = technique->createPass();
|
||||||
pass->setLightingEnabled(false);
|
pass->setLightingEnabled(false);
|
||||||
|
@ -117,7 +121,7 @@ namespace Terrain
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the actual layer texture on top of the alpha map.
|
// Add the actual layer texture on top of the alpha map.
|
||||||
tus = pass->createTextureUnitState("textures\\" + *layer);
|
tus = pass->createTextureUnitState(layer->mDiffuseMap);
|
||||||
if (!first)
|
if (!first)
|
||||||
tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA,
|
tus->setColourOperationEx(Ogre::LBX_BLEND_DIFFUSE_ALPHA,
|
||||||
Ogre::LBS_TEXTURE,
|
Ogre::LBS_TEXTURE,
|
||||||
|
@ -156,6 +160,10 @@ namespace Terrain
|
||||||
p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(true)));
|
p->mShaderProperties.setProperty ("display_composite_map", sh::makeProperty(new sh::BooleanValue(true)));
|
||||||
p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue("0")));
|
p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue("0")));
|
||||||
p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue("0")));
|
p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue("0")));
|
||||||
|
p->mShaderProperties.setProperty ("normal_map_enabled", sh::makeProperty (new sh::BooleanValue(false)));
|
||||||
|
p->mShaderProperties.setProperty ("parallax_enabled", sh::makeProperty (new sh::BooleanValue(false)));
|
||||||
|
p->mShaderProperties.setProperty ("normal_maps",
|
||||||
|
sh::makeProperty (new sh::IntValue(0)));
|
||||||
|
|
||||||
sh::MaterialInstanceTextureUnit* tex = p->createTextureUnit ("compositeMap");
|
sh::MaterialInstanceTextureUnit* tex = p->createTextureUnit ("compositeMap");
|
||||||
tex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mCompositeMap)));
|
tex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(mCompositeMap)));
|
||||||
|
@ -210,6 +218,11 @@ namespace Terrain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++neededTextureUnits; // layer texture
|
++neededTextureUnits; // layer texture
|
||||||
|
|
||||||
|
// Check if this layer has a normal map
|
||||||
|
if (mNormalMapping && !mLayerList[layerOffset].mNormalMap.empty())
|
||||||
|
++neededTextureUnits; // normal map
|
||||||
|
|
||||||
if (neededTextureUnits <= remainingTextureUnits)
|
if (neededTextureUnits <= remainingTextureUnits)
|
||||||
{
|
{
|
||||||
// We can fit another!
|
// We can fit another!
|
||||||
|
@ -238,6 +251,8 @@ namespace Terrain
|
||||||
|
|
||||||
p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass))));
|
p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass))));
|
||||||
p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures))));
|
p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures))));
|
||||||
|
p->mShaderProperties.setProperty ("normal_map_enabled",
|
||||||
|
sh::makeProperty (new sh::BooleanValue(false)));
|
||||||
|
|
||||||
// blend maps
|
// blend maps
|
||||||
// the index of the first blend map used in this pass
|
// the index of the first blend map used in this pass
|
||||||
|
@ -254,17 +269,39 @@ namespace Terrain
|
||||||
}
|
}
|
||||||
|
|
||||||
// layer maps
|
// layer maps
|
||||||
|
bool anyNormalMaps = false;
|
||||||
|
bool anyParallax = false;
|
||||||
|
size_t normalMaps = 0;
|
||||||
for (int i = 0; i < numLayersInThisPass; ++i)
|
for (int i = 0; i < numLayersInThisPass; ++i)
|
||||||
{
|
{
|
||||||
|
const LayerInfo& layer = mLayerList[layerOffset+i];
|
||||||
|
// diffuse map
|
||||||
sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i));
|
sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i));
|
||||||
diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue("textures\\"+mLayerList[layerOffset+i])));
|
diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(layer.mDiffuseMap)));
|
||||||
|
|
||||||
|
// normal map (optional)
|
||||||
|
bool useNormalMap = mNormalMapping && !mLayerList[layerOffset+i].mNormalMap.empty() && !renderCompositeMap;
|
||||||
|
bool useParallax = useNormalMap && mParallaxMapping && layer.mParallax;
|
||||||
|
if (useNormalMap)
|
||||||
|
{
|
||||||
|
anyNormalMaps = true;
|
||||||
|
anyParallax = anyParallax || useParallax;
|
||||||
|
sh::MaterialInstanceTextureUnit* normalTex = p->createTextureUnit ("normalMap" + Ogre::StringConverter::toString(i));
|
||||||
|
normalTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(layer.mNormalMap)));
|
||||||
|
}
|
||||||
|
p->mShaderProperties.setProperty ("use_normal_map_" + Ogre::StringConverter::toString(i),
|
||||||
|
sh::makeProperty (new sh::BooleanValue(useNormalMap)));
|
||||||
|
p->mShaderProperties.setProperty ("use_parallax_" + Ogre::StringConverter::toString(i),
|
||||||
|
sh::makeProperty (new sh::BooleanValue(useParallax)));
|
||||||
|
boost::hash_combine(normalMaps, useNormalMap);
|
||||||
|
boost::hash_combine(normalMaps, useNormalMap && layer.mParallax);
|
||||||
|
|
||||||
if (i+layerOffset > 0)
|
if (i+layerOffset > 0)
|
||||||
{
|
{
|
||||||
int blendTextureIndex = getBlendmapIndexForLayer(layerOffset+i);
|
int blendTextureIndex = getBlendmapIndexForLayer(layerOffset+i);
|
||||||
std::string blendTextureComponent = getBlendmapComponentForLayer(layerOffset+i);
|
std::string blendTextureComponent = getBlendmapComponentForLayer(layerOffset+i);
|
||||||
p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i),
|
p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i),
|
||||||
sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + blendTextureComponent)));
|
sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + blendTextureComponent)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -274,6 +311,14 @@ namespace Terrain
|
||||||
sh::makeProperty (new sh::StringValue("")));
|
sh::makeProperty (new sh::StringValue("")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p->mShaderProperties.setProperty ("normal_map_enabled",
|
||||||
|
sh::makeProperty (new sh::BooleanValue(anyNormalMaps)));
|
||||||
|
p->mShaderProperties.setProperty ("parallax_enabled",
|
||||||
|
sh::makeProperty (new sh::BooleanValue(anyParallax)));
|
||||||
|
// Since the permutation handler can't handle dynamic property names,
|
||||||
|
// combine normal map settings for all layers into one value
|
||||||
|
p->mShaderProperties.setProperty ("normal_maps",
|
||||||
|
sh::makeProperty (new sh::IntValue(normalMaps)));
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
if (shadows)
|
if (shadows)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <OgreMaterial.h>
|
#include <OgreMaterial.h>
|
||||||
|
|
||||||
|
#include "storage.hpp"
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -15,13 +17,15 @@ namespace Terrain
|
||||||
/// so if this parameter is true, then the supplied blend maps are expected to be packed.
|
/// so if this parameter is true, then the supplied blend maps are expected to be packed.
|
||||||
MaterialGenerator (bool shaders);
|
MaterialGenerator (bool shaders);
|
||||||
|
|
||||||
void setLayerList (const std::vector<std::string>& layerList) { mLayerList = layerList; }
|
void setLayerList (const std::vector<LayerInfo>& layerList) { mLayerList = layerList; }
|
||||||
bool hasLayers() { return mLayerList.size(); }
|
bool hasLayers() { return mLayerList.size(); }
|
||||||
void setBlendmapList (const std::vector<Ogre::TexturePtr>& blendmapList) { mBlendmapList = blendmapList; }
|
void setBlendmapList (const std::vector<Ogre::TexturePtr>& blendmapList) { mBlendmapList = blendmapList; }
|
||||||
const std::vector<Ogre::TexturePtr>& getBlendmapList() { return mBlendmapList; }
|
const std::vector<Ogre::TexturePtr>& getBlendmapList() { return mBlendmapList; }
|
||||||
void setCompositeMap (const std::string& name) { mCompositeMap = name; }
|
void setCompositeMap (const std::string& name) { mCompositeMap = name; }
|
||||||
|
|
||||||
void enableShadows(bool shadows) { mShadows = shadows; }
|
void enableShadows(bool shadows) { mShadows = shadows; }
|
||||||
|
void enableNormalMapping(bool normalMapping) { mNormalMapping = normalMapping; }
|
||||||
|
void enableParallaxMapping(bool parallaxMapping) { mParallaxMapping = parallaxMapping; }
|
||||||
void enableSplitShadows(bool splitShadows) { mSplitShadows = splitShadows; }
|
void enableSplitShadows(bool splitShadows) { mSplitShadows = splitShadows; }
|
||||||
|
|
||||||
/// Creates a material suitable for displaying a chunk of terrain using alpha-blending.
|
/// Creates a material suitable for displaying a chunk of terrain using alpha-blending.
|
||||||
|
@ -43,12 +47,14 @@ namespace Terrain
|
||||||
private:
|
private:
|
||||||
Ogre::MaterialPtr create (Ogre::MaterialPtr mat, bool renderCompositeMap, bool displayCompositeMap);
|
Ogre::MaterialPtr create (Ogre::MaterialPtr mat, bool renderCompositeMap, bool displayCompositeMap);
|
||||||
|
|
||||||
std::vector<std::string> mLayerList;
|
std::vector<LayerInfo> mLayerList;
|
||||||
std::vector<Ogre::TexturePtr> mBlendmapList;
|
std::vector<Ogre::TexturePtr> mBlendmapList;
|
||||||
std::string mCompositeMap;
|
std::string mCompositeMap;
|
||||||
bool mShaders;
|
bool mShaders;
|
||||||
bool mShadows;
|
bool mShadows;
|
||||||
bool mSplitShadows;
|
bool mSplitShadows;
|
||||||
|
bool mNormalMapping;
|
||||||
|
bool mParallaxMapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,7 +371,7 @@ void QuadTreeNode::destroyChunks(bool children)
|
||||||
for (std::vector<Ogre::TexturePtr>::const_iterator it = list.begin(); it != list.end(); ++it)
|
for (std::vector<Ogre::TexturePtr>::const_iterator it = list.begin(); it != list.end(); ++it)
|
||||||
Ogre::TextureManager::getSingleton().remove((*it)->getName());
|
Ogre::TextureManager::getSingleton().remove((*it)->getName());
|
||||||
mMaterialGenerator->setBlendmapList(std::vector<Ogre::TexturePtr>());
|
mMaterialGenerator->setBlendmapList(std::vector<Ogre::TexturePtr>());
|
||||||
mMaterialGenerator->setLayerList(std::vector<std::string>());
|
mMaterialGenerator->setLayerList(std::vector<LayerInfo>());
|
||||||
mMaterialGenerator->setCompositeMap("");
|
mMaterialGenerator->setCompositeMap("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ void QuadTreeNode::ensureLayerInfo()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<Ogre::TexturePtr> blendmaps;
|
std::vector<Ogre::TexturePtr> blendmaps;
|
||||||
std::vector<std::string> layerList;
|
std::vector<LayerInfo> layerList;
|
||||||
mTerrain->getStorage()->getBlendmaps(mSize, mCenter, mTerrain->getShadersEnabled(), blendmaps, layerList);
|
mTerrain->getStorage()->getBlendmaps(mSize, mCenter, mTerrain->getShadersEnabled(), blendmaps, layerList);
|
||||||
|
|
||||||
mMaterialGenerator->setLayerList(layerList);
|
mMaterialGenerator->setLayerList(layerList);
|
||||||
|
@ -427,11 +427,13 @@ void QuadTreeNode::prepareForCompositeMap(Ogre::TRect<float> area)
|
||||||
|
|
||||||
if (mIsDummy)
|
if (mIsDummy)
|
||||||
{
|
{
|
||||||
// TODO - why is this completely black?
|
|
||||||
// TODO - store this default material somewhere instead of creating one for each empty cell
|
// TODO - store this default material somewhere instead of creating one for each empty cell
|
||||||
MaterialGenerator matGen(mTerrain->getShadersEnabled());
|
MaterialGenerator matGen(mTerrain->getShadersEnabled());
|
||||||
std::vector<std::string> layer;
|
std::vector<LayerInfo> layer;
|
||||||
layer.push_back("_land_default.dds");
|
LayerInfo info;
|
||||||
|
info.mDiffuseMap = "textures\\_land_default.dds";
|
||||||
|
info.mParallax = false;
|
||||||
|
layer.push_back(info);
|
||||||
matGen.setLayerList(layer);
|
matGen.setLayerList(layer);
|
||||||
makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT(Ogre::MaterialPtr()));
|
makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT(Ogre::MaterialPtr()));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
#include <OgreTextureManager.h>
|
#include <OgreTextureManager.h>
|
||||||
#include <OgreStringConverter.h>
|
#include <OgreStringConverter.h>
|
||||||
#include <OgreRenderSystem.h>
|
#include <OgreRenderSystem.h>
|
||||||
|
#include <OgreResourceGroupManager.h>
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
|
|
||||||
#include <boost/multi_array.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
@ -302,7 +303,7 @@ namespace Terrain
|
||||||
}
|
}
|
||||||
|
|
||||||
void Storage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter,
|
void Storage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter,
|
||||||
bool pack, std::vector<Ogre::TexturePtr> &blendmaps, std::vector<std::string> &layerList)
|
bool pack, std::vector<Ogre::TexturePtr> &blendmaps, std::vector<LayerInfo> &layerList)
|
||||||
{
|
{
|
||||||
// TODO - blending isn't completely right yet; the blending radius appears to be
|
// TODO - blending isn't completely right yet; the blending radius appears to be
|
||||||
// different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap
|
// different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap
|
||||||
|
@ -336,7 +337,7 @@ namespace Terrain
|
||||||
{
|
{
|
||||||
int size = textureIndicesMap.size();
|
int size = textureIndicesMap.size();
|
||||||
textureIndicesMap[*it] = size;
|
textureIndicesMap[*it] = size;
|
||||||
layerList.push_back(getTextureName(*it));
|
layerList.push_back(getLayerInfo(getTextureName(*it)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int numTextures = textureIndices.size();
|
int numTextures = textureIndices.size();
|
||||||
|
@ -466,5 +467,34 @@ namespace Terrain
|
||||||
return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x];
|
return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LayerInfo Storage::getLayerInfo(const std::string& texture)
|
||||||
|
{
|
||||||
|
// Already have this cached?
|
||||||
|
if (mLayerInfoMap.find(texture) != mLayerInfoMap.end())
|
||||||
|
return mLayerInfoMap[texture];
|
||||||
|
|
||||||
|
LayerInfo info;
|
||||||
|
info.mParallax = false;
|
||||||
|
info.mDiffuseMap = "textures\\" + texture;
|
||||||
|
std::string texture_ = texture;
|
||||||
|
boost::replace_last(texture_, ".", "_nh.");
|
||||||
|
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_))
|
||||||
|
{
|
||||||
|
info.mNormalMap = "textures\\" + texture_;
|
||||||
|
info.mParallax = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture_ = texture;
|
||||||
|
boost::replace_last(texture_, ".", "_n.");
|
||||||
|
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_))
|
||||||
|
info.mNormalMap = "textures\\" + texture_;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLayerInfoMap[texture] = info;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,13 @@
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct LayerInfo
|
||||||
|
{
|
||||||
|
std::string mDiffuseMap;
|
||||||
|
std::string mNormalMap;
|
||||||
|
bool mParallax; // Height info in normal map alpha channel?
|
||||||
|
};
|
||||||
|
|
||||||
/// We keep storage of terrain data abstract here since we need different implementations for game and editor
|
/// We keep storage of terrain data abstract here since we need different implementations for game and editor
|
||||||
class Storage
|
class Storage
|
||||||
{
|
{
|
||||||
|
@ -58,7 +65,7 @@ namespace Terrain
|
||||||
/// @param layerList names of the layer textures used will be written here
|
/// @param layerList names of the layer textures used will be written here
|
||||||
void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack,
|
void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack,
|
||||||
std::vector<Ogre::TexturePtr>& blendmaps,
|
std::vector<Ogre::TexturePtr>& blendmaps,
|
||||||
std::vector<std::string>& layerList);
|
std::vector<LayerInfo>& layerList);
|
||||||
|
|
||||||
float getHeightAt (const Ogre::Vector3& worldPos);
|
float getHeightAt (const Ogre::Vector3& worldPos);
|
||||||
|
|
||||||
|
@ -77,6 +84,10 @@ namespace Terrain
|
||||||
UniqueTextureId getVtexIndexAt(int cellX, int cellY,
|
UniqueTextureId getVtexIndexAt(int cellX, int cellY,
|
||||||
int x, int y);
|
int x, int y);
|
||||||
std::string getTextureName (UniqueTextureId id);
|
std::string getTextureName (UniqueTextureId id);
|
||||||
|
|
||||||
|
std::map<std::string, LayerInfo> mLayerInfoMap;
|
||||||
|
|
||||||
|
LayerInfo getLayerInfo(const std::string& texture);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,7 +327,6 @@
|
||||||
shInput(float4, lightResult)
|
shInput(float4, lightResult)
|
||||||
shInput(float3, directionalResult)
|
shInput(float3, directionalResult)
|
||||||
#else
|
#else
|
||||||
shUniform(float, lightCount) @shAutoConstant(lightCount, light_count)
|
|
||||||
shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights))
|
shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights))
|
||||||
shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights))
|
shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights))
|
||||||
shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights))
|
shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights))
|
||||||
|
|
|
@ -27,6 +27,16 @@
|
||||||
|
|
||||||
#define COMPOSITE_MAP @shPropertyBool(display_composite_map)
|
#define COMPOSITE_MAP @shPropertyBool(display_composite_map)
|
||||||
|
|
||||||
|
#define NORMAL_MAP @shPropertyBool(normal_map_enabled)
|
||||||
|
#define PARALLAX @shPropertyBool(parallax_enabled)
|
||||||
|
|
||||||
|
#define VERTEX_LIGHTING (!NORMAL_MAP)
|
||||||
|
|
||||||
|
#define PARALLAX_SCALE 0.04
|
||||||
|
#define PARALLAX_BIAS -0.02
|
||||||
|
|
||||||
|
// This is just for the permutation handler
|
||||||
|
#define NORMAL_MAPS @shPropertyString(normal_maps)
|
||||||
|
|
||||||
#if NEED_DEPTH
|
#if NEED_DEPTH
|
||||||
@shAllocatePassthrough(1, depth)
|
@shAllocatePassthrough(1, depth)
|
||||||
|
@ -37,8 +47,13 @@
|
||||||
@shAllocatePassthrough(3, worldPos)
|
@shAllocatePassthrough(3, worldPos)
|
||||||
|
|
||||||
#if LIGHTING
|
#if LIGHTING
|
||||||
|
@shAllocatePassthrough(3, normalPassthrough)
|
||||||
|
#if VERTEX_LIGHTING
|
||||||
@shAllocatePassthrough(3, lightResult)
|
@shAllocatePassthrough(3, lightResult)
|
||||||
@shAllocatePassthrough(3, directionalResult)
|
@shAllocatePassthrough(3, directionalResult)
|
||||||
|
#else
|
||||||
|
@shAllocatePassthrough(3, colourPassthrough)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SHADOWS
|
#if SHADOWS
|
||||||
@shAllocatePassthrough(4, lightSpacePos0)
|
@shAllocatePassthrough(4, lightSpacePos0)
|
||||||
|
@ -69,11 +84,12 @@
|
||||||
shNormalInput(float4)
|
shNormalInput(float4)
|
||||||
shColourInput(float4)
|
shColourInput(float4)
|
||||||
|
|
||||||
shUniform(float, lightCount) @shAutoConstant(lightCount, light_count)
|
#if VERTEX_LIGHTING
|
||||||
shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights))
|
shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights))
|
||||||
shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights))
|
shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights))
|
||||||
shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights))
|
shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights))
|
||||||
shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour)
|
shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SHADOWS
|
#if SHADOWS
|
||||||
shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix)
|
shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix)
|
||||||
|
@ -122,6 +138,13 @@
|
||||||
|
|
||||||
@shPassthroughAssign(worldPos, worldPos.xyz);
|
@shPassthroughAssign(worldPos, worldPos.xyz);
|
||||||
|
|
||||||
|
#if LIGHTING
|
||||||
|
@shPassthroughAssign(normalPassthrough, normal.xyz);
|
||||||
|
#endif
|
||||||
|
#if LIGHTING && !VERTEX_LIGHTING
|
||||||
|
@shPassthroughAssign(colourPassthrough, colour.xyz);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LIGHTING
|
#if LIGHTING
|
||||||
|
|
||||||
#if SHADOWS
|
#if SHADOWS
|
||||||
|
@ -139,6 +162,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if VERTEX_LIGHTING
|
||||||
// Lighting
|
// Lighting
|
||||||
float3 lightDir;
|
float3 lightDir;
|
||||||
float d;
|
float d;
|
||||||
|
@ -164,6 +188,7 @@
|
||||||
|
|
||||||
@shPassthroughAssign(lightResult, lightResult);
|
@shPassthroughAssign(lightResult, lightResult);
|
||||||
@shPassthroughAssign(directionalResult, directionalResult);
|
@shPassthroughAssign(directionalResult, directionalResult);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -189,6 +214,9 @@
|
||||||
|
|
||||||
@shForeach(@shPropertyString(num_layers))
|
@shForeach(@shPropertyString(num_layers))
|
||||||
shSampler2D(diffuseMap@shIterator)
|
shSampler2D(diffuseMap@shIterator)
|
||||||
|
#if @shPropertyBool(use_normal_map_@shIterator)
|
||||||
|
shSampler2D(normalMap@shIterator)
|
||||||
|
#endif
|
||||||
@shEndForeach
|
@shEndForeach
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -201,6 +229,15 @@
|
||||||
@shPassthroughFragmentInputs
|
@shPassthroughFragmentInputs
|
||||||
|
|
||||||
#if LIGHTING
|
#if LIGHTING
|
||||||
|
|
||||||
|
#if !VERTEX_LIGHTING
|
||||||
|
shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_array, @shGlobalSettingString(num_lights))
|
||||||
|
shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights))
|
||||||
|
shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights))
|
||||||
|
shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour)
|
||||||
|
shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SHADOWS
|
#if SHADOWS
|
||||||
shSampler2D(shadowMap0)
|
shSampler2D(shadowMap0)
|
||||||
shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, @shPropertyString(shadowtexture_offset))
|
shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, @shPropertyString(shadowtexture_offset))
|
||||||
|
@ -220,13 +257,21 @@
|
||||||
|
|
||||||
#if (UNDERWATER) || (FOG)
|
#if (UNDERWATER) || (FOG)
|
||||||
shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix)
|
shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix)
|
||||||
shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UNDERWATER
|
#if UNDERWATER
|
||||||
shUniform(float, waterLevel) @shSharedParameter(waterLevel)
|
shUniform(float, waterLevel) @shSharedParameter(waterLevel)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// For specular
|
||||||
|
#if LIGHTING
|
||||||
|
shUniform(float3, lightSpec0) @shAutoConstant(lightSpec0, light_specular_colour, 0)
|
||||||
|
shUniform(float3, lightPos0) @shAutoConstant(lightPos0, light_position, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position)
|
||||||
|
|
||||||
SH_START_PROGRAM
|
SH_START_PROGRAM
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -238,12 +283,32 @@
|
||||||
|
|
||||||
float3 worldPos = @shPassthroughReceive(worldPos);
|
float3 worldPos = @shPassthroughReceive(worldPos);
|
||||||
|
|
||||||
|
#if LIGHTING
|
||||||
|
float3 normal = @shPassthroughReceive(normalPassthrough);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LIGHTING && !VERTEX_LIGHTING
|
||||||
|
|
||||||
|
#if NORMAL_MAP
|
||||||
|
// derive the tangent space basis
|
||||||
|
float3 tangent = float3(1,0, 0);
|
||||||
|
|
||||||
|
float3 binormal = normalize(cross(tangent, normal));
|
||||||
|
tangent = normalize(cross(normal, binormal)); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal
|
||||||
|
|
||||||
|
// derive final matrix
|
||||||
|
float3x3 tbn = float3x3(tangent, binormal, normal);
|
||||||
|
#if SH_GLSL
|
||||||
|
tbn = transpose(tbn);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if UNDERWATER
|
#if UNDERWATER
|
||||||
float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel);
|
float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if !IS_FIRST_PASS
|
#if !IS_FIRST_PASS
|
||||||
// Opacity the previous passes should have, i.e. 1 - (opacity of this pass)
|
// Opacity the previous passes should have, i.e. 1 - (opacity of this pass)
|
||||||
float previousAlpha = 1.f;
|
float previousAlpha = 1.f;
|
||||||
|
@ -252,6 +317,8 @@ float previousAlpha = 1.f;
|
||||||
|
|
||||||
shOutputColour(0) = float4(1,1,1,1);
|
shOutputColour(0) = float4(1,1,1,1);
|
||||||
|
|
||||||
|
float3 TSnormal = float3(0,0,1);
|
||||||
|
|
||||||
#if COMPOSITE_MAP
|
#if COMPOSITE_MAP
|
||||||
shOutputColour(0).xyz = shSample(compositeMap, UV).xyz;
|
shOutputColour(0).xyz = shSample(compositeMap, UV).xyz;
|
||||||
#else
|
#else
|
||||||
|
@ -266,38 +333,89 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
|
||||||
@shEndForeach
|
@shEndForeach
|
||||||
|
|
||||||
|
|
||||||
float3 albedo = float3(0,0,0);
|
float4 albedo = float4(0,0,0,1);
|
||||||
|
|
||||||
float2 layerUV = UV * 16;
|
float2 layerUV = UV * 16;
|
||||||
|
float2 thisLayerUV;
|
||||||
|
float4 normalTex;
|
||||||
|
|
||||||
|
float3 eyeDir = normalize(cameraPos.xyz - worldPos);
|
||||||
|
#if PARALLAX
|
||||||
|
float3 TSeyeDir = normalize(shMatrixMult(tbn, eyeDir));
|
||||||
|
#endif
|
||||||
|
|
||||||
@shForeach(@shPropertyString(num_layers))
|
@shForeach(@shPropertyString(num_layers))
|
||||||
|
#if @shPropertyBool(use_normal_map_@shIterator)
|
||||||
|
normalTex = shSample(normalMap@shIterator, thisLayerUV);
|
||||||
|
#if @shIterator == 0 && IS_FIRST_PASS
|
||||||
|
TSnormal = normalize(normalTex.xyz * 2 - 1);
|
||||||
|
#else
|
||||||
|
TSnormal = shLerp(TSnormal, normalTex.xyz * 2 - 1, blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
thisLayerUV = layerUV;
|
||||||
|
// required to play nicely with the tangents
|
||||||
|
thisLayerUV.y *= -1;
|
||||||
|
#if @shPropertyBool(use_parallax_@shIterator)
|
||||||
|
thisLayerUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS );
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IS_FIRST_PASS
|
#if IS_FIRST_PASS
|
||||||
#if @shIterator == 0
|
#if @shIterator == 0
|
||||||
// first layer of first pass is the base layer and doesn't need a blend map
|
// first layer of first pass is the base layer and doesn't need a blend map
|
||||||
albedo = shSample(diffuseMap0, layerUV).rgb;
|
albedo = shSample(diffuseMap0, layerUV);
|
||||||
#else
|
#else
|
||||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, layerUV).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, thisLayerUV), blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if @shIterator == 0
|
#if @shIterator == 0
|
||||||
albedo = shSample(diffuseMap@shIterator, layerUV).rgb, blendValues@shPropertyString(blendmap_component_@shIterator);
|
albedo = shSample(diffuseMap@shIterator, layerUV);
|
||||||
#else
|
#else
|
||||||
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, layerUV).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
|
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, thisLayerUV), blendValues@shPropertyString(blendmap_component_@shIterator));
|
||||||
#endif
|
#endif
|
||||||
previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator);
|
previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@shEndForeach
|
@shEndForeach
|
||||||
|
|
||||||
shOutputColour(0).rgb *= albedo;
|
shOutputColour(0).rgb *= albedo.xyz;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LIGHTING
|
#if LIGHTING
|
||||||
|
|
||||||
|
#if VERTEX_LIGHTING
|
||||||
// Lighting
|
// Lighting
|
||||||
float3 lightResult = @shPassthroughReceive(lightResult);
|
float3 lightResult = @shPassthroughReceive(lightResult);
|
||||||
float3 directionalResult = @shPassthroughReceive(directionalResult);
|
float3 directionalResult = @shPassthroughReceive(directionalResult);
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if NORMAL_MAP
|
||||||
|
normal = normalize (shMatrixMult( transpose(tbn), TSnormal ));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float3 colour = @shPassthroughReceive(colourPassthrough);
|
||||||
|
float3 lightDir;
|
||||||
|
float d;
|
||||||
|
float3 lightResult = float3(0,0,0);
|
||||||
|
@shForeach(@shGlobalSettingString(num_lights))
|
||||||
|
lightDir = lightPosition[@shIterator].xyz - (worldPos * lightPosition[@shIterator].w);
|
||||||
|
d = length(lightDir);
|
||||||
|
lightDir = normalize(lightDir);
|
||||||
|
|
||||||
|
lightResult.xyz += lightDiffuse[@shIterator].xyz
|
||||||
|
* shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d)))
|
||||||
|
* max(dot(normal.xyz, lightDir), 0);
|
||||||
|
#if @shIterator == 0
|
||||||
|
float3 directionalResult = lightResult.xyz;
|
||||||
|
#endif
|
||||||
|
@shEndForeach
|
||||||
|
lightResult.xyz += lightAmbient.xyz;
|
||||||
|
lightResult.xyz *= colour.xyz;
|
||||||
|
directionalResult.xyz *= colour.xyz;
|
||||||
|
#endif
|
||||||
|
|
||||||
// shadows only for the first (directional) light
|
// shadows only for the first (directional) light
|
||||||
#if SHADOWS
|
#if SHADOWS
|
||||||
|
@ -325,6 +443,17 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
|
||||||
shOutputColour(0).xyz *= (lightResult - directionalResult * (1.0-shadow));
|
shOutputColour(0).xyz *= (lightResult - directionalResult * (1.0-shadow));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LIGHTING && !COMPOSITE_MAP
|
||||||
|
// Specular
|
||||||
|
float3 light0Dir = normalize(lightPos0.xyz);
|
||||||
|
|
||||||
|
float NdotL = max(dot(normal, light0Dir), 0);
|
||||||
|
float3 halfVec = normalize (light0Dir + eyeDir);
|
||||||
|
|
||||||
|
float3 specular = pow(max(dot(normal, halfVec), 0), 32) * lightSpec0;
|
||||||
|
shOutputColour(0).xyz += specular * (1.f-albedo.a) * shadow;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if FOG
|
#if FOG
|
||||||
float fogValue = shSaturate((depth - fogParams.y) * fogParams.w);
|
float fogValue = shSaturate((depth - fogParams.y) * fogParams.w);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue