Difference between revisions of "Shading Technique - Glow Mapping"

From Horde3D Wiki
Jump to: navigation, search
(draft)
 
m (fixed a typo)
 
(2 intermediate revisions by the same user not shown)
Line 7: Line 7:
 
== Overview ==
 
== Overview ==
 
For an in-depth overview of this technique, see the Gamasutra article [http://www.gamasutra.com/features/20040526/james_pfv.htm Real-Time Glow] by By Greg James and John O’Rorke.
 
For an in-depth overview of this technique, see the Gamasutra article [http://www.gamasutra.com/features/20040526/james_pfv.htm 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'''
 +
 +
{{CppSourceCode|
 +
description= Setup the RenderTargets. If this is for HDR, then these RenderTargets will already exist, so just change depthBuf to "true" on the first one|
 +
code=
 +
<source lang="cpp" line="1">
 +
<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>
 +
</source>}}
 +
 +
 +
{{CppSourceCode|
 +
description= insert this new stage after the "Geometry" stage.|
 +
code=
 +
<source lang="cpp" line="1">
 +
<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>
 +
</source>}}
 +
 +
 +
'''New shader code'''
 +
 +
{{CppSourceCode|
 +
description= This context is designed to be added to a copy of the parallax shader - parallax_glow.shader.xml|
 +
code=
 +
<source lang="cpp" line="1">
 +
<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>
 +
</source>}}
 +
 +
 +
 +
{{CppSourceCode|
 +
description= This is a new shader, called postGlow.shader.xml|
 +
code=
 +
<source lang="cpp" line="1">
 +
<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>
 +
</source>}}
 +
 +
 +
{{CppSourceCode|
 +
description= The material to go with the postGlow shader - postGlow.material.xml|
 +
code=
 +
<source lang="cpp" line="1">
 +
<Material>
 +
<Shader source="postGlow.shader.xml"/>
 +
</Material>
 +
</source>}}
 +
 +
 +
 +
{{CppSourceCode|
 +
description= This context is designed to be added to the original skinning shaders - skinning.shader.xml and skinning_metal.shader.xml|
 +
code=
 +
<source lang="cpp" line="1">
 +
<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>
 +
</source>}}
 +
  
 
== Example Result ==  
 
== Example Result ==  

Latest revision as of 01:15, 8 August 2008

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