<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://horde3d.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ecksp</id>
		<title>Horde3D Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://horde3d.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ecksp"/>
		<link rel="alternate" type="text/html" href="http://horde3d.org/wiki/index.php?title=Special:Contributions/Ecksp"/>
		<updated>2026-05-14T00:19:18Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.29.3</generator>

	<entry>
		<id>http://horde3d.org/wiki/index.php?title=Shading_Technique_-_Terrain_Shading&amp;diff=449</id>
		<title>Shading Technique - Terrain Shading</title>
		<link rel="alternate" type="text/html" href="http://horde3d.org/wiki/index.php?title=Shading_Technique_-_Terrain_Shading&amp;diff=449"/>
				<updated>2009-01-05T09:53:21Z</updated>
		
		<summary type="html">&lt;p&gt;Ecksp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Explanation of Technique ==&lt;br /&gt;
&lt;br /&gt;
If you look at any piece of land in the real world you'll notice that it's made of a number of different materials. Rocks, dirt, foliage, etc. You'll also notice that the materials at some levels are different than those at higher or lower levels and that some materials don't show up on slopes over a certain degree (like foliage on steep slopes.) Our purpose here is to mimic this aspect of nature to some degree.&lt;br /&gt;
&lt;br /&gt;
== The Material ==&lt;br /&gt;
&lt;br /&gt;
{{CppSourceCode|&lt;br /&gt;
description= Terrain shader material|&lt;br /&gt;
code=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;Material&amp;gt;&lt;br /&gt;
	&amp;lt;Shader source=&amp;quot;terrain.shader.xml&amp;quot;/&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;0&amp;quot; map=&amp;quot;heightmap.tga&amp;quot; allowCompression=&amp;quot;false&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;1&amp;quot; map=&amp;quot;dirt.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;2&amp;quot; map=&amp;quot;grass.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;3&amp;quot; map=&amp;quot;rock.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;4&amp;quot; map=&amp;quot;snow.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;sunDir&amp;quot; a=&amp;quot;1.0&amp;quot; b=&amp;quot;-1.0&amp;quot; c=&amp;quot;0.0&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;!-- a=min height, b=max height, c=min slope, d=max slope --&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;rockData&amp;quot; a=&amp;quot;0.0&amp;quot; b=&amp;quot;520.0&amp;quot; c=&amp;quot;0.16&amp;quot; d=&amp;quot;1.0&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;snowData&amp;quot; a=&amp;quot;240.0&amp;quot; b=&amp;quot;520.0&amp;quot; c=&amp;quot;0.0&amp;quot; d=&amp;quot;0.7&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;dirtData&amp;quot; a=&amp;quot;0.0&amp;quot; b=&amp;quot;270.0&amp;quot; c=&amp;quot;0.0&amp;quot; d=&amp;quot;0.83&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;grassData&amp;quot; a=&amp;quot;0.0&amp;quot; b=&amp;quot;256.0&amp;quot; c=&amp;quot;0.0&amp;quot; d=&amp;quot;0.66&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;!-- a=grass, b=dirt, c=rock, d=snow --&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;mapStrength&amp;quot; a=&amp;quot;1.0&amp;quot; b=&amp;quot;0.4&amp;quot; c=&amp;quot;0.28&amp;quot; d=&amp;quot;0.86&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/Material&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== The Material Explained ==&lt;br /&gt;
&lt;br /&gt;
There's nothing fancy going on here of course. I got the values for the data variables and map strength just by fiddling around with them in a small test program.&lt;br /&gt;
&lt;br /&gt;
== The Vertex Shader ==&lt;br /&gt;
&lt;br /&gt;
{{CppSourceCode|&lt;br /&gt;
description= Terrain vertex shader|&lt;br /&gt;
code=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 terBlockParams;&lt;br /&gt;
attribute float terHeight;&lt;br /&gt;
varying float height;&lt;br /&gt;
varying vec3 triTexCoords;&lt;br /&gt;
				&lt;br /&gt;
void main( void )&lt;br /&gt;
{&lt;br /&gt;
	vec4 newPos = vec4(gl_Vertex.x * terBlockParams.z + terBlockParams.x, terHeight,&lt;br /&gt;
						gl_Vertex.z * terBlockParams.z + terBlockParams.y, gl_Vertex.w);&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = calcWorldPos(newPos);&lt;br /&gt;
	triTexCoords = newPos.xyz;&lt;br /&gt;
	height = pos.y;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== Explanation of the Vertex Shader ==&lt;br /&gt;
&lt;br /&gt;
Some of you may have noticed that this is awfully similar to the example shader that comes with the terrain extension. The only differences here are a.) We're now using a vec3 to hold the texture coordinates which will be required for the triplanar texturing, and b.) We're saving the height of the vertex for the height/slope based portion of the fragment shader.&lt;br /&gt;
&lt;br /&gt;
== The Fragment Shader ==&lt;br /&gt;
&lt;br /&gt;
{{CppSourceCode|&lt;br /&gt;
description= Terrain fragment shader|&lt;br /&gt;
code=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 sunDir;&lt;br /&gt;
				&lt;br /&gt;
// tex0=heightmap, tex1=dirt, tex2=grass, tex3=rock, tex4=snow&lt;br /&gt;
uniform sampler2D tex0, tex1, tex2, tex3, tex4;&lt;br /&gt;
				&lt;br /&gt;
// .x = min height, .y = max height, .z = min slope, .w = max slope&lt;br /&gt;
uniform vec4 snowData;&lt;br /&gt;
uniform vec4 rockData;&lt;br /&gt;
uniform vec4 dirtData;&lt;br /&gt;
uniform vec4 grassData;&lt;br /&gt;
				&lt;br /&gt;
// .x=grass, .y=dirt, .z=rock, .w=snow&lt;br /&gt;
uniform vec4 mapStrength;&lt;br /&gt;
				&lt;br /&gt;
varying float height;&lt;br /&gt;
varying vec3 triTexCoords;&lt;br /&gt;
								&lt;br /&gt;
vec3 light = -normalize( sunDir.xyz );&lt;br /&gt;
&lt;br /&gt;
// this comes from the book Real-Time 3D Terrain Engines Using C++ And DirectX &lt;br /&gt;
float computeWeight(float value, float minExtent, float maxExtent)&lt;br /&gt;
{&lt;br /&gt;
	float weight = 0.0;&lt;br /&gt;
				&lt;br /&gt;
	if(value &amp;gt;= minExtent &amp;amp;&amp;amp; value &amp;lt;= maxExtent)&lt;br /&gt;
	{&lt;br /&gt;
		float range = maxExtent - minExtent;&lt;br /&gt;
		&lt;br /&gt;
		weight = value - minExtent;&lt;br /&gt;
						&lt;br /&gt;
		// convert to [0, 1] based on its distance to midpoint of the extents&lt;br /&gt;
		weight *= 1.0 / range;&lt;br /&gt;
		weight -= 0.5;&lt;br /&gt;
		weight *= 2.0;&lt;br /&gt;
						&lt;br /&gt;
		// square result for non-linear falloff&lt;br /&gt;
		weight *= weight;&lt;br /&gt;
						&lt;br /&gt;
		// invert and bound check&lt;br /&gt;
		weight = 1.0 - abs(weight);&lt;br /&gt;
		weight = clamp(weight, 0.001, 1.0);&lt;br /&gt;
	}&lt;br /&gt;
					&lt;br /&gt;
	return weight;&lt;br /&gt;
}&lt;br /&gt;
				&lt;br /&gt;
void main( void )&lt;br /&gt;
{&lt;br /&gt;
	vec4 texel = texture2D(tex0, triTexCoords.xz) * 2.0 - 1.0;&lt;br /&gt;
	// Use max because of numerical issues&lt;br /&gt;
	float ny = sqrt(max(1.0 - texel.b*texel.b - texel.a*texel.a, 0.0));		&lt;br /&gt;
	vec3 normal = vec3(texel.b, ny, texel.a);&lt;br /&gt;
&lt;br /&gt;
	// Wrap lighting for sun&lt;br /&gt;
	float l = max( dot( normal, light ), 0.0 ) * 0.5 + 0.5;&lt;br /&gt;
					&lt;br /&gt;
	// slope: 1.0 = steep, 0.0 = flat&lt;br /&gt;
	float slope = 1.0 - ny;&lt;br /&gt;
					&lt;br /&gt;
	vec4 weights = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	&lt;br /&gt;
	// once all 3 lookups have been done for a texture these weights&lt;br /&gt;
	// say how much of the sum of those lookups to use&lt;br /&gt;
	weights.x = computeWeight(height, rockData.x, rockData.y) * &lt;br /&gt;
				computeWeight(slope, rockData.z, rockData.w) * mapStrength.z;&lt;br /&gt;
	weights.y = computeWeight(height, dirtData.x, dirtData.y) * &lt;br /&gt;
				computeWeight(slope, dirtData.z, dirtData.w) * mapStrength.y;&lt;br /&gt;
	weights.z = computeWeight(height, snowData.x, snowData.y) * &lt;br /&gt;
				computeWeight(slope, snowData.z, snowData.w) * mapStrength.w;&lt;br /&gt;
	weights.w = computeWeight(height, grassData.x, grassData.y) * &lt;br /&gt;
				computeWeight(slope, grassData.z, grassData.w) * mapStrength.x;&lt;br /&gt;
	weights *= 1.0 / (weights.x + weights.y + weights.z + weights.w);&lt;br /&gt;
					&lt;br /&gt;
	// this comes from the gpu gems 3 article: &lt;br /&gt;
	// generating complex procedural terrains using the gpu&lt;br /&gt;
	// used to determine how much of each planar lookup to use&lt;br /&gt;
	// for each texture&lt;br /&gt;
	vec3 tpweights = abs(normal);&lt;br /&gt;
	tpweights = (tpweights - 0.2) * 7.0;&lt;br /&gt;
	tpweights = max(tpweights, vec3(0.0, 0.0, 0.0));&lt;br /&gt;
	tpweights /= (tpweights.x + tpweights.y + tpweights.z).xxx;&lt;br /&gt;
				&lt;br /&gt;
	vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
	vec4 tempColor = vec4(0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
						&lt;br /&gt;
	// dirt&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex1, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex1, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex1, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.y * tempColor;&lt;br /&gt;
&lt;br /&gt;
	// grass&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex2, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex2, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex2, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.w * tempColor;&lt;br /&gt;
	&lt;br /&gt;
	// rock&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex3, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex3, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex3, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.x * tempColor;&lt;br /&gt;
	&lt;br /&gt;
	// snow&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex4, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex4, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex4, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.z * tempColor;&lt;br /&gt;
					&lt;br /&gt;
	gl_FragColor = finalColor * l;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== Explanation of the Fragment Shader ==&lt;br /&gt;
&lt;br /&gt;
The most important part of this shader is in calculating the weights to use not  only for each texture but also for each plane(xy, yz and xz.) &lt;br /&gt;
&lt;br /&gt;
The weights variable holds the weights for each individual texture. Height and slope weights are calculated for each texture then multiplied with the strength of the texture which basically tells how important that texture is when it's being blended with others. The last line of the weights calculation makes sure the sum of all the weights is 1.&lt;br /&gt;
&lt;br /&gt;
The tpweights variable holds the weights for each plane. It's based on the normal that was calculated at the start of the function and must also sum to 1.&lt;br /&gt;
&lt;br /&gt;
Once we have all our weights we do a texture lookup using each of the planes in triTexCoords as texture coordinates, multiply each by it's weight, add them all up and then add that sum to the final color.&lt;br /&gt;
&lt;br /&gt;
== Final Words == &lt;br /&gt;
&lt;br /&gt;
This is quite an expensive shader. You could get away with adding another texture or two to the mix but you'd quickly start limiting your target audience. You may notice this is also a modified version of the example shader from the terrain extension.&lt;/div&gt;</summary>
		<author><name>Ecksp</name></author>	</entry>

	<entry>
		<id>http://horde3d.org/wiki/index.php?title=Shading_Technique_-_Terrain_Shading&amp;diff=448</id>
		<title>Shading Technique - Terrain Shading</title>
		<link rel="alternate" type="text/html" href="http://horde3d.org/wiki/index.php?title=Shading_Technique_-_Terrain_Shading&amp;diff=448"/>
				<updated>2009-01-05T09:52:35Z</updated>
		
		<summary type="html">&lt;p&gt;Ecksp: New page: == Explanation of Technique ==  If you look at any piece of land in the real world you'll notice that it's made of a number of different materials. Rocks, dirt, foliage, etc. You'll also n...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Explanation of Technique ==&lt;br /&gt;
&lt;br /&gt;
If you look at any piece of land in the real world you'll notice that it's made of a number of different materials. Rocks, dirt, foliage, etc. You'll also notice that the materials at some levels are different than those at higher or lower levels and that some materials don't show up on slopes over a certain degree (like foliage on steep slopes.) Our purpose here is to mimic this aspect of nature to some degree.&lt;br /&gt;
&lt;br /&gt;
== The Material ==&lt;br /&gt;
&lt;br /&gt;
{{CppSourceCode|&lt;br /&gt;
description= Terrain shader material|&lt;br /&gt;
code=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;Material&amp;gt;&lt;br /&gt;
	&amp;lt;Shader source=&amp;quot;terrain.shader.xml&amp;quot;/&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;0&amp;quot; map=&amp;quot;heightmap.tga&amp;quot; allowCompression=&amp;quot;false&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;1&amp;quot; map=&amp;quot;dirt.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;2&amp;quot; map=&amp;quot;grass.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;3&amp;quot; map=&amp;quot;rock.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;TexUnit unit=&amp;quot;4&amp;quot; map=&amp;quot;snow.jpg&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;sunDir&amp;quot; a=&amp;quot;1.0&amp;quot; b=&amp;quot;-1.0&amp;quot; c=&amp;quot;0.0&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;!-- a=min height, b=max height, c=min slope, d=max slope --&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;rockData&amp;quot; a=&amp;quot;0.0&amp;quot; b=&amp;quot;520.0&amp;quot; c=&amp;quot;0.16&amp;quot; d=&amp;quot;1.0&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;snowData&amp;quot; a=&amp;quot;240.0&amp;quot; b=&amp;quot;520.0&amp;quot; c=&amp;quot;0.0&amp;quot; d=&amp;quot;0.7&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;dirtData&amp;quot; a=&amp;quot;0.0&amp;quot; b=&amp;quot;270.0&amp;quot; c=&amp;quot;0.0&amp;quot; d=&amp;quot;0.83&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;grassData&amp;quot; a=&amp;quot;0.0&amp;quot; b=&amp;quot;256.0&amp;quot; c=&amp;quot;0.0&amp;quot; d=&amp;quot;0.66&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;!-- a=grass, b=dirt, c=rock, d=snow --&amp;gt;&lt;br /&gt;
	&amp;lt;Uniform name=&amp;quot;mapStrength&amp;quot; a=&amp;quot;1.0&amp;quot; b=&amp;quot;0.4&amp;quot; c=&amp;quot;0.28&amp;quot; d=&amp;quot;0.86&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/Material&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== The Material Explained ==&lt;br /&gt;
&lt;br /&gt;
There's nothing fancy going on here of course. I got the values for the data variables and map strength just by fiddling around with them in a small test program.&lt;br /&gt;
&lt;br /&gt;
== The Vertex Shader ==&lt;br /&gt;
&lt;br /&gt;
{{CppSourceCode|&lt;br /&gt;
description= Terrain vertex shader|&lt;br /&gt;
code=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 terBlockParams;&lt;br /&gt;
attribute float terHeight;&lt;br /&gt;
varying float height;&lt;br /&gt;
varying vec3 triTexCoords;&lt;br /&gt;
				&lt;br /&gt;
void main( void )&lt;br /&gt;
{&lt;br /&gt;
	vec4 newPos = vec4(gl_Vertex.x * terBlockParams.z + terBlockParams.x, terHeight,&lt;br /&gt;
						gl_Vertex.z * terBlockParams.z + terBlockParams.y, gl_Vertex.w);&lt;br /&gt;
&lt;br /&gt;
	vec4 pos = calcWorldPos(newPos);&lt;br /&gt;
	triTexCoords = newPos.xyz;&lt;br /&gt;
	height = pos.y;&lt;br /&gt;
&lt;br /&gt;
	gl_Position = gl_ModelViewProjectionMatrix * pos;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== Explanation of the Vertex Shader ==&lt;br /&gt;
&lt;br /&gt;
Some of you may have noticed that this is awfully similar to the example shader that comes with the terrain extension. The only differences here are a.) We're now using a vec3 to hold the texture coordinates which will be required for the triplanar texturing, and b.) We're saving the height of the vertex for the height/slope based portion of the fragment shader.&lt;br /&gt;
&lt;br /&gt;
== The Fragment Shader ==&lt;br /&gt;
&lt;br /&gt;
{{CppSourceCode|&lt;br /&gt;
description= Terrain fragment shader|&lt;br /&gt;
code=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
uniform vec4 sunDir;&lt;br /&gt;
				&lt;br /&gt;
// tex0=heightmap, tex1=dirt, tex2=grass, tex3=rock, tex4=snow&lt;br /&gt;
uniform sampler2D tex0, tex1, tex2, tex3, tex4;&lt;br /&gt;
				&lt;br /&gt;
// .x = min height, .y = max height, .z = min slope, .w = max slope&lt;br /&gt;
uniform vec4 snowData;&lt;br /&gt;
uniform vec4 rockData;&lt;br /&gt;
uniform vec4 dirtData;&lt;br /&gt;
uniform vec4 grassData;&lt;br /&gt;
				&lt;br /&gt;
// .x=grass, .y=dirt, .z=rock, .w=snow&lt;br /&gt;
uniform vec4 mapStrength;&lt;br /&gt;
				&lt;br /&gt;
varying float height;&lt;br /&gt;
varying vec3 triTexCoords;&lt;br /&gt;
								&lt;br /&gt;
vec3 light = -normalize( sunDir.xyz );&lt;br /&gt;
&lt;br /&gt;
// this comes from the book Real-Time 3D Terrain Engines Using C++ And DirectX &lt;br /&gt;
float computeWeight(float value, float minExtent, float maxExtent)&lt;br /&gt;
{&lt;br /&gt;
	float weight = 0.0;&lt;br /&gt;
				&lt;br /&gt;
	if(value &amp;gt;= minExtent &amp;amp;&amp;amp; value &amp;lt;= maxExtent)&lt;br /&gt;
	{&lt;br /&gt;
		float range = maxExtent - minExtent;&lt;br /&gt;
		&lt;br /&gt;
		weight = value - minExtent;&lt;br /&gt;
						&lt;br /&gt;
		// convert to [0, 1] based on its distance to midpoint of the extents&lt;br /&gt;
		weight *= 1.0 / range;&lt;br /&gt;
		weight -= 0.5;&lt;br /&gt;
		weight *= 2.0;&lt;br /&gt;
						&lt;br /&gt;
		// square result for non-linear falloff&lt;br /&gt;
		weight *= weight;&lt;br /&gt;
						&lt;br /&gt;
		// invert and bound check&lt;br /&gt;
		weight = 1.0 - abs(weight);&lt;br /&gt;
		weight = clamp(weight, 0.001, 1.0);&lt;br /&gt;
	}&lt;br /&gt;
					&lt;br /&gt;
	return weight;&lt;br /&gt;
}&lt;br /&gt;
				&lt;br /&gt;
void main( void )&lt;br /&gt;
{&lt;br /&gt;
	vec4 texel = texture2D(tex0, triTexCoords.xz) * 2.0 - 1.0;&lt;br /&gt;
	// Use max because of numerical issues&lt;br /&gt;
	float ny = sqrt(max(1.0 - texel.b*texel.b - texel.a*texel.a, 0.0));		&lt;br /&gt;
	vec3 normal = vec3(texel.b, ny, texel.a);&lt;br /&gt;
&lt;br /&gt;
	// Wrap lighting for sun&lt;br /&gt;
	float l = max( dot( normal, light ), 0.0 ) * 0.5 + 0.5;&lt;br /&gt;
					&lt;br /&gt;
	// slope: 1.0 = steep, 0.0 = flat&lt;br /&gt;
	float slope = 1.0 - ny;&lt;br /&gt;
					&lt;br /&gt;
	vec4 weights = vec4(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
	&lt;br /&gt;
	// once all 3 lookups have been done for a texture these weights&lt;br /&gt;
	// say how much of the sum of those lookups to use&lt;br /&gt;
	weights.x = computeWeight(height, rockData.x, rockData.y) * &lt;br /&gt;
				computeWeight(slope, rockData.z, rockData.w) * mapStrength.z;&lt;br /&gt;
	weights.y = computeWeight(height, dirtData.x, dirtData.y) * &lt;br /&gt;
				computeWeight(slope, dirtData.z, dirtData.w) * mapStrength.y;&lt;br /&gt;
	weights.z = computeWeight(height, snowData.x, snowData.y) * &lt;br /&gt;
				computeWeight(slope, snowData.z, snowData.w) * mapStrength.w;&lt;br /&gt;
	weights.w = computeWeight(height, grassData.x, grassData.y) * &lt;br /&gt;
				computeWeight(slope, grassData.z, grassData.w) * mapStrength.x;&lt;br /&gt;
	weights *= 1.0 / (weights.x + weights.y + weights.z + weights.w);&lt;br /&gt;
					&lt;br /&gt;
	// this comes from the gpu gems 3 article: &lt;br /&gt;
	// generating complex procedural terrains using the gpu&lt;br /&gt;
	// used to determine how much of each planar lookup to use&lt;br /&gt;
	// for each texture&lt;br /&gt;
	vec3 tpweights = abs(normal);&lt;br /&gt;
	tpweights = (tpweights - 0.2) * 7.0;&lt;br /&gt;
	tpweights = max(tpweights, vec3(0.0, 0.0, 0.0));&lt;br /&gt;
	tpweights /= (tpweights.x + tpweights.y + tpweights.z).xxx;&lt;br /&gt;
				&lt;br /&gt;
	vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
	vec4 tempColor = vec4(0.0, 0.0, 0.0, 1.0);&lt;br /&gt;
						&lt;br /&gt;
	// dirt&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex1, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex1, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex1, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.y * tempColor;&lt;br /&gt;
&lt;br /&gt;
	// grass&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex2, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex2, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex2, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.w * tempColor;&lt;br /&gt;
	&lt;br /&gt;
	// rock&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex3, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex3, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex3, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.x * tempColor;&lt;br /&gt;
	&lt;br /&gt;
	// snow&lt;br /&gt;
	tempColor = tpweights.z * texture2D(tex4, triTexCoords.xy*5.0);&lt;br /&gt;
	tempColor += tpweights.x * texture2D(tex4, triTexCoords.yz*5.0);&lt;br /&gt;
	tempColor += tpweights.y * texture2D(tex4, triTexCoords.xz*5.0);&lt;br /&gt;
	finalColor += weights.z * tempColor;&lt;br /&gt;
					&lt;br /&gt;
	gl_FragColor = finalColor * l;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== Explanation of the Fragment Shader ==&lt;br /&gt;
&lt;br /&gt;
The most important part of this shader is in calculating the weights to use not  only for each texture but also for each plane(xy, yz and xz.) &lt;br /&gt;
&lt;br /&gt;
The weights variable holds the weights for each individual texture. Height and slope weights are calculated for each texture then multiplied with the strength of the texture which basically tells how important that texture is when it's being blended with others. The last line of the weights calculation makes sure the sum of all the weights is 1.&lt;br /&gt;
&lt;br /&gt;
The tpweights variable holds the weights for each plane. It's based on the normal that was calculated at the start of the function and must also sum to 1.&lt;br /&gt;
&lt;br /&gt;
Once we have all our weights we do a texture lookup using each of the planes in triTexCoords as texture coordinates, multiply each by it's weight, add them all up and then add that sum to the final color.&lt;br /&gt;
&lt;br /&gt;
== Final Words == &lt;br /&gt;
&lt;br /&gt;
This is quite an expensive shader. You could get away with adding another texture or two to the mix but you'd quickly start limiting your target audience. You may notice this is also a modified version of the example shader from the terrain extension.&lt;br /&gt;
&lt;br /&gt;
== Example Result ==&lt;/div&gt;</summary>
		<author><name>Ecksp</name></author>	</entry>

	<entry>
		<id>http://horde3d.org/wiki/index.php?title=Horde3D_Wiki:Community_portal&amp;diff=447</id>
		<title>Horde3D Wiki:Community portal</title>
		<link rel="alternate" type="text/html" href="http://horde3d.org/wiki/index.php?title=Horde3D_Wiki:Community_portal&amp;diff=447"/>
				<updated>2009-01-05T09:14:35Z</updated>
		
		<summary type="html">&lt;p&gt;Ecksp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOEDITSECTION__{{ContentBlock|width=800|color=orange&lt;br /&gt;
|content= '''The community portal section of the Horde3D wiki contains community contributed articles that are not part of the official documentation. Feel free to add articles to our wiki or links to external tutorials.'''}}&lt;br /&gt;
{{SpacerBlock}}&lt;br /&gt;
{{ContentBlock|width=800&lt;br /&gt;
|header=Horde3D is a cross-platform graphics engine. The currently supported platform are Windows, Linux and Mac OS X.&lt;br /&gt;
|content={{!!}}&lt;br /&gt;
==Setting up the Development Environment==&lt;br /&gt;
*[[Horde3D Development Environment for Windows]]&lt;br /&gt;
*[[Horde3D Development Environment for Linux]]&lt;br /&gt;
*[[Horde3D Development Environment for Mac OS X]]&lt;br /&gt;
&lt;br /&gt;
*[[Horde3D Development Environment from SVN]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Tutorials==&lt;br /&gt;
[[Category: Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Fell free to write your tutorials here, for the benefit of the whole community. &lt;br /&gt;
&lt;br /&gt;
===Beginner===&lt;br /&gt;
#[[Tutorial - Hello World]] - In this section we will create a simple application that loads a character and animates it using a walk cycle.&lt;br /&gt;
#[[Tutorial - Picking]] - In this section we will demonstrate picking the node under the mouse cursor&lt;br /&gt;
#[[Tutorial - Simple HUD]] - How to use showOverlay to create a simple HUD.&lt;br /&gt;
#[[Tutorial - Setup Horde with SDL]]   - How to Setup Horde with SDL.&lt;br /&gt;
#[[Tutorial - Setup Horde with Qt4]]   - How to Setup Horde with Qt4.&lt;br /&gt;
#[[Tutorial - Setup Horde with Gtkmm]] - How to Setup Horde with Gtkmm&lt;br /&gt;
&lt;br /&gt;
===Intermediate===&lt;br /&gt;
#[[Basic Pipeline Tutorial]] - Create your first custom pipeline.&lt;br /&gt;
&lt;br /&gt;
===Advanced===&lt;br /&gt;
''to come in the future''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Techniques==&lt;br /&gt;
[[Category: Techniques]]&lt;br /&gt;
&lt;br /&gt;
===Shading===&lt;br /&gt;
#[[Shading Technique - Dot Product Detail Texturing]] - Using the dot product of vectors and signed textures for high frequency detail&lt;br /&gt;
#[[Shading Technique - Palette Coloring]] - Quick and dirty palette recoloration of objects&lt;br /&gt;
#[[Shading Technique - Gloss Mapping]] - Mask which areas of an object have specular highlights&lt;br /&gt;
#[[Shading Technique - Glow Mapping]] - Allow areas on an object to emit a strong glowing highlight&lt;br /&gt;
#[[Shading Technique - Fresnel]] - Using reflection and refraction&lt;br /&gt;
#[[Shading Technique - Linear Depth Buffer]] - Create a custom linear depth buffer using vertex&lt;br /&gt;
#[[Shading Technique - Terrain Shading]] - Height and slope based shading with triplanar texturing&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Content Import==&lt;br /&gt;
[[Category: Content Import]]&lt;br /&gt;
#[[Collada - 3DS Max and Maya]] - Exporting from 3D Studio Max and Maya.&lt;br /&gt;
#[[Collada - XSI]] - Exporting from XSI.&lt;br /&gt;
#[[Collada - Modo]] - Exporting from Modo.&lt;br /&gt;
#[[Direct Export from Blender]] - Exporting from Blender.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Ecksp</name></author>	</entry>

	</feed>