Deferred Shading Terrain Material Generator
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Deferred Shading Terrain Material Generator
Hi everyone!
I recently switched to Deferred Shading for my game, and I was also using terrains. Obviously, the default TerrainMaterialGenerator gave an ugly green lime and random black dots, well, garbage all the way . After spending a few days figuring out what needs to be done, and how to do it, I spend 3 days fixing the damn normal calculation, as it needs to be done in eye-space and not object space, and surprisingly there is almost nothing on the web that shows this... Luckily enough, I came across a small GLSL code that showed how to do it. After playing around a bit, I could finally have this working properly
Limitations:
-There are visible seams when shadows are enabled
- Lightmap isn't supported
- Only Cg shader (HLSL conversion would be easy)
- Composite map and low LOD shader not extensively tested
Other than that, it works quite fine:
You can find the generator code and a few other details on the Wiki :
http://www.ogre3d.org/tikiwiki/tiki-ind ... +Generator
I'd be interested if someone have ideas on how to fix shadows seams (at least sub-page seams), as LOD seams can be avoided in most situations.
Have fun
I recently switched to Deferred Shading for my game, and I was also using terrains. Obviously, the default TerrainMaterialGenerator gave an ugly green lime and random black dots, well, garbage all the way . After spending a few days figuring out what needs to be done, and how to do it, I spend 3 days fixing the damn normal calculation, as it needs to be done in eye-space and not object space, and surprisingly there is almost nothing on the web that shows this... Luckily enough, I came across a small GLSL code that showed how to do it. After playing around a bit, I could finally have this working properly
Limitations:
-There are visible seams when shadows are enabled
- Lightmap isn't supported
- Only Cg shader (HLSL conversion would be easy)
- Composite map and low LOD shader not extensively tested
Other than that, it works quite fine:
You can find the generator code and a few other details on the Wiki :
http://www.ogre3d.org/tikiwiki/tiki-ind ... +Generator
I'd be interested if someone have ideas on how to fix shadows seams (at least sub-page seams), as LOD seams can be avoided in most situations.
Have fun
Last edited by Xplodwild on Mon Aug 06, 2012 2:10 pm, edited 1 time in total.
- Mind Calamity
- Ogre Magi
- Posts: 1255
- Joined: Sat Dec 25, 2010 2:55 pm
- Location: Macedonia
- x 81
Re: Deferred Shading Terrain Material Generator
I'm not a wiki expert, but I created a new page under "Snippets/Materials".
And I fixed up some misspellings and made the code parts collapsible.
Thanks for posting this.
And I fixed up some misspellings and made the code parts collapsible.
Thanks for posting this.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
- Nauk
- Gnoll
- Posts: 653
- Joined: Thu May 11, 2006 9:12 pm
- Location: Bavaria
- x 36
- Contact:
Re: Deferred Shading Terrain Material Generator
Nice work and thanks for sharing back
ARTIFEX TERRA 3D - Artist-friendly, free and easy WYSIWYG realtime outdoor scene Editor & Painter
New loader now with Ogre::Terrain support: Addons for Artifex on SourceForge
MOC - Minimal Ogre Collision & Mousepicking
Simple TerrainMaterialGenerator for the use of standard Ogre material with Ogre::Terrain
Support me on Patreon
-
- Greenskin
- Posts: 122
- Joined: Fri Jan 20, 2012 6:44 pm
- Location: Russia,Moscow
- x 1
Re: Deferred Shading Terrain Material Generator
Thanks for posting
Performance is very good,but shadows not working for me.
I'm using caelum on scene.
On standart shadow generator shadows working a fine.
What you can say?
Performance is very good,but shadows not working for me.
I'm using caelum on scene.
On standart shadow generator shadows working a fine.
What you can say?
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Re: Deferred Shading Terrain Material Generator
Did you enable shadows in the TerrainGlobalOptions?
Make sure your LightExtrusionDistance are right also. I had a couple of issues with them mis-set by default. Check the sample.
Make sure your LightExtrusionDistance are right also. I had a couple of issues with them mis-set by default. Check the sample.
-
- Greenskin
- Posts: 122
- Joined: Fri Jan 20, 2012 6:44 pm
- Location: Russia,Moscow
- x 1
Re: Deferred Shading Terrain Material Generator
of course enabled.Xplodwild wrote:Did you enable shadows in the TerrainGlobalOptions?
Ok,later i will say result
Make sure your LightExtrusionDistance are right also.
Thanks for reply
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Hi,
i cannot get your code to work. Its compiling, but the Terrain is always totaly lit up (as shown in the attachment). Maybe i use it the wrong way. Looks like full ambient light (but no ambient enabled at all).
To setup the textures i do this:
Is it the right way to setup the normal maps as second texture name?
Ogre-Log:
i cannot get your code to work. Its compiling, but the Terrain is always totaly lit up (as shown in the attachment). Maybe i use it the wrong way. Looks like full ambient light (but no ambient enabled at all).
To setup the textures i do this:
Code: Select all
Ogre::Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
defaultimp.terrainSize = mTerrainGroup->getTerrainSize();
defaultimp.worldSize = mWorldSizePerTerrainSize * defaultimp.terrainSize;
defaultimp.inputScale = DEFAULT_IMPORT_IMAGE_SCALING;
defaultimp.minBatchSize = DEFAULT_IMPORT_MIN_BATCHSIZE;
defaultimp.maxBatchSize = DEFAULT_IMPORT_MAX_BATCHSIZE;
defaultimp.layerList.resize(3);
defaultimp.layerList[0].worldSize = 100;
defaultimp.layerList[0].textureNames.push_back("splatting1.png");
defaultimp.layerList[0].textureNames.push_back("testnormalmap.png");
defaultimp.layerList[1].worldSize = 30;
defaultimp.layerList[1].textureNames.push_back("splatting2.png");
defaultimp.layerList[1].textureNames.push_back("testnormalmap.png");
defaultimp.layerList[2].worldSize = 200;
defaultimp.layerList[2].textureNames.push_back("splatting3.png");
defaultimp.layerList[2].textureNames.push_back("testnormalmap.png");
Ogre-Log:
Code: Select all
17:05:36: Creating resource group General
17:05:36: Creating resource group Internal
17:05:36: Creating resource group Autodetect
17:05:36: SceneManagerFactory for type 'DefaultSceneManager' registered.
17:05:36: Registering ResourceManager for type Material
17:05:36: Registering ResourceManager for type Mesh
17:05:36: Registering ResourceManager for type Skeleton
17:05:36: MovableObjectFactory for type 'ParticleSystem' registered.
17:05:36: OverlayElementFactory for type Panel registered.
17:05:36: OverlayElementFactory for type BorderPanel registered.
17:05:36: OverlayElementFactory for type TextArea registered.
17:05:36: Registering ResourceManager for type Font
17:05:36: ArchiveFactory for archive type FileSystem registered.
17:05:36: ArchiveFactory for archive type Zip registered.
17:05:36: ArchiveFactory for archive type EmbeddedZip registered.
17:05:36: DDS codec registering
17:05:36: FreeImage version: 3.15.3
17:05:36: This program uses FreeImage, a free, open source image library supporting all common bitmap formats. See http://freeimage.sourceforge.net for details
17:05:36: Supported formats: bmp,ico,jpg,jif,jpeg,jpe,jng,koa,iff,lbm,mng,pbm,pbm,pcd,pcx,pgm,pgm,png,ppm,ppm,ras,tga,targa,tif,tiff,wap,wbmp,wbm,psd,cut,xbm,xpm,gif,hdr,g3,sgi,exr,j2k,j2c,jp2,pfm,pct,pict,pic,3fr,arw,bay,bmq,cap,cine,cr2,crw,cs1,dc2,dcr,drf,dsc,dng,erf,fff,ia,iiq,k25,kc2,kdc,mdc,mef,mos,mrw,nef,nrw,orf,pef,ptx,pxn,qtk,raf,raw,rdc,rw2,rwl,rwz,sr2,srf,srw,sti
17:05:36: Registering ResourceManager for type HighLevelGpuProgram
17:05:36: Registering ResourceManager for type Compositor
17:05:36: MovableObjectFactory for type 'Entity' registered.
17:05:36: MovableObjectFactory for type 'Light' registered.
17:05:36: MovableObjectFactory for type 'BillboardSet' registered.
17:05:36: MovableObjectFactory for type 'ManualObject' registered.
17:05:36: MovableObjectFactory for type 'BillboardChain' registered.
17:05:36: MovableObjectFactory for type 'RibbonTrail' registered.
17:05:36: Loading library .\RenderSystem_Direct3D9_d
17:05:36: Installing plugin: D3D9 RenderSystem
17:05:36: D3D9 : Direct3D9 Rendering Subsystem created.
17:05:36: D3D9: Driver Detection Starts
17:05:36: D3D9: Driver Detection Ends
17:05:36: Plugin successfully installed
17:05:36: Loading library .\RenderSystem_GL_d
17:05:36: Installing plugin: GL RenderSystem
17:05:36: OpenGL Rendering Subsystem created.
17:05:36: Plugin successfully installed
17:05:36: Loading library .\Plugin_CgProgramManager_d
17:05:36: Installing plugin: Cg Program Manager
17:05:36: Plugin successfully installed
17:05:36: *-*-* OGRE Initialising
17:05:36: *-*-* Version 1.8.0 (Byatis)
17:05:36: Added resource location 'data/models' of type 'FileSystem' to resource group 'General'
17:05:36: Added resource location 'data/materials/textures' of type 'FileSystem' to resource group 'General'
17:05:36: Added resource location 'data/materials/scripts' of type 'FileSystem' to resource group 'General'
17:05:36: Added resource location 'data/materials/programs' of type 'FileSystem' to resource group 'General'
17:05:36: D3D9 : RenderSystem Option: Allow NVPerfHUD = No
17:05:36: D3D9 : RenderSystem Option: FSAA = 0
17:05:36: D3D9 : RenderSystem Option: Fixed Pipeline Enabled = Yes
17:05:36: D3D9 : RenderSystem Option: Floating-point mode = Fastest
17:05:36: D3D9 : RenderSystem Option: Full Screen = No
17:05:36: D3D9 : RenderSystem Option: Multi device memory hint = Use minimum system memory
17:05:36: D3D9 : RenderSystem Option: Rendering Device = Monitor-1-NVIDIA GeForce GTX 460
17:05:36: D3D9 : RenderSystem Option: Resource Creation Policy = Create on all devices
17:05:36: D3D9 : RenderSystem Option: Use Multihead = Auto
17:05:36: D3D9 : RenderSystem Option: VSync = No
17:05:36: D3D9 : RenderSystem Option: VSync Interval = 1
17:05:36: D3D9 : RenderSystem Option: Video Mode = 640 x 480 @ 16-bit colour
17:05:36: D3D9 : RenderSystem Option: sRGB Gamma Conversion = No
17:05:37: CPU Identifier & Features
17:05:37: -------------------------
17:05:37: * CPU ID: AuthenticAMD: AMD Phenom(tm) II X4 955 Processor
17:05:37: * SSE: yes
17:05:37: * SSE2: yes
17:05:37: * SSE3: yes
17:05:37: * MMX: yes
17:05:37: * MMXEXT: yes
17:05:37: * 3DNOW: yes
17:05:37: * 3DNOWEXT: yes
17:05:37: * CMOV: yes
17:05:37: * TSC: yes
17:05:37: * FPU: yes
17:05:37: * PRO: yes
17:05:37: * HT: no
17:05:37: -------------------------
17:05:37: D3D9 : Subsystem Initialising
17:05:37: Registering ResourceManager for type Texture
17:05:37: Registering ResourceManager for type GpuProgram
17:05:37: ***************************************
17:05:37: *** D3D9 : Subsystem Initialised OK ***
17:05:37: ***************************************
17:05:37: D3D9RenderSystem::_createRenderWindow "QOgreWidget_RenderWindow", 732x781 windowed miscParams: externalWindowHandle=2496594
17:05:37: D3D9 : Created D3D9 Rendering Window 'QOgreWidget_RenderWindow' : 732x781, 32bpp
17:05:37: D3D9 : WARNING - disabling VSync in windowed mode can cause timing issues at lower frame rates, turn VSync on if you observe this problem.
17:05:37: D3D9: Vertex texture format supported - PF_A8R8G8B8
17:05:37: D3D9: Vertex texture format supported - PF_B8G8R8A8
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT16_RGB
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT16_RGBA
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT32_RGB
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT32_RGBA
17:05:37: D3D9: Vertex texture format supported - PF_R8G8B8A8
17:05:37: D3D9: Vertex texture format supported - PF_DEPTH
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT16_R
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT32_R
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT16_GR
17:05:37: D3D9: Vertex texture format supported - PF_FLOAT32_GR
17:05:37: D3D9: Vertex texture format supported - PF_PVRTC_RGB2
17:05:37: D3D9: Vertex texture format supported - PF_PVRTC_RGBA2
17:05:37: D3D9: Vertex texture format supported - PF_PVRTC_RGB4
17:05:37: D3D9: Vertex texture format supported - PF_PVRTC_RGBA4
17:05:37: D3D9: Vertex texture format supported - PF_R8
17:05:37: D3D9: Vertex texture format supported - PF_RG8
17:05:37: RenderSystem capabilities
17:05:37: -------------------------
17:05:37: RenderSystem Name: Direct3D9 Rendering Subsystem
17:05:37: GPU Vendor: nvidia
17:05:37: Device Name: Monitor-1-NVIDIA GeForce GTX 460
17:05:37: Driver Version: 8.17.12.9610
17:05:37: * Fixed function pipeline: yes
17:05:37: * Hardware generation of mipmaps: yes
17:05:37: * Texture blending: yes
17:05:37: * Anisotropic texture filtering: yes
17:05:37: * Dot product texture operation: yes
17:05:37: * Cube mapping: yes
17:05:37: * Hardware stencil buffer: yes
17:05:37: - Stencil depth: 8
17:05:37: - Two sided stencil support: yes
17:05:37: - Wrap stencil values: yes
17:05:37: * Hardware vertex / index buffers: yes
17:05:37: * Vertex programs: yes
17:05:37: * Number of floating-point constants for vertex programs: 256
17:05:37: * Number of integer constants for vertex programs: 16
17:05:37: * Number of boolean constants for vertex programs: 16
17:05:37: * Fragment programs: yes
17:05:37: * Number of floating-point constants for fragment programs: 224
17:05:37: * Number of integer constants for fragment programs: 16
17:05:37: * Number of boolean constants for fragment programs: 16
17:05:37: * Geometry programs: no
17:05:37: * Number of floating-point constants for geometry programs: 0
17:05:37: * Number of integer constants for geometry programs: 0
17:05:37: * Number of boolean constants for geometry programs: 0
17:05:37: * Supported Shader Profiles: hlsl ps_1_1 ps_1_2 ps_1_3 ps_1_4 ps_2_0 ps_2_a ps_2_b ps_2_x ps_3_0 vs_1_1 vs_2_0 vs_2_a vs_2_x vs_3_0
17:05:37: * Texture Compression: yes
17:05:37: - DXT: yes
17:05:37: - VTC: no
17:05:37: - PVRTC: no
17:05:37: * Scissor Rectangle: yes
17:05:37: * Hardware Occlusion Query: yes
17:05:37: * User clip planes: yes
17:05:37: * VET_UBYTE4 vertex element type: yes
17:05:37: * Infinite far plane projection: yes
17:05:37: * Hardware render-to-texture: yes
17:05:37: * Floating point textures: yes
17:05:37: * Non-power-of-two textures: yes
17:05:37: * Volume textures: yes
17:05:37: * Multiple Render Targets: 4
17:05:37: - With different bit depths: yes
17:05:37: * Point Sprites: yes
17:05:37: * Extended point parameters: yes
17:05:37: * Max Point Size: 8192
17:05:37: * Vertex texture fetch: yes
17:05:37: * Number of world matrices: 0
17:05:37: * Number of texture units: 8
17:05:37: * Stencil buffer depth: 8
17:05:37: * Number of vertex blend matrices: 0
17:05:37: - Max vertex textures: 4
17:05:37: - Vertex textures shared: no
17:05:37: * Render to Vertex Buffer : no
17:05:37: * DirectX per stage constants: yes
17:05:37: DefaultWorkQueue('Root') initialising on thread 03BE28D8.
17:05:37: DefaultWorkQueue('Root')::WorkerFunc - thread 03347ED8 starting.
17:05:37: DefaultWorkQueue('Root')::WorkerFunc - thread 03347F48 starting.
17:05:37: DefaultWorkQueue('Root')::WorkerFunc - thread 03348770 starting.
17:05:37: DefaultWorkQueue('Root')::WorkerFunc - thread 007A4858 starting.
17:05:37: Particle Renderer Type 'billboard' registered
17:05:37: Parsing scripts for resource group Autodetect
17:05:37: Finished parsing scripts for resource group Autodetect
17:05:37: Creating resources for group Autodetect
17:05:37: All done
17:05:37: Parsing scripts for resource group General
17:05:37: Parsing script TerrainShader.program
17:05:37: Parsing script Ogre.material
17:05:37: Parsing script Terrain.material
17:05:37: Finished parsing scripts for resource group General
17:05:37: Creating resources for group General
17:05:37: All done
17:05:37: Parsing scripts for resource group Internal
17:05:37: Finished parsing scripts for resource group Internal
17:05:37: Creating resources for group Internal
17:05:37: All done
17:05:37: Mesh: Loading ogrehead.mesh.
17:05:37: Texture: GreenSkin.jpg: Loading 1 faces(PF_R8G8B8,256x256x1) Internal format is PF_X8R8G8B8,256x256x1.
17:05:37: Texture: spheremap.png: Loading 1 faces(PF_R8G8B8,256x256x1) Internal format is PF_X8R8G8B8,256x256x1.
17:05:37: Texture: tusk.jpg: Loading 1 faces(PF_R8G8B8,128x128x1) Internal format is PF_X8R8G8B8,128x128x1.
17:05:37: Terrain created; size=513 minBatch=33 maxBatch=65 treeDepth=4 lodLevels=5 leafLods=2
17:05:38: *** Terrain Fragment Program: OgreTerrain/3163266815/sm2/fp/hlod ***
float4 expand(float4 v)
{
return v * 2 - 1;
}
void main_fp(
float4 position : TEXCOORD0,
out float4 oColor0 : COLOR0,
out float4 oColor1 : COLOR1,
out float4 oColor2 : COLOR2,
uniform float cFarDistance,
uniform float4x4 viewMatrix,
float4 uvMisc : TEXCOORD1,
float4 layerUV0 : TEXCOORD2,
float4 layerUV1 : TEXCOORD3,
uniform sampler2D globalNormal : register(s0)
, uniform sampler2D blendTex0 : register(s1)
, uniform sampler2D difftex0 : register(s2)
, uniform sampler2D normtex0 : register(s3)
, uniform sampler2D difftex1 : register(s4)
, uniform sampler2D normtex1 : register(s5)
, uniform sampler2D difftex2 : register(s6)
, uniform sampler2D normtex2 : register(s7)
)
{
float2 uv = uvMisc.xy;
oColor0 = float4(0,0,0,0);
oColor1 = oColor2 = float4(1,1,1,1);
float3 normal = expand(tex2D(globalNormal, uv));
float3 diffuse = float3(0,0,0);
float specular = 0;
float4 blendTexVal0 = tex2D(blendTex0, uv);
float3 tangent = float3(1, 0, 0);
normal = mul(viewMatrix, float4(normal,0)).xyz;
tangent = mul(viewMatrix, float4(tangent,0)).xyz;
float3 binormal = cross(normal, tangent);
float3x3 TBN = float3x3(tangent, binormal, normal);
float3 TSnormal;
float2 uv0 = layerUV0.xy;
TSnormal = expand(tex2D(normtex0, uv0)).rgb;
oColor1.rgb = TSnormal;
float4 diffuseSpecTex0 = tex2D(difftex0, uv0);
diffuse = diffuseSpecTex0.rgb;
specular = diffuseSpecTex0.a;
float2 uv1 = layerUV0.zw;
TSnormal = expand(tex2D(normtex1, uv1)).rgb;
oColor1.rgb = lerp(oColor1.rgb, TSnormal, blendTexVal0.r);
float4 diffuseSpecTex1 = tex2D(difftex1, uv1);
diffuse = lerp(diffuse, diffuseSpecTex1.rgb, blendTexVal0.r);
specular = lerp(specular, diffuseSpecTex1.a, blendTexVal0.r);
float2 uv2 = layerUV1.xy;
TSnormal = expand(tex2D(normtex2, uv2)).rgb;
oColor1.rgb = lerp(oColor1.rgb, TSnormal, blendTexVal0.g);
float4 diffuseSpecTex2 = tex2D(difftex2, uv2);
diffuse = lerp(diffuse, diffuseSpecTex2.rgb, blendTexVal0.g);
specular = lerp(specular, diffuseSpecTex2.a, blendTexVal0.g);
oColor0.rgb += diffuse;
oColor0.a += specular;
oColor1 = float4(normalize(mul(TSnormal, TBN)), length(position) / cFarDistance);
}
*** ***
17:05:38: Texture: splatting1.png: Loading 1 faces(PF_R8G8B8,1024x1024x1) Internal format is PF_X8R8G8B8,1024x1024x1.
17:05:38: Texture: testnormalmap.png: Loading 1 faces(PF_R8G8B8,1024x1024x1) Internal format is PF_X8R8G8B8,1024x1024x1.
17:05:39: Texture: splatting2.png: Loading 1 faces(PF_R8G8B8,1024x1024x1) Internal format is PF_X8R8G8B8,1024x1024x1.
17:05:39: Texture: splatting3.png: Loading 1 faces(PF_R8G8B8,1024x1024x1) Internal format is PF_X8R8G8B8,1024x1024x1.
- Attachments
-
- terrain.jpg (142.29 KiB) Viewed 7063 times
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Re: Deferred Shading Terrain Material Generator
Do you have lights in your scene at least? How do you set your ambient light? No ambient light set = fully bright if I remember correctly.
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Have a look on the Ogre-Head. Its shaded -> light existing in scene. I set Ambient-Light to (0,0,0). Tested different Lightsources (Spot & Directional). The head is lit as expected but the terrain is always on full light. I m using DirectX as RenderSystem - in my App-Setup im not able to test OpenGL (cause of QT trouble..) - have u tested the shader on Dx?
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Really want to use and tweak your MaterialGenerator but i can't get it running ...
My setup for the terrain is based on the wiki tutorial. I may did anything wrong?
Defines:
Implementation:
My setup for the terrain is based on the wiki tutorial. I may did anything wrong?
Code: Select all
ko::koTerrain::instance()->setupTerrain("test", 513, Ogre::Vector3(0, 0, 0));
ko::koTerrain::instance()->setDirectionalLight(lightd);
ko::koTerrain::instance()->loadTerrain();
Code: Select all
#define DEFAULT_WORLDSIZE_PER_TERRAINSIZE 10.0
#define DEFAULT_TERRAIN_FILENAME_EXTENSION ".terrain"
#define DEFAULT_MAX_PIXELERROR 8
#define DEFAULT_COMPOSITE_MAP_DISTANCE 3000
#define DEFAULT_IMPORT_IMAGE_SCALING 600
#define DEFAULT_IMPORT_MIN_BATCHSIZE 33
#define DEFAULT_IMPORT_MAX_BATCHSIZE 65
Code: Select all
#include "koTerrain.h"
using namespace ko;
koTerrain::koTerrain()
: mWorldSizePerTerrainSize(DEFAULT_WORLDSIZE_PER_TERRAINSIZE),
mTerrainFilenameExtension(DEFAULT_TERRAIN_FILENAME_EXTENSION),
mTerrainGlobals(NULL),
mTerrainGroup(NULL)
{
}
koTerrain::~koTerrain()
{
}
void koTerrain::setDirectionalLight(Ogre::Light* light)
{
if(mTerrainGlobals)
{
mTerrainGlobals->setLightMapDirection(light->getDerivedDirection());
mTerrainGlobals->setCompositeMapAmbient(koOgre::instance()->getScnMgr()->getAmbientLight());
mTerrainGlobals->setCompositeMapDiffuse(light->getDiffuseColour());
}
}
void koTerrain::setTerrainDefaults()
{
if(mTerrainGroup)
{
// Configure default import settings for if we use imported image
Ogre::Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
defaultimp.terrainSize = mTerrainGroup->getTerrainSize();
defaultimp.worldSize = mWorldSizePerTerrainSize * defaultimp.terrainSize;
defaultimp.inputScale = DEFAULT_IMPORT_IMAGE_SCALING;
defaultimp.minBatchSize = DEFAULT_IMPORT_MIN_BATCHSIZE;
defaultimp.maxBatchSize = DEFAULT_IMPORT_MAX_BATCHSIZE;
defaultimp.layerList.resize(3);
defaultimp.layerList[0].worldSize = 100;
defaultimp.layerList[0].textureNames.push_back("splatting1.png");
defaultimp.layerList[0].textureNames.push_back("testnormalmap.png");
defaultimp.layerList[1].worldSize = 30;
defaultimp.layerList[1].textureNames.push_back("splatting2.png");
defaultimp.layerList[1].textureNames.push_back("testnormalmap.png");
defaultimp.layerList[2].worldSize = 200;
defaultimp.layerList[2].textureNames.push_back("splatting3.png");
defaultimp.layerList[2].textureNames.push_back("testnormalmap.png");
}
}
void koTerrain::setupTerrain(Ogre::String terrainFilename, Ogre::uint16 terrainSize, Ogre::Vector3 origin)
{
mTerrainFilename = terrainFilename;
mTerrainGlobals = new Ogre::TerrainGlobalOptions();
mTerrainGroup = new Ogre::TerrainGroup(koOgre::instance()->getScnMgr(),
Ogre::Terrain::ALIGN_X_Z,
terrainSize,
mWorldSizePerTerrainSize * terrainSize);
mTerrainGroup->setFilenameConvention(terrainFilename, mTerrainFilenameExtension);
mTerrainGroup->setOrigin(origin);
mTerrainGlobals->setMaxPixelError(DEFAULT_MAX_PIXELERROR);
mTerrainGlobals->setCompositeMapDistance(DEFAULT_COMPOSITE_MAP_DISTANCE);
// Setup custom material generator
Ogre::koTerrainMaterialGenerator *terrainMaterialGenerator = new Ogre::koTerrainMaterialGenerator();
mTerrainMaterialGenerator.bind( terrainMaterialGenerator );
mTerrainGlobals->setDefaultMaterialGenerator(mTerrainMaterialGenerator);
//mTerrainGlobals->setCastsDynamicShadows(true);
setTerrainDefaults();
mTerrainGroup->defineTerrain(0, 0, 1.0);
}
void koTerrain::loadTerrain()
{
mTerrainGroup->loadAllTerrains(true);
mTerrainGroup->freeTemporaryResources();
}
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Re: Deferred Shading Terrain Material Generator
You need to be running the deferred framework, and it works perfectly in Qt based applications (as my screen shots were taken from my Qt based editor running ogre direct x 9)
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
yeah - thank you that wasnt clear to me... i ll try it again using the framework!
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
- vitefalcon
- Orc
- Posts: 438
- Joined: Tue Sep 18, 2007 5:28 pm
- Location: Seattle, USA
- x 13
Re: Deferred Shading Terrain Material Generator
@Xplodwild: That's a cool piece for work. Congrats
Sorry if this is a dumb question. With deferred rendering isn't it hard to get alpha-blending correct? If so, have you solved this?
Sorry if this is a dumb question. With deferred rendering isn't it hard to get alpha-blending correct? If so, have you solved this?
-
- Halfling
- Posts: 74
- Joined: Wed Aug 10, 2011 2:11 pm
- x 11
Re: Deferred Shading Terrain Material Generator
EDIT: Sorry, misunderstood the questionvitefalcon wrote:@Xplodwild: That's a cool piece for work. Congrats
Sorry if this is a dumb question. With deferred rendering isn't it hard to get alpha-blending correct? If so, have you solved this?
Last edited by Alexiss on Sun Oct 07, 2012 5:43 pm, edited 1 time in total.
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Re: Deferred Shading Terrain Material Generator
Do you mean terrain splatting alpha blending? It's not really alpha blending as you're not rendering each piece in different batch. The material shader "paints" the terrain using lerps to do the alpha blending and transition, thus everything is still opaque and rendered during one pass by the shader using all the texture units needed.vitefalcon wrote:@Xplodwild: That's a cool piece for work. Congrats
Sorry if this is a dumb question. With deferred rendering isn't it hard to get alpha-blending correct? If so, have you solved this?
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Now its working on the Deferred Shading System. But the lighting result isnt as expected. The following screenshot was taken with a single point light (and a small ambient light).
its looking like a spotlight with an big open angle. and the strangest thing is a second lit area (as you can see on the screenshot) which disappears if the camera position changes!!! if i try to load other meshes they lit up as expected (so its something wrong with the materialgenerator thought)!
Code: Select all
light = mSceneMgr->createLight();
light->setAttenuation(3250, 1.0, 0.0014, 0.00007);
light->setType(Ogre::Light::LT_POINT);
light->setDiffuseColour(1, 1, 1);
light->setSpecularColour(0.5, 0.5, 0.5);
light->setPosition(0, 50, 0);
node->attachObject(light);
- Attachments
-
- wrong.jpg (39.24 KiB) Viewed 6834 times
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
[SOLVED] There was a problem with the splatting textures. Caused by a wrong LayerList Size (didnt match the numer of the textures + normaltextures). So the Generator is finally working as expected and i'm now something more familiar with the terrain system .
Thank you for sharing your work!
Thank you for sharing your work!
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Cause i want to use normal-textures aswell as simple diffuse ones i had to adapt the shader Xplodwild presented. If the normal maps are missing the original shader didnt compute correct normals.That results in a dark and unlighted terrain. My version of the shader is looking for an normal-mapping sampler inside the terrain layer and if there is no - it will take the vertex normal to compute the simple diffuse texture layer.
It was easy to integrate.
In "...SM2Profile::ShaderHelperCg::generateFpLayer() and ..SM2Profile::ShaderHelperCg::generateFpLayer()" i am now looking for the normal textures for each layer:
and later on i m using those informations to compute the correct normals:
Coding this stuff i may found another bug in the shader. There is no TSnormal-blending at all. In the FPfooter the TSnormal of the last layer will be applied to the GBuffer-Normal-Texture. This is maybe not the expected result. I m not quite sure if i m right but i think the TSnormal has to be blended with each layer blending factor.
The original code did something like that:
The problem is assignment of the TSnormal. The if-statement after the assignment is unnecessary cause of the oColor1 assignment in the FPfooter:
So this way - the GBuffer-Normal-Texture get the last layer normal but not a right blended one. I fixed this using something like this:
My editor - using the shader - isn't able to change the alpha splatting so far so i could not test if the blending is working correct. But a single diffuse texture layer seems now to reflect all the light (directional light) more correct. Notice - my code is mostly untested.
So my whole shader cpp is now looking like this. I added a few more lines of code beside thouse above. If there is a need i would integrate my fix into the original Shader (similar to this one - simply replace the classname).
If iam completly wrong - be patient im new to that stuff and i didnt know it better!
It was easy to integrate.
In "...SM2Profile::ShaderHelperCg::generateFpLayer() and ..SM2Profile::ShaderHelperCg::generateFpLayer()" i am now looking for the normal textures for each layer:
Code: Select all
std::vector<bool> layerNormalMapping;
layerNormalMapping.resize(terrain->getLayerCount());
for(unsigned int i = 0; i < terrain->getLayerCount(); i++)
{
if(terrain->getLayerTextureName(i, 1).compare("") == 0)
layerNormalMapping[i] = false;
else
layerNormalMapping[i] = true;
}
Code: Select all
if(layerNormalMapping[layer])
{
outStream << " TSnormal2 = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n";
outStream << " TSnormal2 = normalize(TSnormal2);\n";
}
else
{
outStream << " TSnormal2 = normalize(normal);\n";
}
if (layer)
outStream << " TSnormal = lerp(TSnormal, TSnormal2, " << blendWeightStr << ");\n"; // THIS ONE MAY FIXES THE NORMAL-BLENDING-ISSUE
else
outStream << " TSnormal = TSnormal2;\n";
The original code did something like that:
Code: Select all
outStream << " TSnormal = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n";
if (layer)
{
outStream << " oColor1.rgb = lerp(oColor1.rgb, TSnormal, " << blendWeightStr << ");\n";
}
else
{
outStream << " oColor1.rgb = TSnormal;\n";
}
Code: Select all
outStream << " oColor1 = float4(normalize(mul(TSnormal, TBN)), length(position) / cFarDistance);\n" << "}\n";
Code: Select all
outStream << " TSnormal2 = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n";
outStream << " TSnormal2 = normalize(TSnormal2);\n";
outStream << " TSnormal = lerp(TSnormal, TSnormal2, " << blendWeightStr << ");\n";
So my whole shader cpp is now looking like this. I added a few more lines of code beside thouse above. If there is a need i would integrate my fix into the original Shader (similar to this one - simply replace the classname).
If iam completly wrong - be patient im new to that stuff and i didnt know it better!
Code: Select all
#include "koTerrainMaterialGenerator.h"
#include "Terrain/OgreTerrain.h"
#include "OgreMaterialManager.h"
#include "OgreTechnique.h"
#include "OgrePass.h"
#include "OgreTextureUnitState.h"
#include "OgreGpuProgramManager.h"
#include "OgreHighLevelGpuProgramManager.h"
#include "OgreHardwarePixelBuffer.h"
#include "koTerrain.h"
namespace Ogre
{
//---------------------------------------------------------------------
koTerrainMaterialGenerator::koTerrainMaterialGenerator()
{
// define the layers
// We expect terrain textures to have no alpha, so we use the alpha channel
// in the albedo texture to store specular reflection
// similarly we double-up the normal and height (for parallax)
mLayerDecl.samplers.push_back(TerrainLayerSampler("albedo_specular", PF_BYTE_RGBA));
mLayerDecl.samplers.push_back(TerrainLayerSampler("normal_height", PF_BYTE_RGBA));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(0, TLSS_ALBEDO, 0, 3));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(0, TLSS_SPECULAR, 3, 1));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(1, TLSS_NORMAL, 0, 3));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(1, TLSS_HEIGHT, 3, 1));
mProfiles.push_back(OGRE_NEW SM2Profile(this, "SM2", "Profile for rendering on Shader Model 2 capable cards"));
// TODO - check hardware capabilities & use fallbacks if required (more profiles needed)
setActiveProfile("SM2");
}
//---------------------------------------------------------------------
koTerrainMaterialGenerator::~koTerrainMaterialGenerator()
{
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
koTerrainMaterialGenerator::SM2Profile::SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc)
: Profile(parent, name, desc)
, mShaderGen(0)
, mGlobalColourMapEnabled(false)
, mLightmapEnabled(false)
, mCompositeMapEnabled(false)
{
}
//---------------------------------------------------------------------
koTerrainMaterialGenerator::SM2Profile::~SM2Profile()
{
OGRE_DELETE mShaderGen;
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::requestOptions(Terrain* terrain)
{
terrain->_setMorphRequired(true);
terrain->_setNormalMapRequired(true);
terrain->_setLightMapRequired(mLightmapEnabled, true);
terrain->_setCompositeMapRequired(mCompositeMapEnabled);
}
//---------------------------------------------------------------------
bool koTerrainMaterialGenerator::SM2Profile::isVertexCompressionSupported() const
{
return true;
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::setGlobalColourMapEnabled(bool enabled)
{
if (enabled != mGlobalColourMapEnabled)
{
mGlobalColourMapEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::setLightmapEnabled(bool enabled)
{
if (enabled != mLightmapEnabled)
{
mLightmapEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::setCompositeMapEnabled(bool enabled)
{
if (enabled != mCompositeMapEnabled)
{
mCompositeMapEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
uint8 koTerrainMaterialGenerator::SM2Profile::getMaxLayers(const Terrain* terrain) const
{
// count the texture units free
uint8 freeTextureUnits = 16;
// lightmap
--freeTextureUnits;
// normalmap
--freeTextureUnits;
// colourmap
if (terrain->getGlobalColourMapEnabled())
--freeTextureUnits;
// each layer needs 2.25 units (1xdiffusespec, 1xnormalheight, 0.25xblend)
return static_cast<uint8>(freeTextureUnits / 2.25f);
}
//---------------------------------------------------------------------
MaterialPtr koTerrainMaterialGenerator::SM2Profile::generate(const Terrain* terrain)
{
// re-use old material if exists
MaterialPtr mat = terrain->_getMaterial();
if (mat.isNull())
{
MaterialManager& matMgr = MaterialManager::getSingleton();
// it's important that the names are deterministic for a given terrain, so
// use the terrain pointer as an ID
const String& matName = terrain->getMaterialName();
mat = matMgr.getByName(matName);
if (mat.isNull())
{
mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
}
}
// clear everything
mat->removeAllTechniques();
addTechnique(mat, terrain, HIGH_LOD);
// LOD
if(mCompositeMapEnabled)
{
addTechnique(mat, terrain, LOW_LOD);
Material::LodValueList lodValues;
lodValues.push_back(TerrainGlobalOptions::getSingleton().getCompositeMapDistance());
mat->setLodLevels(lodValues);
Technique* lowLodTechnique = mat->getTechnique(1);
lowLodTechnique->setLodIndex(1);
}
updateParams(mat, terrain);
return mat;
}
//---------------------------------------------------------------------
MaterialPtr koTerrainMaterialGenerator::SM2Profile::generateForCompositeMap(const Terrain* terrain)
{
// re-use old material if exists
MaterialPtr mat = terrain->_getCompositeMapMaterial();
if (mat.isNull())
{
MaterialManager& matMgr = MaterialManager::getSingleton();
// it's important that the names are deterministic for a given terrain, so
// use the terrain pointer as an ID
const String& matName = terrain->getMaterialName() + "/comp";
mat = matMgr.getByName(matName);
if (mat.isNull())
{
mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
}
}
// clear everything
mat->removeAllTechniques();
addTechnique(mat, terrain, RENDER_COMPOSITE_MAP);
updateParamsForCompositeMap(mat, terrain);
return mat;
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::addTechnique(
const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt)
{
Technique* tech = mat->createTechnique();
tech->setSchemeName("GBuffer");
// Only supporting one pass
Pass* pass = tech->createPass();
//pass->setName("NO_DEFERRED");
GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
if (!mShaderGen)
{
if (hmgr.isLanguageSupported("cg"))
mShaderGen = OGRE_NEW ShaderHelperCg();
else
{
// todo
}
// check SM3 features
mSM3Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_3_0");
mSM4Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_4_0");
}
HighLevelGpuProgramPtr vprog = mShaderGen->generateVertexProgram(this, terrain, tt);
HighLevelGpuProgramPtr fprog = mShaderGen->generateFragmentProgram(this, terrain, tt);
pass->setVertexProgram(vprog->getName());
pass->setFragmentProgram(fprog->getName());
if (tt == HIGH_LOD || tt == RENDER_COMPOSITE_MAP)
{
// global normal map
TextureUnitState* tu = pass->createTextureUnitState();
tu->setTextureName(terrain->getTerrainNormalMap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
// global colour map
if (terrain->getGlobalColourMapEnabled() && isGlobalColourMapEnabled())
{
tu = pass->createTextureUnitState(terrain->getGlobalColourMap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}
// light map
if (isLightmapEnabled())
{
tu = pass->createTextureUnitState(terrain->getLightmap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}
// blend maps
uint maxLayers = getMaxLayers(terrain);
uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
for (uint i = 0; i < numBlendTextures; ++i)
{
tu = pass->createTextureUnitState(terrain->getBlendTextureName(i));
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}
// layer textures
for (uint i = 0; i < numLayers; ++i)
{
// diffuse / specular
pass->createTextureUnitState(terrain->getLayerTextureName(i, 0));
// normal / height
pass->createTextureUnitState(terrain->getLayerTextureName(i, 1));
}
}
else
{
// LOW_LOD textures
// composite map
TextureUnitState* tu = pass->createTextureUnitState();
tu->setTextureName(terrain->getCompositeMap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
// That's it!
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::updateParams(const MaterialPtr& mat, const Terrain* terrain)
{
mShaderGen->updateParams(this, mat, terrain, false);
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain)
{
mShaderGen->updateParams(this, mat, terrain, true);
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
koTerrainMaterialGenerator::SM2Profile::ShaderHelper::generateVertexProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramPtr ret = createVertexProgram(prof, terrain, tt);
StringUtil::StrStreamType sourceStr;
generateVertexProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str());
ret->load();
defaultVpParams(prof, terrain, tt, ret);
#if OGRE_DEBUG_MODE
LogManager::getSingleton().stream(LML_CRITICAL) << "*** Terrain Vertex Program: "
<< ret->getName() << " ***\n" << ret->getSource() << "\n*** ***";
#endif
return ret;
}
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
koTerrainMaterialGenerator::SM2Profile::ShaderHelper::generateFragmentProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramPtr ret = createFragmentProgram(prof, terrain, tt);
StringUtil::StrStreamType sourceStr;
generateFragmentProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str());
ret->load();
defaultFpParams(prof, terrain, tt, ret);
#if 1
LogManager::getSingleton().stream(LML_CRITICAL) << "*** Terrain Fragment Program: "
<< ret->getName() << " ***\n" << ret->getSource() << "\n*** ***";
#endif
return ret;
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::generateVertexProgramSource(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
generateVpHeader(prof, terrain, tt, outStream);
if (tt != LOW_LOD)
{
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
for (uint i = 0; i < numLayers; ++i)
generateVpLayer(prof, terrain, tt, i, outStream);
}
generateVpFooter(prof, terrain, tt, outStream);
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::generateFragmentProgramSource(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
generateFpHeader(prof, terrain, tt, outStream);
if (tt != LOW_LOD)
{
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
for (uint i = 0; i < numLayers; ++i)
generateFpLayer(prof, terrain, tt, i, outStream);
}
generateFpFooter(prof, terrain, tt, outStream);
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::defaultVpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
{
GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
params->setIgnoreMissingParams(true);
params->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX);
params->setNamedAutoConstant("viewMatrix", GpuProgramParameters::ACT_WORLDVIEW_MATRIX);
params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM,
Terrain::LOD_MORPH_CUSTOM_PARAM);
params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
if (terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP)
{
Matrix4 posIndexToObjectSpace;
terrain->getPointTransform(&posIndexToObjectSpace);
params->setNamedConstant("posIndexToObjectSpace", posIndexToObjectSpace);
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::defaultFpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
{
GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
params->setIgnoreMissingParams(true);
params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
params->setNamedAutoConstant("cFarDistance", Ogre::GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
params->setNamedAutoConstant("viewMatrix", GpuProgramParameters::ACT_WORLDVIEW_MATRIX); // tout sauf Z : VIEW_MATRIX
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::updateParams(
const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap)
{
Pass* p = mat->getTechnique(0)->getPass(0);
if (compositeMap)
{
updateVpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getVertexProgramParameters());
updateFpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getFragmentProgramParameters());
}
else
{
// high lod
updateVpParams(prof, terrain, HIGH_LOD, p->getVertexProgramParameters());
updateFpParams(prof, terrain, HIGH_LOD, p->getFragmentProgramParameters());
if(prof->isCompositeMapEnabled())
{
// low lod
p = mat->getTechnique(1)->getPass(0);
updateVpParams(prof, terrain, LOW_LOD, p->getVertexProgramParameters());
updateFpParams(prof, terrain, LOW_LOD, p->getFragmentProgramParameters());
}
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::updateVpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
{
params->setIgnoreMissingParams(true);
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
uint numUVMul = numLayers / 4;
if (numLayers % 4)
++numUVMul;
for (uint i = 0; i < numUVMul; ++i)
{
Vector4 uvMul(
terrain->getLayerUVMultiplier(i * 4),
terrain->getLayerUVMultiplier(i * 4 + 1),
terrain->getLayerUVMultiplier(i * 4 + 2),
terrain->getLayerUVMultiplier(i * 4 + 3)
);
params->setNamedConstant("uvMul_" + StringConverter::toString(i), uvMul);
}
if (terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP)
{
Real baseUVScale = 1.0f / (terrain->getSize() - 1);
params->setNamedConstant("baseUVScale", baseUVScale);
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelper::updateFpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
{
params->setIgnoreMissingParams(true);
// TODO - parameterise this?
/*Vector4 scaleBiasSpecular(0.03, -0.04, 32, 1);
params->setNamedConstant("scaleBiasSpecular", scaleBiasSpecular);*/
}
//---------------------------------------------------------------------
String koTerrainMaterialGenerator::SM2Profile::ShaderHelper::getChannel(uint idx)
{
uint rem = idx % 4;
switch(rem)
{
case 0:
default:
return "r";
case 1:
return "g";
case 2:
return "b";
case 3:
return "a";
};
}
//---------------------------------------------------------------------
String koTerrainMaterialGenerator::SM2Profile::ShaderHelper::getVertexProgramName(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
String progName = terrain->getMaterialName() + "/sm2/vp";
switch(tt)
{
case HIGH_LOD:
progName += "/hlod";
break;
case LOW_LOD:
progName += "/llod";
break;
case RENDER_COMPOSITE_MAP:
progName += "/comp";
break;
}
return progName;
}
//---------------------------------------------------------------------
String koTerrainMaterialGenerator::SM2Profile::ShaderHelper::getFragmentProgramName(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
String progName = terrain->getMaterialName() + "/sm2/fp";
switch(tt)
{
case HIGH_LOD:
progName += "/hlod";
break;
case LOW_LOD:
progName += "/llod";
break;
case RENDER_COMPOSITE_MAP:
progName += "/comp";
break;
}
return progName;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::createVertexProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getVertexProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
}
else
{
ret->unload();
}
ret->setParameter("profiles", "vs_4_0 vs_3_0 vs_2_0 arbvp1");
ret->setParameter("entry_point", "main_vp");
return ret;
}
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::createFragmentProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getFragmentProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
}
else
{
ret->unload();
}
ret->setParameter("profiles", "ps_4_0 ps_3_0 ps_2_x fp40 arbfp1");
ret->setParameter("entry_point", "main_fp");
return ret;
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::generateVpHeader(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
outStream <<
"void main_vp(\n";
bool compression = terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP;
if (compression)
{
outStream <<
"float2 posIndex : POSITION,\n"
"float height : TEXCOORD0,\n";
}
else
{
outStream <<
"float4 pos : POSITION,\n"
"float2 uv : TEXCOORD0,\n";
}
if (tt != RENDER_COMPOSITE_MAP)
outStream << "float2 delta : TEXCOORD1,\n"; // lodDelta, lodThreshold
outStream <<
"uniform float4x4 worldMatrix,\n"
"uniform float4x4 viewMatrix,\n"
"uniform float4x4 viewProjMatrix,\n"
"uniform float2 lodMorph,\n"; // morph amount, morph LOD target
if (compression)
{
outStream <<
"uniform float4x4 posIndexToObjectSpace,\n"
"uniform float baseUVScale,\n";
}
// uv multipliers
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
uint numUVMultipliers = (numLayers / 4);
if (numLayers % 4)
++numUVMultipliers;
for (uint i = 0; i < numUVMultipliers; ++i)
outStream << "uniform float4 uvMul_" << i << ", \n";
outStream <<
"out float4 oPos : POSITION,\n"
"out float4 oPosObj : TEXCOORD0\n";
uint texCoordSet = 1;
outStream <<
", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n";
// layer UV's premultiplied, packed as xy/zw
uint numUVSets = numLayers / 2;
if (numLayers % 2)
++numUVSets;
if (tt != LOW_LOD)
{
for (uint i = 0; i < numUVSets; ++i)
{
outStream <<
", out float4 oUV" << i << " : TEXCOORD" << texCoordSet++ << "\n";
}
}
if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP)
{
outStream << ", out float2 lodInfo : TEXCOORD" << texCoordSet++ << "\n";
}
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
outStream <<
", uniform float4 fogParams\n"
", out float fogVal : COLOR\n";
}
// check we haven't exceeded texture coordinates
if (texCoordSet > 8)
{
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"Requested options require too many texture coordinate sets! Try reducing the number of layers.",
__FUNCTION__);
}
outStream <<
")\n"
"{\n";
if (compression)
{
outStream <<
" float4 pos;\n"
" pos = mul(posIndexToObjectSpace, float4(posIndex, height, 1));\n"
" float2 uv = float2(posIndex.x * baseUVScale, 1.0 - (posIndex.y * baseUVScale));\n";
}
outStream <<
" float4 worldPos = mul(worldMatrix, pos);\n"
" oPosObj = mul(viewMatrix, pos);\n";
if (tt != RENDER_COMPOSITE_MAP)
{
// 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
outStream <<
" float toMorph = -min(0, sign(delta.y - lodMorph.y));\n";
// this will either be 1 (morph) or 0 (don't morph)
if (prof->getParent()->getDebugLevel())
{
// x == LOD level (-1 since value is target level, we want to display actual)
outStream << "lodInfo.x = (lodMorph.y - 1) / " << terrain->getNumLodLevels() << ";\n";
// y == LOD morph
outStream << "lodInfo.y = toMorph * lodMorph.x;\n";
}
// morph
switch (terrain->getAlignment())
{
case Terrain::ALIGN_X_Y:
outStream << " worldPos.z += delta.x * toMorph * lodMorph.x;\n";
break;
case Terrain::ALIGN_X_Z:
outStream << " worldPos.y += delta.x * toMorph * lodMorph.x;\n";
break;
case Terrain::ALIGN_Y_Z:
outStream << " worldPos.x += delta.x * toMorph * lodMorph.x;\n";
break;
};
}
// generate UVs
if (tt != LOW_LOD)
{
for (uint i = 0; i < numUVSets; ++i)
{
uint layer = i * 2;
uint uvMulIdx = layer / 4;
outStream <<
" oUV" << i << ".xy = " << " uv.xy * uvMul_" << uvMulIdx << "." << getChannel(layer) << ";\n";
outStream <<
" oUV" << i << ".zw = " << " uv.xy * uvMul_" << uvMulIdx << "." << getChannel(layer+1) << ";\n";
}
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::generateFpHeader(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
// Main header
outStream <<
// helpers
"float4 expand(float4 v)\n"
"{ \n"
" return v * 2 - 1;\n"
"}\n\n\n";
outStream <<
"void main_fp(\n"
"float4 position : TEXCOORD0,\n"
" out float4 oColor0 : COLOR0,\n"
" out float4 oColor1 : COLOR1,\n"
//" out float4 oColor2 : COLOR2,\n"
"uniform float cFarDistance,\n"
"uniform float4x4 viewMatrix,\n";
uint texCoordSet = 1;
outStream <<
"float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n";
std::vector<bool> layerNormalMapping;
layerNormalMapping.resize(terrain->getLayerCount());
for(unsigned int i = 0; i < terrain->getLayerCount(); i++)
{
if(terrain->getLayerTextureName(i, 1).compare("") == 0)
layerNormalMapping[i] = false;
else
layerNormalMapping[i] = true;
}
// UV's premultiplied, packed as xy/zw
uint maxLayers = prof->getMaxLayers(terrain);
uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
uint numUVSets = numLayers / 2;
if (numLayers % 2)
++numUVSets;
if (tt != LOW_LOD)
{
for (uint i = 0; i < numUVSets; ++i)
{
outStream <<
"float4 layerUV" << i << " : TEXCOORD" << texCoordSet++ << ", \n";
}
}
if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP)
{
outStream << "float2 lodInfo : TEXCOORD" << texCoordSet++ << ", \n";
}
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
outStream <<
"uniform float3 fogColour, \n"
"float fogVal : COLOR,\n";
}
uint currentSamplerIdx = 0;
if (tt == LOW_LOD)
{
// single composite map covers all the others below
outStream <<
"uniform sampler2D compositeMap : register(s" << currentSamplerIdx++ << ")\n";
}
else
{
outStream <<
"uniform sampler2D globalNormal : register(s" << currentSamplerIdx++ << ")\n";
if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
{
outStream << ", uniform sampler2D globalColourMap : register(s"
<< currentSamplerIdx++ << ")\n";
}
// Blend textures - sampler definitions
for (uint i = 0; i < numBlendTextures; ++i)
{
outStream << ", uniform sampler2D blendTex" << i
<< " : register(s" << currentSamplerIdx++ << ")\n";
}
// Layer textures - sampler definitions & UV multipliers
for (uint i = 0; i < numLayers; ++i)
{
outStream << ", uniform sampler2D difftex" << i
<< " : register(s" << currentSamplerIdx++ << ")\n";
if(layerNormalMapping[i])
outStream << ", uniform sampler2D normtex" << i
<< " : register(s" << currentSamplerIdx++ << ")\n";
}
}
// check we haven't exceeded samplers
if (currentSamplerIdx > 16)
{
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"Requested options require too many texture samplers! Try reducing the number of layers.",
__FUNCTION__);
}
outStream <<
") \n"
"{\n"
" float2 uv = uvMisc.xy;\n"
// base colour
" oColor0 = float4(0,0,0,0);\n"
" oColor1 = float4(1,1,1,1);\n";
if (tt != LOW_LOD)
{
outStream <<
" float3 normal = expand(tex2D(globalNormal, uv)).rgb;\n";
}
// set up accumulation areas
outStream << " float3 diffuse = float3(0,0,0);\n"
" float specular = 0;\n";
if (tt == LOW_LOD)
{
// we just do a single calculation from composite map
outStream <<
" float4 composite = tex2D(compositeMap, uv);\n"
" diffuse = composite.rgb;\n";
// TODO - specular; we'll need normals for this!
}
else
{
// set up the blend values
for (uint i = 0; i < numBlendTextures; ++i)
{
outStream << " float4 blendTexVal" << i << " = tex2D(blendTex" << i << ", uv);\n";
}
// derive the tangent space basis
// we do this in the pixel shader because we don't have per-vertex normals
// because of the LOD, we use a normal map
// tangent is always +x or -z in object space depending on alignment
switch(terrain->getAlignment())
{
case Terrain::ALIGN_X_Y:
case Terrain::ALIGN_X_Z:
outStream << " float3 tangent = float3(1, 0, 0);\n";
break;
case Terrain::ALIGN_Y_Z:
outStream << " float3 tangent = float3(0, 0, -1);\n";
break;
};
// We must do normal calculations here instead of the vertex program because terrain normals
// are provided by the "normal" texture, and not in vertex info. We multiply it by the viewMatrix
// so the normals are in eye-space instead of object-space, as required by deferred shading.
outStream << " normal = mul(viewMatrix, float4(normal,0)).xyz;" << std::endl;
outStream << " tangent = mul(viewMatrix, float4(tangent,0)).xyz;" << std::endl;
outStream << " float3 binormal = cross(normal, tangent);" << std::endl;
// derive final matrix
outStream << " float3x3 TBN = float3x3(tangent, binormal, normal);\n";
// set up lighting result placeholders for interpolation
outStream << " float3 TSnormal = normal;\n";
outStream << " float3 TSnormal2;\n";
}
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::generateVpLayer(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream)
{
// nothing to do
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::generateFpLayer(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream)
{
std::vector<bool> layerNormalMapping;
layerNormalMapping.resize(terrain->getLayerCount());
for(unsigned int i = 0; i < terrain->getLayerCount(); i++)
{
if(terrain->getLayerTextureName(i, 1).compare("") == 0)
layerNormalMapping[i] = false;
else
layerNormalMapping[i] = true;
}
uint uvIdx = layer / 2;
String uvChannels = (layer % 2) ? ".zw" : ".xy";
uint blendIdx = (layer-1) / 4;
String blendChannel = getChannel(layer-1);
String blendWeightStr = String("blendTexVal") + StringConverter::toString(blendIdx) +
"." + blendChannel;
// generate early-out conditional
/* Disable - causing some issues even when trying to force the use of texldd
if (layer && prof->_isSM3Available())
outStream << " if (" << blendWeightStr << " > 0.0003)\n { \n";
*/
// generate UV
outStream << " float2 uv" << layer << " = layerUV" << uvIdx << uvChannels << ";\n";
// access TS normal map
if(layerNormalMapping[layer])
{
outStream << " TSnormal2 = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n";
outStream << " TSnormal2 = normalize(TSnormal2);\n";
}
else
{
outStream << " TSnormal2 = normalize(normal);\n";
}
if (layer)
outStream << " TSnormal = lerp(TSnormal, TSnormal2, " << blendWeightStr << ");\n";
else
outStream << " TSnormal = TSnormal2;\n";
if (layer)
{
outStream << " oColor1.rgb = lerp(oColor1.rgb, TSnormal2, " << blendWeightStr << ");\n";
}
else
{
outStream << " oColor1.rgb = TSnormal2;\n";
}
// sample diffuse texture
outStream << " float4 diffuseSpecTex" << layer
<< " = tex2D(difftex" << layer << ", uv" << layer << ");\n";
// apply to common
if (!layer)
{
outStream << " diffuse = diffuseSpecTex0.rgb;\n";
outStream << " specular = diffuseSpecTex0.a;\n";
}
else
{
outStream << " diffuse = lerp(diffuse, diffuseSpecTex" << layer
<< ".rgb, " << blendWeightStr << ");\n";
outStream << " specular = lerp(specular, diffuseSpecTex" << layer
<< ".a, " << blendWeightStr << ");\n";
}
// End early-out
/* Disable - causing some issues even when trying to force the use of texldd
if (layer && prof->_isSM3Available())
outStream << " } // early-out blend value\n";
*/
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::generateVpFooter(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
outStream <<
" oPos = mul(viewProjMatrix, worldPos);\n"
" oUVMisc.xy = uv.xy;\n";
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR)
{
outStream <<
" fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n";
}
else
{
outStream <<
" fogVal = 1 - saturate(1 / (exp(oPos.z * fogParams.x)));\n";
}
}
outStream <<
"}\n";
}
//---------------------------------------------------------------------
void koTerrainMaterialGenerator::SM2Profile::ShaderHelperCg::generateFpFooter(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
std::vector<bool> layerNormalMapping;
layerNormalMapping.resize(terrain->getLayerCount());
for(unsigned int i = 0; i < terrain->getLayerCount(); i++)
{
if(terrain->getLayerTextureName(i, 1).compare("") == 0)
layerNormalMapping[i] = false;
else
layerNormalMapping[i] = true;
}
if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
{
// sample colour map and apply to diffuse
outStream << " diffuse *= tex2D(globalColourMap, uv).rgb;\n";
}
// diffuse lighting
outStream << " oColor0.rgb += diffuse;\n"
" oColor0.a += specular;\n";
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
outStream << " oColor0.rgb = lerp(oColor0.rgb, fogColour, fogVal);\n";
}
// Final return
outStream << " oColor1 = float4(normalize(mul(TSnormal, TBN)), length(position) / cFarDistance);\n" << "}\n";
}
//---------------------------------------------------------------------
}
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
I finally tested the fixed blending and it seems to working very well. Now here comes a screenshot showing a simple diffuse/specular texture (gras) beside a normal mapping one (rocks). Actually the layersize is restricted to 5 (but i think its still cool to use diffuse/specular textures beside normal textures too).
(using the shaderfix provided above - and fixed my fix - i had to comment out something in line 840, now its looking like that "if(true/*layerNormalMapping*/)")
I would like to combine these different kinds of mappings to maximize the layer limit of 5 to a limit which depend of the dynamic combination. Lets say your level designer needs only 3 normal mapping textures - in this case he can use totally up to 7 layers (3 normal mapping, 4 diffuse/specular) - without rewrite something. Technically thats not a problem but the implementation of the terrain system doesnt alllow different sampler declaration of each layer:
I may use a litte "hack" to use a layer declaration of one diffuse and one normal-texture but internally - in the shader - reuse the "normal" texture for the next layer (if this one isnt a normal texture). the problem is maybe the texture filtering (could be different from diffuse and normal texture). i do not know - but i'll try!
(using the shaderfix provided above - and fixed my fix - i had to comment out something in line 840, now its looking like that "if(true/*layerNormalMapping*/)")
I would like to combine these different kinds of mappings to maximize the layer limit of 5 to a limit which depend of the dynamic combination. Lets say your level designer needs only 3 normal mapping textures - in this case he can use totally up to 7 layers (3 normal mapping, 4 diffuse/specular) - without rewrite something. Technically thats not a problem but the implementation of the terrain system doesnt alllow different sampler declaration of each layer:
The definition of the information each layer will contain in this terrain.
All layers must contain the same structure of information, although the input textures can be different per layer instance.
I may use a litte "hack" to use a layer declaration of one diffuse and one normal-texture but internally - in the shader - reuse the "normal" texture for the next layer (if this one isnt a normal texture). the problem is maybe the texture filtering (could be different from diffuse and normal texture). i do not know - but i'll try!
Last edited by technique on Fri Oct 26, 2012 12:45 pm, edited 1 time in total.
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Re: Deferred Shading Terrain Material Generator
For your first fix, I'm not sure normal blending should be applied twice, as TBN already takes into account the terrain "world normal map".
However, there is an issue I fixed in my local copy but forgot to push to wiki, the final return line of generateFpFooter should read:
Instead of mul(TSnormal, TBN), as it would only take the last normal map sampler. I'm updating the wiki to reflect this fix.
For your TSnormal2, I'm not sure it's right, for me you'd be applying twice the world normal map.
However, there is an issue I fixed in my local copy but forgot to push to wiki, the final return line of generateFpFooter should read:
Code: Select all
outStream << " oColor1 = float4(normalize(mul(oColor1.rgb, TBN)), length(position) / cFarDistance);\n"
For your TSnormal2, I'm not sure it's right, for me you'd be applying twice the world normal map.
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Its because of the Simple Texture Layer (without normal-mapping). My problem was the assignment/blending of the TSnormal for none normal mapping layer. Basically to get the terrain normal out of the tbn its just a multiplication like this (0,0,1)^T * TBN. So for each Simple Texture Layer i should blend with the vector v= (0,0,1)? may this be the right way?Xplodwild wrote: For your TSnormal2, I'm not sure it's right, for me you'd be applying twice the world normal map.
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender
- Xplodwild
- Goblin
- Posts: 231
- Joined: Thu Feb 12, 2009 3:49 pm
- Location: France
- x 13
- Contact:
Re: Deferred Shading Terrain Material Generator
No normal mapping layer should point Z, yes.
But there's no point having a deferred shading if you don't use normalmaps :p
But there's no point having a deferred shading if you don't use normalmaps :p
-
- Halfling
- Posts: 91
- Joined: Fri Oct 22, 2010 10:46 pm
- x 8
Re: Deferred Shading Terrain Material Generator
Meh...for terrain - it may be usefull to pass on normal mapping for a few layer to get a higher layer maximum (as i wrote before). Especially for textures which dont need an extra "bumpy-look".
For DF - I really want to have many lights affecting the terrain so for me this is the most important advantage in deferred shading.
For DF - I really want to have many lights affecting the terrain so for me this is the most important advantage in deferred shading.
Kingdoms Defender offers Tower Defense action with breathtaking 3-D graphics for your mobile Android device.
Give it a try:
Free-Version:
http://play.google.com/store/apps/detai ... ender_free
Full-Version:
http://play.google.com/store/apps/detai ... msdefender