Shading Technique - Glow Mapping

From Horde3D Wiki
Jump to: navigation, search

I'm in the process of writing this article - come back later!

Overview

For an in-depth overview of this technique, see the Gamasutra article Real-Time Glow by By Greg James and John O’Rorke.

Temporary code dump

Until I finish writing this article, here's the undocumented code ;)

Pipeline changes

Setup the RenderTargets. If this is for HDR, then these RenderTargets will already exist, so just change depthBuf to "true" on the first one
<Setup>
	<RenderTarget id="BLURBUF1" depthBuf="true"  numColBufs="1" format="RGBA8" bilinear="true" scale="0.25" />
	<RenderTarget id="BLURBUF2" depthBuf="false" numColBufs="1" format="RGBA8" bilinear="true" scale="0.25" />
</Setup>


insert this new stage after the "Geometry" stage.
<stage id="Glow">
	<SwitchTarget target="BLURBUF1" />			
	<ClearTarget depthBuf="true" colBuf0="true" />
	<DrawGeometry context="GLOWMASK" />
	
	<!-- Repeat these steps as many times as you like, it makes the bloom softer -->
	<SwitchTarget target="BLURBUF2" />
	<BindBuffer texUnit="0" target="BLURBUF1" bufIndex="0" />
	<DrawQuad   material="postGlow.material.xml" context="BLURV" />
	<SwitchTarget target="BLURBUF1" />
	<BindBuffer texUnit="0" target="BLURBUF2" bufIndex="0" />
	<DrawQuad   material="postGlow.material.xml" context="BLURH" />
	
	<SwitchTarget target="BLURBUF2" />
	<BindBuffer texUnit="0" target="BLURBUF1" bufIndex="0" />
	<DrawQuad   material="postGlow.material.xml" context="BLURV" />
	<SwitchTarget target="BLURBUF1" />
	<BindBuffer texUnit="0" target="BLURBUF2" bufIndex="0" />
	<DrawQuad   material="postGlow.material.xml" context="BLURH" />
	
	<SwitchTarget target="BLURBUF2" />
	<BindBuffer texUnit="0" target="BLURBUF1" bufIndex="0" />
	<DrawQuad   material="postGlow.material.xml" context="BLURV" />
	<SwitchTarget target="BLURBUF1" />
	<BindBuffer texUnit="0" target="BLURBUF2" bufIndex="0" />
	<DrawQuad   material="postGlow.material.xml" context="BLURH" />
	
	<!-- In the HDR version, target should be set to "HDRBUF" -->
	<SwitchTarget target="" />
	<BindBuffer texUnit="0" target="BLURBUF1" bufIndex="0" />
	<DrawQuad material="postGlow.material.xml" context="FINALPASS" />
</stage>


New shader code

This context is designed to be added to a copy of the parallax shader - parallax_glow.shader.xml
<Context id="GLOWMASK">	
	<!-- This material does glow - output colors masked by the alpha channel -->
	<VertexShader>
		<InsCode code="utilityLib/vertCommon.glsl" />
		<DefCode>
		<![CDATA[
			uniform vec3 viewer;
			attribute vec2 texCoords0;
			attribute vec3 normal, tangent, bitangent;
			varying vec3 eyeTS;
			varying vec2 texCoords;
			varying vec4 pos;
		
			void main( void )
			{
				// Transform tangent space basis
				vec3 tsbTangent = normalize( calcWorldVec( tangent ) );
				vec3 tsbBitangent = normalize( calcWorldVec( bitangent ) );
				vec3 tsbNormal = normalize( calcWorldVec( normal ) );
				
				// Calculate world space position
				pos = calcWorldPos( gl_Vertex );
				
				// Eye vector and eye vector in tangent space
				eyeTS = calcTanVec( viewer - pos.xyz, tsbTangent, tsbBitangent, tsbNormal );
		
				// Calculate texture coordinates and clip space position
				texCoords = texCoords0;
				gl_Position = gl_ModelViewProjectionMatrix * pos;
			}
		]]>
		</DefCode>
	</VertexShader>
	
	<FragmentShader>
		<DefCode>
		<![CDATA[
			uniform sampler2D tex0;
			varying vec3 eyeTS;
			varying vec2 texCoords;
			
			void main( void )
			{
				const float plxScale = 0.03;
				const float plxBias = -0.015;
				
				// Iterative parallax mapping
				vec3 newCoords = vec3( texCoords, 0 );
				vec3 eye = normalize( eyeTS );
				for( int i = 0; i < 4; ++i )
				{
					vec4 nmap = texture2D( tex0, texCoords.st );
					float height = nmap.a * plxScale + plxBias;
					newCoords += (height - newCoords.p) * nmap.z * eye;
				}
				
				vec4 glow = texture2D( tex0, newCoords.st ).rgba;
				glow *= glow.a;
				
				gl_FragColor = glow;
			}
		]]>
		</DefCode>
	</FragmentShader>
</Context>


This is a new shader, called postGlow.shader.xml
<Shader>
	
	<Context id="BLURH">
		<RenderConfig writeDepth="false" />
		<VertexShader>
			<DefCode>
			<![CDATA[
				varying vec2 texCoord;
				void main( void )
				{
					texCoord = gl_MultiTexCoord0.st; 
					gl_Position = gl_ProjectionMatrix * gl_Vertex;
				}
			]]>
			</DefCode>
		</VertexShader>
		<FragmentShader>
			<InsCode code="utilityLib/fragPostProcess.glsl" />
			<DefCode>
			<![CDATA[
				uniform sampler2D tex;
				uniform vec2 frameBufSize;
				varying vec2 texCoord;
				void main( void )
				{	
					float halfPixel = 0.5 / frameBufSize.x;
					vec4 col  = texture2D( tex, texCoord + vec2( halfPixel,   0.0 ) );
					     col += texture2D( tex, texCoord - vec2( halfPixel,   0.0 ) );
					     col += texture2D( tex, texCoord + vec2( halfPixel*3.0, 0.0 ) );
					     col += texture2D( tex, texCoord - vec2( halfPixel*3.0, 0.0 ) );
					gl_FragColor = col * 0.25; 
				}
			]]>
			</DefCode>
		</FragmentShader>
	</Context>
	<Context id="BLURV">
		<RenderConfig writeDepth="false" />
		<VertexShader>
			<DefCode>
			<![CDATA[
				varying vec2 texCoord;
				void main( void )
				{
					texCoord = gl_MultiTexCoord0.st; 
					gl_Position = gl_ProjectionMatrix * gl_Vertex;
				}
			]]>
			</DefCode>
		</VertexShader>
		<FragmentShader>
			<InsCode code="utilityLib/fragPostProcess.glsl" />
			<DefCode>
			<![CDATA[
				uniform sampler2D tex;
				uniform vec2 frameBufSize;
				varying vec2 texCoord;
				void main( void )
				{	
					float halfPixel = 0.5 / frameBufSize.y;
					vec4 col  = texture2D( tex, texCoord + vec2( 0.0, halfPixel   ) );
					     col += texture2D( tex, texCoord - vec2( 0.0, halfPixel   ) );
					     col += texture2D( tex, texCoord + vec2( 0.0, halfPixel*3.0 ) );
					     col += texture2D( tex, texCoord - vec2( 0.0, halfPixel*3.0 ) );
					gl_FragColor = col * 0.25;
				}
			]]>
			</DefCode>
		</FragmentShader>
	</Context>
	
	<Context id="FINALPASS">
		<RenderConfig writeDepth="false" blendMode="ADD" />
		
		<VertexShader>
			<DefCode>
			<![CDATA[
				varying vec2 texCoord;
				
				void main( void )
				{
					texCoord = gl_MultiTexCoord0.st; 
					gl_Position = gl_ProjectionMatrix * gl_Vertex;
				}
			]]>
			</DefCode>
		</VertexShader>
		
		<FragmentShader>
			<DefCode>
			<![CDATA[
				uniform sampler2D tex0, tex1;
				uniform vec2 frameBufSize;
				uniform vec4 hdrParams;
				varying vec2 texCoord;
				
				void main( void )
				{
					gl_FragColor = texture2D( tex0, texCoord );	// Glow color
				}
			]]>
			</DefCode>
		</FragmentShader>
	</Context>
</Shader>


The material to go with the postGlow shader - postGlow.material.xml
<Material>
	<Shader source="postGlow.shader.xml"/>
</Material>


This context is designed to be added to the original skinning shaders - skinning.shader.xml and skinning_metal.shader.xml
<Context id="GLOWMASK">	
	<!-- This material does not glow - output black pixels -->
	<VertexShader>
		<InsCode code="utilityLib/vertCommon.glsl" />
		<InsCode code="utilityLib/vertSkinning.glsl" />
		<DefCode>
		<![CDATA[
			void main( void )
			{
				// Calculate skinning matrices
				mat4 skinningMat = calcSkinningMat();
				mat3 skinningMatVec = getSkinningMatVec( skinningMat );
				// Calculate world space position
				vec4 pos = calcWorldPos( skinPos( gl_Vertex, skinningMat ) );
				// Calculate clip space position
				gl_Position = gl_ModelViewProjectionMatrix * pos;
			}
		]]>
		</DefCode>
	</VertexShader>
	
	<FragmentShader>
		<InsCode code="utilityLib/fragLighting.glsl" />
		<DefCode>
		<![CDATA[
			void main( void )
			{
				gl_FragColor.rgb = vec3(0,0,0);
			}
		]]>
		</DefCode>
	</FragmentShader>
</Context>


Example Result

Click here to view

To-Do List for this Article

- Write the article, describe the code and pipeline changes required
- Add pictures
- Ask for permission to upload a ZIP of my finished xml/tga files ;)

Technique - Glow
File:Todo.jpg
Using an alpha channel to add emissive bloom.
Version: 1.0
Compatible with Horde3D: 1.0 beta
Release date: 2008-08-06
Author(s): DarkAngel