Project

General

Profile

SO3Engine
SO3GBufferMaterialGenerator.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
27#include "OgreMaterialManager.h"
28#include "OgreGpuProgramManager.h"
29#include "OgreStringConverter.h"
30#include "OgreHighLevelGpuProgramManager.h"
31#include "OgreTechnique.h"
32
33//Use this directive to control whether you are writing projective (regular) or linear depth.
34#define WRITE_LINEAR_DEPTH
35
36namespace SO3
37{
38
42
43void SGBufferMaterialGenerator::FreeMaterial(const Ogre::MaterialPtr& ogreMaterial)
44{
45 unsigned short techniqueIndex = 0;
46 Ogre::Material::TechniqueIterator iOgreTechnique = ogreMaterial->getTechniqueIterator();
47 while(iOgreTechnique.hasMoreElements())
48 {
49 Ogre::Technique* ogreTechnique = iOgreTechnique.getNext();
50 if((ogreTechnique->getName() == "GBuffer") || (ogreTechnique->getName() == "NoGBuffer"))
51 {
52 ogreMaterial->removeTechnique(techniqueIndex);
53 iOgreTechnique = ogreMaterial->getTechniqueIterator();
54 techniqueIndex = 0;
55 }
56 else
57 {
58 techniqueIndex++;
59 }
60 }
61}
62
63Ogre::GpuProgramPtr SGBufferMaterialGenerator::GenerateVertexShader(SGBuffer* gbuffer, Ogre::uint32 permutationValue)
64{
65 Ogre::StringStream ss;
66
67 // Starting to write the vertex shader function signature
68 ss << "void ToGBufferVP(" << std::endl;
69 ss << " float4 iPosition : POSITION," << std::endl;
70 ss << " float3 iNormal : NORMAL," << std::endl;
71
72 Ogre::uint32 numTexCoords = (permutationValue & SGBufferMaterialPermutation::SO3_GBP_TEXCOORD_MASK) >> 8;
73 for (Ogre::uint32 i=0; i<numTexCoords; i++)
74 ss << " float2 iUV" << i << " : TEXCOORD" << i << ',' << std::endl;
75
77 ss << " float3 iTangent : TANGENT0," << std::endl;
78
79 //TODO : Skinning inputs
80 ss << std::endl;
81
82 ss << " out float4 oPosition : POSITION," << std::endl;
83#ifdef WRITE_LINEAR_DEPTH
84 ss << " out float3 oViewPos : TEXCOORD0," << std::endl;
85#else
86 ss << " out float oDepth : TEXCOORD0," << std::endl;
87#endif
88
89 ss << " out float3 oNormal : TEXCOORD1," << std::endl;
90 int texCoordNum = 2;
92 {
93 ss << " out float3 oTangent : TEXCOORD" << texCoordNum++ << ',' << std::endl;
94 ss << " out float3 oBiNormal : TEXCOORD" << texCoordNum++ << ',' << std::endl;
95 }
96
97 for (Ogre::uint32 i=0; i<numTexCoords; i++)
98 ss << " out float2 oUV" << i << " : TEXCOORD" << texCoordNum++ << ',' << std::endl;
99
100 ss << std::endl;
101 ss << " uniform float4x4 wvp," << std::endl;
102 ss << " uniform float4x4 wv" << std::endl;
103 ss << " )" << std::endl;
104
105 // Starting to write the vertex shader function content
106 ss << "{" << std::endl;
107 ss << " oPosition = mul(wvp, iPosition);" << std::endl;
108 ss << " oNormal = mul(wv, float4(iNormal,0)).xyz;" << std::endl;
110 {
111 ss << " oTangent = mul(wv, float4(iTangent,0)).xyz;" << std::endl;
112 ss << " oBiNormal = cross(oNormal, oTangent);" << std::endl;
113 }
114
115#ifdef WRITE_LINEAR_DEPTH
116 ss << " oViewPos = mul(wv, iPosition).xyz;" << std::endl;
117#else
118 ss << " oDepth = oPosition.w;" << std::endl;
119#endif
120
121 for (Ogre::uint32 i=0; i<numTexCoords; i++)
122 ss << " oUV" << i << " = iUV" << i << ';' << std::endl;
123
124 ss << "}" << std::endl;
125 // The vertex shader has been completely generated
126
127 Ogre::String programSource = ss.str();
128 Ogre::String programName = materialBaseName + "VP_" + Ogre::StringConverter::toString(permutationValue);
129
130#if SO3_DEBUG
131 // Show the generated vertex program in the log.
132 Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(programSource, Ogre::LML_CRITICAL);
133#endif
134
135 // Create shader object
136 // TODO in another group than Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME?
137 Ogre::HighLevelGpuProgramPtr ptrProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(programName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", Ogre::GPT_VERTEX_PROGRAM);
138 ptrProgram->setSource(programSource);
139 ptrProgram->setParameter("entry_point", "ToGBufferVP");
140 ptrProgram->setParameter("profiles", "vs_1_1 arbvp1");
141
142 // Bind our function parameters to Ogre's related values.
143 const Ogre::GpuProgramParametersSharedPtr& params = ptrProgram->getDefaultParameters();
144 if (params->_findNamedConstantDefinition("wvp"))
145 params->setNamedAutoConstant("wvp", Ogre::GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
146
147 if (params->_findNamedConstantDefinition("wv"))
148 params->setNamedAutoConstant("wv", Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX);
149
150 ptrProgram->load();
151
152 return Ogre::GpuProgramPtr(ptrProgram);
153}
154
155Ogre::GpuProgramPtr SGBufferMaterialGenerator::GenerateFragmentShader(SGBuffer* gbuffer, Ogre::uint32 permutationValue)
156{
157 Ogre::StringStream ss;
158
159 // Adding gbuffer variable type definition
161
162 // Starting to write the fragment shader function signature
163 ss << "void ToGBufferFP(" << std::endl;
164#ifdef WRITE_LINEAR_DEPTH
165 ss << " float3 iViewPos : TEXCOORD0," << std::endl;
166#else
167 ss << " float1 iDepth : TEXCOORD0," << std::endl;
168#endif
169
170 ss << " float3 iNormal : TEXCOORD1," << std::endl;
171 int texCoordNum = 2;
173 {
174 ss << " float3 iTangent : TEXCOORD" << texCoordNum++ << ',' << std::endl;
175 ss << " float3 iBiNormal : TEXCOORD" << texCoordNum++ << ',' << std::endl;
176 }
177
178 Ogre::uint32 numTexCoords = (permutationValue & SGBufferMaterialPermutation::SO3_GBP_TEXCOORD_MASK) >> 8;
179 for (Ogre::uint32 i=0; i<numTexCoords; i++)
180 ss << " float2 iUV" << i << " : TEXCOORD" << texCoordNum++ << ',' << std::endl;
181
182 ss << std::endl;
183 ss << " out "<< gbuffer->GetGBufferMaterialPixelOutputStructureTypeName() << " gbuffer," << std::endl;
184 ss << std::endl;
185
186 int samplerNum = 0;
188 ss << " uniform sampler2D sNormalMap : register(s" << samplerNum++ << ")," << std::endl;
189
191 ss << " uniform sampler2D sSpecularMap : register(s" << samplerNum++ << ")," << std::endl;
192
194 ss << " uniform sampler2D sLightMap : register(s" << samplerNum++ << ")," << std::endl;
195
196 Ogre::uint32 numTextures = permutationValue & SGBufferMaterialPermutation::SO3_GBP_TEXTURE_MASK;
197 for (Ogre::uint32 i=0; i<numTextures; i++)
198 ss << " uniform sampler2D sTex" << i << " : register(s" << samplerNum++ << ")," << std::endl;
199
200 if (numTextures == 0 || permutationValue & SGBufferMaterialPermutation::SO3_GBP_HAS_DIFFUSE_COLOUR)
201 ss << " uniform float4 cDiffuseColour," << std::endl;
202
204 ss << " uniform float4 cSpecularColour," << std::endl;
205
207 ss << " uniform float4 cEmissiveColour," << std::endl;
208
210 ss << " uniform float cRejectAlpha," << std::endl;
211
212#ifdef WRITE_LINEAR_DEPTH
213 ss << " uniform float cFarDistance," << std::endl;
214#endif
215
216 ss << " uniform float cSpecularity" << std::endl;
217 ss << " )" << std::endl;
218
219 // Starting to write the fragment shader function content
220 ss << "{" << std::endl;
221
222 // reset gbuffer var
223 ss << " gbuffer.Reset();" << std::endl;
224
225 // Diffuse component
226 if (numTexCoords > 0 && numTextures > 0)
227 {
228 ss << " float4 textureColor = tex2D(sTex0, iUV0);" << std::endl;
230 ss << " textureColor.rgb *= cDiffuseColour.rgb;" << std::endl;
231 }
232 else
233 {
234 ss << " float4 textureColor = float4(cDiffuseColour.rgb, 1);" << std::endl;
235 }
236
237 // Alpha rejection test. Stop the shader processing if condition is true.
239 {
240 ss << " if(textureColor.a <= cRejectAlpha)" << std::endl;
241 ss << " discard;" << std::endl;
242 }
243
244 // Use light map for diffuse light contrib
246 {
247 ss << " float4 lighting = tex2D(sLightMap, iUV0);" << std::endl;
248 ss << " textureColor = float4(textureColor.rgb * lighting.rgb + lighting.a, 1);" << std::endl;
249 }
250
251 // Set diffuse color
252 ss << " gbuffer.SetDiffuse(textureColor.rgb);" << std::endl;
253
254 // Depth
255#ifdef WRITE_LINEAR_DEPTH
256 ss << " gbuffer.SetDepth(length(iViewPos) / cFarDistance);" << std::endl;
257#else
258 ss << " gbuffer.SetDepth(iDepth);" << std::endl;
259#endif
260
261 // Specular colour
262 ss << " float3 specularColour = float3(0, 0, 0);" << std::endl;
264 {
265 ss << " specularColour = tex2D(sSpecularMap, iUV0).rgb;" << std::endl;
267 ss << " specularColour *= cSpecularColour.rgb" << std::endl;
268 }
269 else
270 {
272 ss << " specularColour = cSpecularColour.rgb;" << std::endl;
273 }
274
275 // Write specular colour to gbuffer
276 ss << " gbuffer.SetSpecular(specularColour);" << std::endl;
277
278 // Shininess
279 ss << " gbuffer.SetShininess(cSpecularity);" << std::endl;
280
281 // Emissive factor
283 ss << " gbuffer.SetEmissive((cEmissiveColour.r + cEmissiveColour.g + cEmissiveColour.b) / 3);" << std::endl;
284
285 // Normal
287 {
288 ss << " float3 texNormal = (tex2D(sNormalMap, iUV0)-0.5)*2;" << std::endl;
289 ss << " float3x3 normalRotation = float3x3(iTangent, iBiNormal, iNormal);" << std::endl;
290 ss << " gbuffer.SetNormal(normalize(mul(texNormal, normalRotation)));" << std::endl;
291 }
292 else
293 {
294 ss << " gbuffer.SetNormal(normalize(iNormal));" << std::endl;
295 }
296 ss << "}" << std::endl;
297 // The fragment shader has been completely generated
298
299 Ogre::String programSource = ss.str();
300 Ogre::String programName = materialBaseName + "FP_" + Ogre::StringConverter::toString(permutationValue);
301
302#if SO3_DEBUG
303 // Show the generated fragment program in the log.
304 Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(programSource, Ogre::LML_CRITICAL);
305#endif
306
307 // Create shader object
308 Ogre::HighLevelGpuProgramPtr ptrProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(programName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", Ogre::GPT_FRAGMENT_PROGRAM);
309 ptrProgram->setSource(programSource);
310 ptrProgram->setParameter("entry_point","ToGBufferFP");
311 ptrProgram->setParameter("profiles","ps_2_0 arbfp1");
312
313 // Bind our function parameters to Ogre's related values.
314 const Ogre::GpuProgramParametersSharedPtr& params = ptrProgram->getDefaultParameters();
315 if (params->_findNamedConstantDefinition("cSpecularity"))
316 params->setNamedAutoConstant("cSpecularity", Ogre::GpuProgramParameters::ACT_SURFACE_SHININESS);
317
318 if ((numTextures == 0 || permutationValue & SGBufferMaterialPermutation::SO3_GBP_HAS_DIFFUSE_COLOUR) && (params->_findNamedConstantDefinition("cDiffuseColour")))
319 params->setNamedAutoConstant("cDiffuseColour", Ogre::GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
320
321 if ((permutationValue & SGBufferMaterialPermutation::SO3_GBP_HAS_SPECULAR_COLOUR) && (params->_findNamedConstantDefinition("cSpecularColour")))
322 params->setNamedAutoConstant("cSpecularColour", Ogre::GpuProgramParameters::ACT_SURFACE_SPECULAR_COLOUR);
323
324 if ((permutationValue & SGBufferMaterialPermutation::SO3_GBP_HAS_EMISSIVE_COLOUR) && (params->_findNamedConstantDefinition("cEmissiveColour")))
325 params->setNamedAutoConstant("cEmissiveColour", Ogre::GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
326#ifdef WRITE_LINEAR_DEPTH
327 //TODO : Should this be the distance to the far corner, not the far clip distance?
328 if (params->_findNamedConstantDefinition("cFarDistance"))
329 params->setNamedAutoConstant("cFarDistance", Ogre::GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
330#endif
331 ptrProgram->load();
332
333 return Ogre::GpuProgramPtr(ptrProgram);
334}
335
336Ogre::MaterialPtr SGBufferMaterialGenerator::GenerateTemplateMaterial(SGBuffer* gbuffer, Ogre::uint32 permutationValue)
337{
338 Ogre::String matName = materialBaseName + "Mat_" + Ogre::StringConverter::toString(permutationValue);
339
340 Ogre::MaterialPtr matPtr = Ogre::MaterialManager::getSingleton().create(matName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
341 Ogre::Pass* pass = matPtr->getTechnique(0)->getPass(0);
342 pass->setName(materialBaseName + "Pass_" + Ogre::StringConverter::toString(permutationValue));
343 pass->setLightingEnabled(false);
344
346 pass->createTextureUnitState();
347
349 pass->createTextureUnitState();
350
352 pass->createTextureUnitState();
353
354 Ogre::uint32 numTextures = permutationValue & SGBufferMaterialPermutation::SO3_GBP_TEXTURE_MASK;
355 for (Ogre::uint32 i=0; i<numTextures; i++)
356 pass->createTextureUnitState();
357
358 return matPtr;
359}
360
361}
Ogre::String GetGBufferMaterialPixelOutputStructureTypeName()
Ogre::String GenerateGBufferMaterialPixelOutputStructure()
virtual Ogre::GpuProgramPtr GenerateVertexShader(SGBuffer *gbuffer, Ogre::uint32 permutationValue)
void FreeMaterial(const Ogre::MaterialPtr &ogreMaterial)
virtual Ogre::MaterialPtr GenerateTemplateMaterial(SGBuffer *gbuffer, Ogre::uint32 permutationValue)
virtual Ogre::GpuProgramPtr GenerateFragmentShader(SGBuffer *gbuffer, Ogre::uint32 permutationValue)
const Ogre::String materialBaseName
Base name of materials generated by this.