Give your model a new look
The 3DPixelArt geometry shader was made as a final assignment for the Graphics Programming course of DAE. The goal was to write a hlsl shader that shows you are capable of using the geometry shader and implement it into a given game engine.
The shader loops over the triangles of the base-mesh and generates cubes at a possition snapped to a 3D-grid of given size. The color of the cubes are sampled of the diffuse texture of the base model.
The size of the cubes can be altered by changing the parameters.
The goblin used in this presentation was created by Kenny Guillaume
Video
3DPixelArt Geometry shader example from Stijn Doyen on Vimeo.
Screenshots
Shader code
Show/Hide shader code
//************ // VARIABLES * //************ cbuffer cbPerObject { float4x4 matWorld : World; float4x4 matWorldViewProj : WorldViewProjection; float4x4 matViewInv : VIEWINVERSE; float4 vLightDir : DIRECTION < string UIName = "Point Lamp 0 Position"; string Object = "PointLight"; string Space = "World"; > = {-54.0f, 50.0f, 100.0f, 1.0f}; } float m_BlockSize = 2; BlendState NoBlend { BlendEnable[0] = FALSE; }; RasterizerState BackCulling { CullMode = BACK; //FillMode = WIREFRAME; }; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap;// of Mirror of Clamp of Border AddressV = Wrap;// of Mirror of Clamp of Border }; Texture2D m_TextureDiffuse; //********** // STRUCTS * //********** struct VS_DATA { float3 Position : POSITION; float3 Normal : NORMAL; float2 TexCoord : TEXCOORD; }; struct GS_DATA { float4 Position : SV_POSITION; float4 WorldPosition: COLOR1; //if you give position as semantic, you lose one variable (pos = float3, color = float4) float3 Normal : NORMAL; float3 Color : Color; }; //**************** // VERTEX SHADER * //**************** VS_DATA MainVS(VS_DATA vsData) { return vsData; } //****************** // GEOMETRY SHADERS * //****************** void CreateVertexWVP(inout TriangleStream<GS_DATA> tStream, VS_DATA newVertex, float3 color) { GS_DATA temp; temp.Position = mul(float4(newVertex.Position,1),matWorldViewProj); temp.WorldPosition = mul(float4(newVertex.Position,1),matWorld); temp.Normal = mul(newVertex.Normal, (float3x3)matWorld); temp.Color = color; tStream.Append(temp); } [maxvertexcount(24)] void Cubifier(triangle VS_DATA vertices[3], inout TriangleStream<GS_DATA> tStream) { float3 center = vertices[0].Position + vertices[1].Position + vertices[2].Position; center/=3; center = floor(center/m_BlockSize); center *= m_BlockSize; float halfSize = m_BlockSize/2; float3 color = float3(1,1,1); color = m_TextureDiffuse.SampleLevel(samLinear,vertices[0].TexCoord,0); color += m_TextureDiffuse.SampleLevel(samLinear,vertices[1].TexCoord,0); color += m_TextureDiffuse.SampleLevel(samLinear,vertices[2].TexCoord,0); color/=3; VS_DATA A,B,C,D; //X-1 // A:Y+1,Z-1 B:Y+1,Z+1 // C:Y-1,Z-1 D:Y-1,Z+1 A.Position = center + float3(-1,+1,-1) * halfSize; B.Position = center + float3(-1,+1,+1) * halfSize; C.Position = center + float3(-1,-1,-1) * halfSize; D.Position = center + float3(-1,-1,+1) * halfSize; A.Normal = float3(-1,0,0); B.Normal = float3(-1,0,0); C.Normal = float3(-1,0,0); D.Normal = float3(-1,0,0); A.TexCoord = float2(0,0); B.TexCoord = float2(1,0); C.TexCoord = float2(0,1); D.TexCoord = float2(1,1); CreateVertexWVP(tStream,A, color); CreateVertexWVP(tStream,B, color); CreateVertexWVP(tStream,C, color); CreateVertexWVP(tStream,D, color); tStream.RestartStrip(); //Y-1 // A:X-1,Z+1 B:X+1,Z+1 // C:X-1,Z-1 D:X+1,Z-1 // A.Position = center + float3(-1,-1,+1) * halfSize; B.Position = center + float3(+1,-1,+1) * halfSize; C.Position = center + float3(-1,-1,-1) * halfSize; D.Position = center + float3(+1,-1,-1) * halfSize; A.Normal = float3(0,-1,0); B.Normal = float3(0,-1,0); C.Normal = float3(0,-1,0); D.Normal = float3(0,-1,0); CreateVertexWVP(tStream,A, color); CreateVertexWVP(tStream,B, color); CreateVertexWVP(tStream,C, color); CreateVertexWVP(tStream,D, color); tStream.RestartStrip(); //Z-1 // A:X+1,Y+1 B:X-1,Y+1 // C:X+1,Y-1 D:X-1,Y-1 // A.Position = center + float3(+1,+1,-1) * halfSize; B.Position = center + float3(-1,+1,-1) * halfSize; C.Position = center + float3(+1,-1,-1) * halfSize; D.Position = center + float3(-1,-1,-1) * halfSize; A.Normal = float3(0,0,-1); B.Normal = float3(0,0,-1); C.Normal = float3(0,0,-1); D.Normal = float3(0,0,-1); CreateVertexWVP(tStream,A, color); CreateVertexWVP(tStream,B, color); CreateVertexWVP(tStream,C, color); CreateVertexWVP(tStream,D, color); tStream.RestartStrip(); //X+1 // A:Y+1,Z+1 B:Y+1,Z-1 // C:Y-1,Z+1 D:Y-1,Z-1 // A.Position = center + float3(+1,+1,+1)*halfSize; B.Position = center + float3(+1,+1,-1)*halfSize; C.Position = center + float3(+1,-1,+1)*halfSize; D.Position = center + float3(+1,-1,-1)*halfSize; A.Normal = float3(+1,0,0); B.Normal = float3(+1,0,0); C.Normal = float3(+1,0,0); D.Normal = float3(+1,0,0); CreateVertexWVP(tStream,A, color); CreateVertexWVP(tStream,B, color); CreateVertexWVP(tStream,C, color); CreateVertexWVP(tStream,D, color); tStream.RestartStrip(); //Z+1 // A:X-1,Y+1 B:X+1,Y+1 // C:X-1,Y-1 D:X+1,Y-1 // A.Position = center + float3(-1,+1,+1)*halfSize; B.Position = center + float3(+1,+1,+1)*halfSize; C.Position = center + float3(-1,-1,+1)*halfSize; D.Position = center + float3(+1,-1,+1)*halfSize; A.Normal = float3(0,0,1); B.Normal = float3(0,0,1); C.Normal = float3(0,0,1); D.Normal = float3(0,0,1); CreateVertexWVP(tStream,A, color); CreateVertexWVP(tStream,B, color); CreateVertexWVP(tStream,C, color); CreateVertexWVP(tStream,D, color); tStream.RestartStrip(); //Y+1 // A:X-1,Z-1 B:X+1,Z-1 // C:X-1,Z+1 D:X+1,Z+1 // A.Position = center + float3(-1,+1,-1)*halfSize; B.Position = center + float3(+1,+1,-1)*halfSize; C.Position = center + float3(-1,+1,+1)*halfSize; D.Position = center + float3(+1,+1,+1)*halfSize; A.Normal = float3(0,1,0); B.Normal = float3(0,1,0); C.Normal = float3(0,1,0); D.Normal = float3(0,1,0); CreateVertexWVP(tStream,A, color); CreateVertexWVP(tStream,B, color); CreateVertexWVP(tStream,C, color); CreateVertexWVP(tStream,D, color); tStream.RestartStrip(); } //*************** // PIXEL SHADER * //*************** float4 MainPS(GS_DATA input) : SV_TARGET { input.Normal=-normalize(input.Normal); float3 diffColor = input.Color; float diffuseStrenght = dot(input.Normal, -vLightDir); diffuseStrenght = saturate(diffuseStrenght); diffColor *= diffuseStrenght; float3 specularColor = float3(1,1,1); float3 viewDirection = normalize(input.WorldPosition.xyz - matViewInv[3].xyz); float3 hn = normalize(viewDirection + vLightDir); float specularStrenght = dot(input.Normal, - hn); specularStrenght = saturate(specularStrenght); specularStrenght = pow(specularStrenght, 10); specularColor*= specularStrenght; diffColor+=specularColor; return float4(diffColor,1); } //************* // TECHNIQUES * //************* technique10 DefaultTechnique { pass p0 { SetVertexShader(CompileShader(vs_4_0, MainVS())); SetGeometryShader(CompileShader(gs_4_0, Cubifier())); SetPixelShader(CompileShader(ps_4_0, MainPS())); SetRasterizerState(BackCulling); SetBlendState(NoBlend, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff); } }
Used software
- Visual Studio 2012
- Nvidia Shader FX
- Overlord Engine