Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
OgreTerrainPSSMMaterialGenerator.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2012 Torus Knot Software Ltd
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in
17all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25THE SOFTWARE.
26-----------------------------------------------------------------------------
27*/
29
30#include <Terrain/OgreTerrain.h>
31#include <OgreMaterialManager.h>
32#include <OgreTechnique.h>
33#include <OgrePass.h>
34#include <OgreTextureUnitState.h>
35#include <OgreGpuProgramManager.h>
36#include <OgreHighLevelGpuProgramManager.h>
37#include <OgreHardwarePixelBuffer.h>
38#include <OgreShadowCameraSetupPSSM.h>
39#include <OgreHighLevelGpuProgram.h>
40
41namespace Ogre {
42//---------------------------------------------------------------------
44{
45 // define the layers
46 // We expect terrain textures to have no alpha, so we use the alpha channel
47 // in the albedo texture to store specular reflection
48 // similarly we double-up the normal and height (for parallax)
49 mLayerDecl.samplers.push_back(TerrainLayerSampler("albedo_specular", PF_BYTE_RGBA));
50 mLayerDecl.samplers.push_back(TerrainLayerSampler("normal_height", PF_BYTE_RGBA));
51
52 mLayerDecl.elements.push_back(
53 TerrainLayerSamplerElement(0, TLSS_ALBEDO, 0, 3));
54 mLayerDecl.elements.push_back(
55 TerrainLayerSamplerElement(0, TLSS_SPECULAR, 3, 1));
56 mLayerDecl.elements.push_back(
57 TerrainLayerSamplerElement(1, TLSS_NORMAL, 0, 3));
58 mLayerDecl.elements.push_back(
59 TerrainLayerSamplerElement(1, TLSS_HEIGHT, 3, 1));
60
61 mProfiles.push_back(OGRE_NEW SM2Profile(this, "SM2", "Profile for rendering on Shader Model 2 capable cards"));
62 // TODO - check hardware capabilities & use fallbacks if required (more profiles needed)
63 setActiveProfile("SM2");
64}
65
66//---------------------------------------------------------------------
70
71//---------------------------------------------------------------------
72//---------------------------------------------------------------------
73TerrainPSSMMaterialGenerator::SM2Profile::SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc)
74 : Profile(parent, name, desc)
75 , mShaderGen(0)
76 , mLayerNormalMappingEnabled(true)
77 , mLayerParallaxMappingEnabled(true)
78 , mLayerSpecularMappingEnabled(true)
79 , mGlobalColourMapEnabled(true)
80 , mLightmapEnabled(true)
81 , mCompositeMapEnabled(true)
82 , mReceiveDynamicShadows(true)
83 , mPSSM(0)
84 , mDepthShadows(false)
85 , mLowLodShadows(false)
86{
87}
88
89//---------------------------------------------------------------------
91{
92 OGRE_DELETE mShaderGen;
93}
94
95//---------------------------------------------------------------------
97{
98 terrain->_setMorphRequired(true);
99 terrain->_setNormalMapRequired(true);
100 terrain->_setLightMapRequired(mLightmapEnabled, true);
101 terrain->_setCompositeMapRequired(mCompositeMapEnabled);
102}
103
104//---------------------------------------------------------------------
109
110//---------------------------------------------------------------------
112{
113 if (enabled != mLayerNormalMappingEnabled)
114 {
115 mLayerNormalMappingEnabled = enabled;
116 mParent->_markChanged();
117 }
118}
119
120//---------------------------------------------------------------------
122{
123 if (enabled != mLayerParallaxMappingEnabled)
124 {
125 mLayerParallaxMappingEnabled = enabled;
126 mParent->_markChanged();
127 }
128}
129
130//---------------------------------------------------------------------
132{
133 if (enabled != mLayerSpecularMappingEnabled)
134 {
135 mLayerSpecularMappingEnabled = enabled;
136 mParent->_markChanged();
137 }
138}
139
140//---------------------------------------------------------------------
142{
143 if (enabled != mGlobalColourMapEnabled)
144 {
145 mGlobalColourMapEnabled = enabled;
146 mParent->_markChanged();
147 }
148}
149
150//---------------------------------------------------------------------
152{
153 if (enabled != mLightmapEnabled)
154 {
155 mLightmapEnabled = enabled;
156 mParent->_markChanged();
157 }
158}
159
160//---------------------------------------------------------------------
162{
163 if (enabled != mCompositeMapEnabled)
164 {
165 mCompositeMapEnabled = enabled;
166 mParent->_markChanged();
167 }
168}
169
170//---------------------------------------------------------------------
172{
173 if (enabled != mReceiveDynamicShadows)
174 {
175 mReceiveDynamicShadows = enabled;
176 mParent->_markChanged();
177 }
178}
179
180//---------------------------------------------------------------------
182{
183 if (pssmSettings != mPSSM)
184 {
185 mPSSM = pssmSettings;
186 mParent->_markChanged();
187 }
188}
189
190//---------------------------------------------------------------------
192{
193 if (enabled != mDepthShadows)
194 {
195 mDepthShadows = enabled;
196 mParent->_markChanged();
197 }
198}
199
200//---------------------------------------------------------------------
202{
203 if (enabled != mLowLodShadows)
204 {
205 mLowLodShadows = enabled;
206 mParent->_markChanged();
207 }
208}
209
210//---------------------------------------------------------------------
212{
213 // count the texture units free
214 uint8 freeTextureUnits = 16;
215 // lightmap
216 --freeTextureUnits;
217 // normalmap
218 --freeTextureUnits;
219 // colourmap
220 if (terrain->getGlobalColourMapEnabled())
221 --freeTextureUnits;
222 if (isShadowingEnabled(HIGH_LOD, terrain))
223 {
224 uint numShadowTextures = 1;
225 if (getReceiveDynamicShadowsPSSM())
226 {
227 numShadowTextures = getReceiveDynamicShadowsPSSM()->getSplitCount();
228 }
229 freeTextureUnits -= numShadowTextures;
230 }
231
232 // each layer needs 2.25 units (1xdiffusespec, 1xnormalheight, 0.25xblend)
233 return static_cast<uint8>(freeTextureUnits / 2.16f);
234}
235
236//---------------------------------------------------------------------
237MaterialPtr TerrainPSSMMaterialGenerator::SM2Profile::generate(const Terrain* terrain)
238{
239 // re-use old material if exists
240 MaterialPtr mat = terrain->_getMaterial();
241 if (!mat)
242 {
243 MaterialManager& matMgr = MaterialManager::getSingleton();
244
245 // it's important that the names are deterministic for a given terrain, so
246 // use the terrain pointer as an ID
247 const String& matName = terrain->getMaterialName();
248 mat = matMgr.getByName(matName);
249 if (!mat)
250 {
251 mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
252 }
253 }
254 // clear everything
255 mat->removeAllTechniques();
256
257 // Automatically disable normal & parallax mapping if card cannot handle it
258 // We do this rather than having a specific technique for it since it's simpler
259 GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
260 if (!gmgr.isSyntaxSupported("ps_4_0") && !gmgr.isSyntaxSupported("ps_3_0") && !gmgr.isSyntaxSupported("ps_2_x")
261 && !gmgr.isSyntaxSupported("fp40") && !gmgr.isSyntaxSupported("arbfp1"))
262 {
263 setLayerNormalMappingEnabled(false);
264 setLayerParallaxMappingEnabled(false);
265 }
266
267 addTechnique(mat, terrain, HIGH_LOD);
268
269 // LOD
270 if (mCompositeMapEnabled)
271 {
272 addTechnique(mat, terrain, LOW_LOD);
273 Material::LodValueList lodValues;
274 lodValues.push_back(TerrainGlobalOptions::getSingleton().getCompositeMapDistance());
275 mat->setLodLevels(lodValues);
276 Technique* lowLodTechnique = mat->getTechnique(1);
277 lowLodTechnique->setLodIndex(1);
278 }
279
280 updateParams(mat, terrain);
281
282 return mat;
283}
284
285//---------------------------------------------------------------------
287{
288 // re-use old material if exists
289 MaterialPtr mat = terrain->_getCompositeMapMaterial();
290 if (!mat)
291 {
292 MaterialManager& matMgr = MaterialManager::getSingleton();
293
294 // it's important that the names are deterministic for a given terrain, so
295 // use the terrain pointer as an ID
296 const String& matName = terrain->getMaterialName() + "/comp";
297 mat = matMgr.getByName(matName);
298 if (!mat)
299 {
300 mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
301 }
302 }
303 // clear everything
304 mat->removeAllTechniques();
305
306 addTechnique(mat, terrain, RENDER_COMPOSITE_MAP);
307
308 updateParamsForCompositeMap(mat, terrain);
309
310 return mat;
311}
312
313//---------------------------------------------------------------------
315 const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt)
316{
317 Technique* tech = mat->createTechnique();
318
319 // Only supporting one pass
320 Pass* pass = tech->createPass();
321
322 GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
323 HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
324 if (!mShaderGen)
325 {
326 bool check2x = mLayerNormalMappingEnabled || mLayerParallaxMappingEnabled;
327 if (hmgr.isLanguageSupported("cg"))
328 mShaderGen = OGRE_NEW ShaderHelperCg();
329 else if (hmgr.isLanguageSupported("hlsl") &&
330 ((check2x && gmgr.isSyntaxSupported("ps_4_0")) ||
331 (check2x && gmgr.isSyntaxSupported("ps_2_x")) ||
332 (!check2x && gmgr.isSyntaxSupported("ps_2_0"))))
333 mShaderGen = OGRE_NEW ShaderHelperHLSL();
334 else if (hmgr.isLanguageSupported("glsl"))
335 mShaderGen = OGRE_NEW ShaderHelperGLSL();
336 else if (hmgr.isLanguageSupported("glsles"))
337 mShaderGen = OGRE_NEW ShaderHelperGLSLES();
338 else
339 {
340 // todo
341 }
342
343 // check SM3 features
344 mSM3Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_3_0");
345 mSM4Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_4_0");
346 }
347 HighLevelGpuProgramPtr vprog = mShaderGen->generateVertexProgram(this, terrain, tt);
348 HighLevelGpuProgramPtr fprog = mShaderGen->generateFragmentProgram(this, terrain, tt);
349
350 pass->setVertexProgram(vprog->getName());
351 pass->setFragmentProgram(fprog->getName());
352
353 if (tt == HIGH_LOD || tt == RENDER_COMPOSITE_MAP)
354 {
355 // global normal map
356 TextureUnitState* tu = pass->createTextureUnitState();
357 tu->setTextureName(terrain->getTerrainNormalMap()->getName());
358 tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
359
360 // global colour map
361 if (terrain->getGlobalColourMapEnabled() && isGlobalColourMapEnabled())
362 {
363 tu = pass->createTextureUnitState(terrain->getGlobalColourMap()->getName());
364 tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
365 }
366
367 // light map
368 if (isLightmapEnabled())
369 {
370 tu = pass->createTextureUnitState(terrain->getLightmap()->getName());
371 tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
372 }
373
374 // blend maps
375 uint maxLayers = getMaxLayers(terrain);
376 uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
377 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
378 for (uint i = 0; i < numBlendTextures; ++i)
379 {
380 tu = pass->createTextureUnitState(terrain->getBlendTextureName(i));
381 tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
382 }
383
384 // layer textures
385 for (uint i = 0; i < numLayers; ++i)
386 {
387 // diffuse / specular
388 pass->createTextureUnitState(terrain->getLayerTextureName(i, 0));
389 // normal / height
390 pass->createTextureUnitState(terrain->getLayerTextureName(i, 1));
391 }
392 }
393 else
394 {
395 // LOW_LOD textures
396 // composite map
397 TextureUnitState* tu = pass->createTextureUnitState();
398 tu->setTextureName(terrain->getCompositeMap()->getName());
399 tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
400
401 // That's it!
402 }
403
404 // Add shadow textures (always at the end)
405 if (isShadowingEnabled(tt, terrain))
406 {
407 uint numTextures = 1;
408 if (getReceiveDynamicShadowsPSSM())
409 {
410 numTextures = getReceiveDynamicShadowsPSSM()->getSplitCount();
411 }
412 for (uint i = 0; i < numTextures; ++i)
413 {
414 TextureUnitState* tu = pass->createTextureUnitState();
415 tu->setContentType(TextureUnitState::CONTENT_SHADOW);
416 tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
417 tu->setTextureBorderColour(ColourValue::White);
418 }
419 }
420}
421
422//---------------------------------------------------------------------
424{
425 return getReceiveDynamicShadowsEnabled() && tt != RENDER_COMPOSITE_MAP &&
426 (tt != LOW_LOD || mLowLodShadows) &&
427 terrain->getSceneManager()->isShadowTechniqueTextureBased();
428}
429
430//---------------------------------------------------------------------
431void TerrainPSSMMaterialGenerator::SM2Profile::updateParams(const MaterialPtr& mat, const Terrain* terrain)
432{
433 mShaderGen->updateParams(this, mat, terrain, false);
434}
435
436//---------------------------------------------------------------------
437void TerrainPSSMMaterialGenerator::SM2Profile::updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain)
438{
439 mShaderGen->updateParams(this, mat, terrain, true);
440}
441
442//---------------------------------------------------------------------
443//---------------------------------------------------------------------
444HighLevelGpuProgramPtr
446 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
447{
448 HighLevelGpuProgramPtr ret = createVertexProgram(prof, terrain, tt);
449
450 Ogre::StringStream sourceStr;
451 generateVertexProgramSource(prof, terrain, tt, sourceStr);
452 ret->setSource(sourceStr.str());
453 ret->load();
454 defaultVpParams(prof, terrain, tt, ret);
455#if 0
456 LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Vertex Program: "
457 << ret->getName() << " ***\n" << ret->getSource() << "\n*** ***";
458#endif
459
460 return ret;
461}
462
463//---------------------------------------------------------------------
464HighLevelGpuProgramPtr
466 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
467{
468 HighLevelGpuProgramPtr ret = createFragmentProgram(prof, terrain, tt);
469
470 Ogre::StringStream sourceStr;
471 generateFragmentProgramSource(prof, terrain, tt, sourceStr);
472 ret->setSource(sourceStr.str());
473 ret->load();
474 defaultFpParams(prof, terrain, tt, ret);
475
476#if 0
477 LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Fragment Program: "
478 << ret->getName() << " ***\n" << ret->getSource() << "\n*** ***";
479#endif
480
481 return ret;
482}
483
484//---------------------------------------------------------------------
486 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
487{
488 generateVpHeader(prof, terrain, tt, outStream);
489
490 if (tt != LOW_LOD)
491 {
492 uint maxLayers = prof->getMaxLayers(terrain);
493 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
494
495 for (uint i = 0; i < numLayers; ++i)
496 generateVpLayer(prof, terrain, tt, i, outStream);
497 }
498
499 generateVpFooter(prof, terrain, tt, outStream);
500}
501
502//---------------------------------------------------------------------
504 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
505{
506 generateFpHeader(prof, terrain, tt, outStream);
507
508 if (tt != LOW_LOD)
509 {
510 uint maxLayers = prof->getMaxLayers(terrain);
511 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
512
513 for (uint i = 0; i < numLayers; ++i)
514 generateFpLayer(prof, terrain, tt, i, outStream);
515 }
516
517 generateFpFooter(prof, terrain, tt, outStream);
518}
519
520//---------------------------------------------------------------------
522 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
523{
524 GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
525 params->setIgnoreMissingParams(true);
526 params->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX);
527 params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
528 params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM,
529 Terrain::LOD_MORPH_CUSTOM_PARAM);
530 params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
531
532 if (prof->isShadowingEnabled(tt, terrain))
533 {
534 uint numTextures = 1;
536 {
537 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
538 }
539 for (uint i = 0; i < numTextures; ++i)
540 {
541 params->setNamedAutoConstant("texViewProjMatrix" + StringConverter::toString(i),
542 GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
543 /*if (prof->getReceiveDynamicShadowsDepth())
544 {
545 params->setNamedAutoConstant("depthRange" + StringConverter::toString(i),
546 GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i);
547 }*/
548 }
549 }
550
551 if (terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP)
552 {
553 Matrix4 posIndexToObjectSpace;
554 terrain->getPointTransform(&posIndexToObjectSpace);
555 params->setNamedConstant("posIndexToObjectSpace", posIndexToObjectSpace);
556 }
557}
558
559//---------------------------------------------------------------------
561 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
562{
563 GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
564 params->setIgnoreMissingParams(true);
565
566 params->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
567 params->setNamedAutoConstant("lightPosObjSpace", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, 0);
568 params->setNamedAutoConstant("lightDiffuseColour", GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, 0);
569 params->setNamedAutoConstant("lightSpecularColour", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, 0);
570 params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
571 params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
572
573 if (prof->isShadowingEnabled(tt, terrain))
574 {
575 uint numTextures = 1;
577 {
578 PSSMShadowCameraSetup* pssm = prof->getReceiveDynamicShadowsPSSM();
579 numTextures = pssm->getSplitCount();
580 Vector4 splitPoints;
581 const PSSMShadowCameraSetup::SplitPointList& splitPointList = pssm->getSplitPoints();
582 // Populate from split point 1, not 0, since split 0 isn't useful (usually 0)
583 for (uint i = 1; i < numTextures; ++i)
584 {
585 splitPoints[i - 1] = splitPointList[i];
586 }
587 params->setNamedConstant("pssmSplitPoints", splitPoints);
588 }
589
591 {
592 size_t samplerOffset = (tt == HIGH_LOD) ? mShadowSamplerStartHi : mShadowSamplerStartLo;
593 for (uint i = 0; i < numTextures; ++i)
594 {
595 params->setNamedAutoConstant("inverseShadowmapSize" + StringConverter::toString(i),
596 GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i + samplerOffset);
597 }
598 }
599 }
600}
601
602//---------------------------------------------------------------------
604 const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap)
605{
606 Pass* p = mat->getTechnique(0)->getPass(0);
607 if (compositeMap)
608 {
609 updateVpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getVertexProgramParameters());
610 updateFpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getFragmentProgramParameters());
611 }
612 else
613 {
614 // high lod
615 updateVpParams(prof, terrain, HIGH_LOD, p->getVertexProgramParameters());
616 updateFpParams(prof, terrain, HIGH_LOD, p->getFragmentProgramParameters());
617
618 if (prof->isCompositeMapEnabled())
619 {
620 // low lod
621 p = mat->getTechnique(1)->getPass(0);
622 updateVpParams(prof, terrain, LOW_LOD, p->getVertexProgramParameters());
623 updateFpParams(prof, terrain, LOW_LOD, p->getFragmentProgramParameters());
624 }
625 }
626}
627
628//---------------------------------------------------------------------
630 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
631{
632 params->setIgnoreMissingParams(true);
633 uint maxLayers = prof->getMaxLayers(terrain);
634 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
635 uint numUVMul = numLayers / 4;
636 if (numLayers % 4)
637 ++numUVMul;
638 for (uint i = 0; i < numUVMul; ++i)
639 {
640 Vector4 uvMul(
641 terrain->getLayerUVMultiplier(i * 4),
642 terrain->getLayerUVMultiplier(i * 4 + 1),
643 terrain->getLayerUVMultiplier(i * 4 + 2),
644 terrain->getLayerUVMultiplier(i * 4 + 3)
645 );
646 params->setNamedConstant("uvMul_" + StringConverter::toString(i), uvMul);
647 }
648
649 if (terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP)
650 {
651 Real baseUVScale = 1.0f / (terrain->getSize() - 1);
652 params->setNamedConstant("baseUVScale", baseUVScale);
653 }
654}
655
656//---------------------------------------------------------------------
658 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
659{
660 params->setIgnoreMissingParams(true);
661 // TODO - parameterise this?
662 Vector4 scaleBiasSpecular(0.03, -0.04, 32, 1);
663 params->setNamedConstant("scaleBiasSpecular", scaleBiasSpecular);
664}
665
666//---------------------------------------------------------------------
668{
669 uint rem = idx % 4;
670 switch (rem)
671 {
672 case 0:
673 default:
674 return "r";
675 case 1:
676 return "g";
677 case 2:
678 return "b";
679 case 3:
680 return "a";
681 };
682}
683
684//---------------------------------------------------------------------
686 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
687{
688 String progName = terrain->getMaterialName() + "/sm2/vp";
689
690 switch (tt)
691 {
692 case HIGH_LOD:
693 progName += "/hlod";
694 break;
695 case LOW_LOD:
696 progName += "/llod";
697 break;
698 case RENDER_COMPOSITE_MAP:
699 progName += "/comp";
700 break;
701 }
702
703 return progName;
704}
705
706//---------------------------------------------------------------------
708 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
709{
710 String progName = terrain->getMaterialName() + "/sm2/fp";
711
712 switch (tt)
713 {
714 case HIGH_LOD:
715 progName += "/hlod";
716 break;
717 case LOW_LOD:
718 progName += "/llod";
719 break;
720 case RENDER_COMPOSITE_MAP:
721 progName += "/comp";
722 break;
723 }
724
725 return progName;
726}
727
728//---------------------------------------------------------------------
729//---------------------------------------------------------------------
730HighLevelGpuProgramPtr
732 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
733{
734 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
735 String progName = getVertexProgramName(prof, terrain, tt);
736 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
737 if (!ret)
738 {
739 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
740 "cg", GPT_VERTEX_PROGRAM);
741 }
742 else
743 {
744 ret->unload();
745 }
746
747 ret->setParameter("profiles", "vs_4_0 vs_3_0 vs_2_0 arbvp1");
748 ret->setParameter("entry_point", "main_vp");
749
750 return ret;
751}
752
753//---------------------------------------------------------------------
754HighLevelGpuProgramPtr
756 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
757{
758 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
759 String progName = getFragmentProgramName(prof, terrain, tt);
760
761 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
762 if (!ret)
763 {
764 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
765 "cg", GPT_FRAGMENT_PROGRAM);
766 }
767 else
768 {
769 ret->unload();
770 }
771
773 ret->setParameter("profiles", "ps_4_0 ps_3_0 ps_2_x fp40 arbfp1");
774 else
775 ret->setParameter("profiles", "ps_4_0 ps_3_0 ps_2_0 fp30 arbfp1");
776 ret->setParameter("entry_point", "main_fp");
777
778 return ret;
779}
780
781//---------------------------------------------------------------------
783 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
784{
785 outStream <<
786 "void main_vp(\n";
787 bool compression = terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP;
788 if (compression)
789 {
790 outStream <<
791 "float2 posIndex : POSITION,\n"
792 "float height : TEXCOORD0,\n";
793 }
794 else
795 {
796 outStream <<
797 "float4 pos : POSITION,\n"
798 "float2 uv : TEXCOORD0,\n";
799 }
800 if (tt != RENDER_COMPOSITE_MAP)
801 outStream << "float2 delta : TEXCOORD1,\n"; // lodDelta, lodThreshold
802
803 outStream <<
804 "uniform float4x4 worldMatrix,\n"
805 "uniform float4x4 viewProjMatrix,\n"
806 "uniform float2 lodMorph,\n"; // morph amount, morph LOD target
807
808 if (compression)
809 {
810 outStream <<
811 "uniform float4x4 posIndexToObjectSpace,\n"
812 "uniform float baseUVScale,\n";
813 }
814 // uv multipliers
815 uint maxLayers = prof->getMaxLayers(terrain);
816 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
817 uint numUVMultipliers = (numLayers / 4);
818 if (numLayers % 4)
819 ++numUVMultipliers;
820 for (uint i = 0; i < numUVMultipliers; ++i)
821 outStream << "uniform float4 uvMul_" << i << ", \n";
822
823 outStream <<
824 "out float4 oPos : POSITION,\n"
825 "out float4 oPosObj : TEXCOORD0 \n";
826
827 uint texCoordSet = 1;
828 outStream <<
829 ", out float4 oUVMisc : TEXCOORD" << texCoordSet++ << " // xy = uv, z = camDepth\n";
830
831 // layer UV's premultiplied, packed as xy/zw
832 uint numUVSets = numLayers / 2;
833 if (numLayers % 2)
834 ++numUVSets;
835 if (tt != LOW_LOD)
836 {
837 for (uint i = 0; i < numUVSets; ++i)
838 {
839 outStream <<
840 ", out float4 oUV" << i << " : TEXCOORD" << texCoordSet++ << "\n";
841 }
842 }
843
844 if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP)
845 {
846 outStream << ", out float2 lodInfo : TEXCOORD" << texCoordSet++ << "\n";
847 }
848
849 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
850 if (fog)
851 {
852 outStream <<
853 ", uniform float4 fogParams\n"
854 ", out float fogVal : COLOR\n";
855 }
856
857 if (prof->isShadowingEnabled(tt, terrain))
858 {
859 texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream);
860 }
861
862 // check we haven't exceeded texture coordinates
863 if (texCoordSet > 8)
864 {
865 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
866 "Requested options require too many texture coordinate sets! Try reducing the number of layers.",
867 __FUNCTION__);
868 }
869
870 outStream <<
871 ")\n"
872 "{\n";
873 if (compression)
874 {
875 outStream <<
876 " float4 pos;\n"
877 " pos = mul(posIndexToObjectSpace, float4(posIndex, height, 1));\n"
878 " float2 uv = float2(posIndex.x * baseUVScale, 1.0 - (posIndex.y * baseUVScale));\n";
879 }
880 outStream <<
881 " float4 worldPos = mul(worldMatrix, pos);\n"
882 " oPosObj = pos;\n";
883
884 if (tt != RENDER_COMPOSITE_MAP)
885 {
886 // determine whether to apply the LOD morph to this vertex
887 // we store the deltas against all vertices so we only want to apply
888 // the morph to the ones which would disappear. The target LOD which is
889 // being morphed to is stored in lodMorph.y, and the LOD at which
890 // the vertex should be morphed is stored in uv.w. If we subtract
891 // the former from the latter, and arrange to only morph if the
892 // result is negative (it will only be -1 in fact, since after that
893 // the vertex will never be indexed), we will achieve our aim.
894 // sign(vertexLOD - targetLOD) == -1 is to morph
895 outStream <<
896 " float toMorph = -min(0, sign(delta.y - lodMorph.y));\n";
897 // this will either be 1 (morph) or 0 (don't morph)
898 if (prof->getParent()->getDebugLevel())
899 {
900 // x == LOD level (-1 since value is target level, we want to display actual)
901 outStream << "lodInfo.x = (lodMorph.y - 1) / " << terrain->getNumLodLevels() << ";\n";
902 // y == LOD morph
903 outStream << "lodInfo.y = toMorph * lodMorph.x;\n";
904 }
905
906 // morph
907 switch (terrain->getAlignment())
908 {
909 case Terrain::ALIGN_X_Y:
910 outStream << " worldPos.z += delta.x * toMorph * lodMorph.x;\n";
911 break;
912 case Terrain::ALIGN_X_Z:
913 outStream << " worldPos.y += delta.x * toMorph * lodMorph.x;\n";
914 break;
915 case Terrain::ALIGN_Y_Z:
916 outStream << " worldPos.x += delta.x * toMorph * lodMorph.x;\n";
917 break;
918 };
919 }
920
921 // generate UVs
922 if (tt != LOW_LOD)
923 {
924 for (uint i = 0; i < numUVSets; ++i)
925 {
926 uint layer = i * 2;
927 uint uvMulIdx = layer / 4;
928
929 outStream <<
930 " oUV" << i << ".xy = " << " uv.xy * uvMul_" << uvMulIdx << "." << getChannel(layer) << ";\n";
931 outStream <<
932 " oUV" << i << ".zw = " << " uv.xy * uvMul_" << uvMulIdx << "." << getChannel(layer + 1) << ";\n";
933 }
934 }
935}
936
937//---------------------------------------------------------------------
939 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
940{
941 // Main header
942 outStream <<
943 // helpers
944 "float4 expand(float4 v)\n"
945 "{ \n"
946 " return v * 2 - 1;\n"
947 "}\n\n\n";
948
949 if (prof->isShadowingEnabled(tt, terrain))
950 generateFpDynamicShadowsHelpers(prof, terrain, tt, outStream);
951
952 outStream <<
953 "float4 main_fp(\n"
954 "float4 vertexPos : POSITION,\n"
955 "float4 position : TEXCOORD0,\n";
956
957 uint texCoordSet = 1;
958 outStream <<
959 "float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n";
960
961 // UV's premultiplied, packed as xy/zw
962 uint maxLayers = prof->getMaxLayers(terrain);
963 uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
964 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
965 uint numUVSets = numLayers / 2;
966 if (numLayers % 2)
967 ++numUVSets;
968 if (tt != LOW_LOD)
969 {
970 for (uint i = 0; i < numUVSets; ++i)
971 {
972 outStream <<
973 "float4 layerUV" << i << " : TEXCOORD" << texCoordSet++ << ", \n";
974 }
975 }
976 if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP)
977 {
978 outStream << "float2 lodInfo : TEXCOORD" << texCoordSet++ << ", \n";
979 }
980
981 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
982 if (fog)
983 {
984 outStream <<
985 "uniform float3 fogColour, \n"
986 "float fogVal : COLOR,\n";
987 }
988
989 uint currentSamplerIdx = 0;
990
991 outStream <<
992 // Only 1 light supported in this version
993 // deferred shading profile / generator later, ok? :)
994 "uniform float3 ambient,\n"
995 "uniform float4 lightPosObjSpace,\n"
996 "uniform float3 lightDiffuseColour,\n"
997 "uniform float3 lightSpecularColour,\n"
998 "uniform float3 eyePosObjSpace,\n"
999 // pack scale, bias and specular
1000 "uniform float4 scaleBiasSpecular,\n";
1001
1002 if (tt == LOW_LOD)
1003 {
1004 // single composite map covers all the others below
1005 outStream <<
1006 "uniform sampler2D compositeMap : register(s" << currentSamplerIdx++ << ")\n";
1007 }
1008 else
1009 {
1010 outStream <<
1011 "uniform sampler2D globalNormal : register(s" << currentSamplerIdx++ << ")\n";
1012
1013 if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
1014 {
1015 outStream << ", uniform sampler2D globalColourMap : register(s"
1016 << currentSamplerIdx++ << ")\n";
1017 }
1018 if (prof->isLightmapEnabled())
1019 {
1020 outStream << ", uniform sampler2D lightMap : register(s"
1021 << currentSamplerIdx++ << ")\n";
1022 }
1023 // Blend textures - sampler definitions
1024 for (uint i = 0; i < numBlendTextures; ++i)
1025 {
1026 outStream << ", uniform sampler2D blendTex" << i
1027 << " : register(s" << currentSamplerIdx++ << ")\n";
1028 }
1029
1030 // Layer textures - sampler definitions & UV multipliers
1031 for (uint i = 0; i < numLayers; ++i)
1032 {
1033 outStream << ", uniform sampler2D difftex" << i
1034 << " : register(s" << currentSamplerIdx++ << ")\n";
1035 outStream << ", uniform sampler2D normtex" << i
1036 << " : register(s" << currentSamplerIdx++ << ")\n";
1037 }
1038 }
1039
1040 if (prof->isShadowingEnabled(tt, terrain))
1041 {
1042 generateFpDynamicShadowsParams(&texCoordSet, &currentSamplerIdx, prof, terrain, tt, outStream);
1043 }
1044
1045 // check we haven't exceeded samplers
1046 if (currentSamplerIdx > 16)
1047 {
1048 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1049 "Requested options require too many texture samplers! Try reducing the number of layers.",
1050 __FUNCTION__);
1051 }
1052
1053 outStream <<
1054 ") : COLOR\n"
1055 "{\n"
1056 " float4 outputCol;\n"
1057 " float shadow = 1.0;\n"
1058 " float2 uv = uvMisc.xy;\n"
1059 // base colour
1060 " outputCol = float4(0,0,0,1);\n";
1061
1062 if (tt != LOW_LOD)
1063 {
1064 outStream <<
1065 // global normal
1066 " float3 normal = expand(tex2D(globalNormal, uv)).rgb;\n";
1067 }
1068
1069 outStream <<
1070 " float3 lightDir = \n"
1071 " lightPosObjSpace.xyz - (position.xyz * lightPosObjSpace.w);\n"
1072 " float3 eyeDir = eyePosObjSpace - position.xyz;\n"
1073
1074 // set up accumulation areas
1075 " float3 diffuse = float3(0,0,0);\n"
1076 " float specular = 0;\n";
1077
1078 if (tt == LOW_LOD)
1079 {
1080 // we just do a single calculation from composite map
1081 outStream <<
1082 " float4 composite = tex2D(compositeMap, uv);\n"
1083 " diffuse = composite.rgb;\n";
1084 // TODO - specular; we'll need normals for this!
1085 }
1086 else
1087 {
1088 // set up the blend values
1089 for (uint i = 0; i < numBlendTextures; ++i)
1090 {
1091 outStream << " float4 blendTexVal" << i << " = tex2D(blendTex" << i << ", uv);\n";
1092 }
1093
1094 if (prof->isLayerNormalMappingEnabled())
1095 {
1096 // derive the tangent space basis
1097 // we do this in the pixel shader because we don't have per-vertex normals
1098 // because of the LOD, we use a normal map
1099 // tangent is always +x or -z in object space depending on alignment
1100 switch (terrain->getAlignment())
1101 {
1102 case Terrain::ALIGN_X_Y:
1103 case Terrain::ALIGN_X_Z:
1104 outStream << " float3 tangent = float3(1, 0, 0);\n";
1105 break;
1106 case Terrain::ALIGN_Y_Z:
1107 outStream << " float3 tangent = float3(0, 0, -1);\n";
1108 break;
1109 };
1110
1111 outStream << " float3 binormal = normalize(cross(tangent, normal));\n";
1112 // note, now we need to re-cross to derive tangent again because it wasn't orthonormal
1113 outStream << " tangent = normalize(cross(normal, binormal));\n";
1114 // derive final matrix
1115 outStream << " float3x3 TBN = float3x3(tangent, binormal, normal);\n";
1116
1117 // set up lighting result placeholders for interpolation
1118 outStream << " float4 litRes, litResLayer;\n";
1119 outStream << " float3 TSlightDir, TSeyeDir, TShalfAngle, TSnormal;\n";
1121 outStream << " float displacement;\n";
1122 // move
1123 outStream << " TSlightDir = normalize(mul(TBN, lightDir));\n";
1124 outStream << " TSeyeDir = normalize(mul(TBN, eyeDir));\n";
1125 }
1126 else
1127 {
1128 // simple per-pixel lighting with no normal mapping
1129 outStream << " lightDir = normalize(lightDir);\n";
1130 outStream << " eyeDir = normalize(eyeDir);\n";
1131 outStream << " float3 halfAngle = normalize(lightDir + eyeDir);\n";
1132 outStream << " float4 litRes = lit(dot(lightDir, normal), dot(halfAngle, normal), scaleBiasSpecular.z);\n";
1133 }
1134 }
1135}
1136
1137//---------------------------------------------------------------------
1139 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, Ogre::StringStream& outStream)
1140{
1141 // nothing to do
1142}
1143
1144//---------------------------------------------------------------------
1146 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, Ogre::StringStream& outStream)
1147{
1148 uint uvIdx = layer / 2;
1149 String uvChannels = (layer % 2) ? ".zw" : ".xy";
1150 uint blendIdx = (layer - 1) / 4;
1151 String blendChannel = getChannel(layer - 1);
1152 String blendWeightStr = String("blendTexVal") + StringConverter::toString(blendIdx) +
1153 "." + blendChannel;
1154
1155 // generate early-out conditional
1156 /* Disable - causing some issues even when trying to force the use of texldd
1157 if (layer && prof->_isSM3Available())
1158 outStream << " if (" << blendWeightStr << " > 0.0003)\n { \n";
1159 */
1160
1161 // generate UV
1162 outStream << " float2 uv" << layer << " = layerUV" << uvIdx << uvChannels << ";\n";
1163
1164 // calculate lighting here if normal mapping
1165 if (prof->isLayerNormalMappingEnabled())
1166 {
1167 if (prof->isLayerParallaxMappingEnabled() && tt != RENDER_COMPOSITE_MAP)
1168 {
1169 // modify UV - note we have to sample an extra time
1170 outStream << " displacement = tex2D(normtex" << layer << ", uv" << layer << ").a\n"
1171 " * scaleBiasSpecular.x + scaleBiasSpecular.y;\n";
1172 outStream << " uv" << layer << " += TSeyeDir.xy * displacement;\n";
1173 }
1174
1175 // access TS normal map
1176 outStream << " TSnormal = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n";
1177 outStream << " TShalfAngle = normalize(TSlightDir + TSeyeDir);\n";
1178 outStream << " litResLayer = lit(dot(TSlightDir, TSnormal), dot(TShalfAngle, TSnormal), scaleBiasSpecular.z);\n";
1179 if (!layer)
1180 outStream << " litRes = litResLayer;\n";
1181 else
1182 outStream << " litRes = lerp(litRes, litResLayer, " << blendWeightStr << ");\n";
1183 }
1184
1185 // sample diffuse texture
1186 outStream << " float4 diffuseSpecTex" << layer
1187 << " = tex2D(difftex" << layer << ", uv" << layer << ");\n";
1188
1189 // apply to common
1190 if (!layer)
1191 {
1192 outStream << " diffuse = diffuseSpecTex0.rgb;\n";
1194 outStream << " specular = diffuseSpecTex0.a;\n";
1195 }
1196 else
1197 {
1198 outStream << " diffuse = lerp(diffuse, diffuseSpecTex" << layer
1199 << ".rgb, " << blendWeightStr << ");\n";
1201 outStream << " specular = lerp(specular, diffuseSpecTex" << layer
1202 << ".a, " << blendWeightStr << ");\n";
1203 }
1204
1205 // End early-out
1206 /* Disable - causing some issues even when trying to force the use of texldd
1207 if (layer && prof->_isSM3Available())
1208 outStream << " } // early-out blend value\n";
1209 */
1210}
1211
1212//---------------------------------------------------------------------
1214 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1215{
1216 outStream <<
1217 " oPos = mul(viewProjMatrix, worldPos);\n"
1218 " oUVMisc.xy = uv.xy;\n";
1219
1220 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
1221 if (fog)
1222 {
1223 if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR)
1224 {
1225 outStream <<
1226 " fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n";
1227 }
1228 else
1229 {
1230 outStream <<
1231 " fogVal = 1 - saturate(1 / (exp(oPos.z * fogParams.x)));\n";
1232 }
1233 }
1234
1235 if (prof->isShadowingEnabled(tt, terrain))
1236 generateVpDynamicShadows(prof, terrain, tt, outStream);
1237
1238 outStream <<
1239 "}\n";
1240}
1241
1242//---------------------------------------------------------------------
1244 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1245{
1246 if (tt == LOW_LOD)
1247 {
1248 if (prof->isShadowingEnabled(tt, terrain))
1249 {
1250 generateFpDynamicShadows(prof, terrain, tt, outStream);
1251 outStream <<
1252 " outputCol.rgb = diffuse * rtshadow;\n";
1253 }
1254 else
1255 {
1256 outStream <<
1257 " outputCol.rgb = diffuse;\n";
1258 }
1259 }
1260 else
1261 {
1262 if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
1263 {
1264 // sample colour map and apply to diffuse
1265 outStream << " diffuse *= tex2D(globalColourMap, uv).rgb;\n";
1266 }
1267 if (prof->isLightmapEnabled())
1268 {
1269 // sample lightmap
1270 outStream << " shadow = tex2D(lightMap, uv).r;\n";
1271 }
1272
1273 if (prof->isShadowingEnabled(tt, terrain))
1274 {
1275 generateFpDynamicShadows(prof, terrain, tt, outStream);
1276 }
1277
1278 // diffuse lighting
1279 outStream << " outputCol.rgb += ambient * diffuse + litRes.y * lightDiffuseColour * diffuse * shadow;\n";
1280
1281 // specular default
1282 if (!prof->isLayerSpecularMappingEnabled())
1283 outStream << " specular = 1.0;\n";
1284
1285 if (tt == RENDER_COMPOSITE_MAP)
1286 {
1287 // Lighting embedded in alpha
1288 outStream <<
1289 " outputCol.a = shadow;\n";
1290 }
1291 else
1292 {
1293 // Apply specular
1294 outStream << " outputCol.rgb += litRes.z * lightSpecularColour * specular * shadow;\n";
1295
1296 if (prof->getParent()->getDebugLevel())
1297 {
1298 outStream << " outputCol.rg += lodInfo.xy;\n";
1299 }
1300 }
1301 }
1302
1303 bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
1304 if (fog)
1305 {
1306 outStream << " outputCol.rgb = lerp(outputCol.rgb, fogColour, fogVal);\n";
1307 }
1308
1309 // Final return
1310 outStream << " return outputCol;\n"
1311 << "}\n";
1312}
1313
1314//---------------------------------------------------------------------
1316 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1317{
1318 // TODO make filtering configurable
1319 outStream <<
1320 "// Simple PCF \n"
1321 "// Number of samples in one dimension (square for total samples) \n"
1322 "#define NUM_SHADOW_SAMPLES_1D 2.0 \n"
1323 "#define SHADOW_FILTER_SCALE 1 \n"
1324
1325 "#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n"
1326
1327 "float4 offsetSample(float4 uv, float2 offset, float invMapSize) \n"
1328 "{ \n"
1329 " return float4(uv.xy + offset * invMapSize * uv.w, uv.z, uv.w); \n"
1330 "} \n";
1331
1333 {
1334 outStream <<
1335 "float calcDepthShadow(sampler2D shadowMap, float4 uv, float invShadowMapSize) \n"
1336 "{ \n"
1337 " // 4-sample PCF \n"
1338
1339 " float shadow = 0.0; \n"
1340 " float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n"
1341 " for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n"
1342 " for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n"
1343 " { \n"
1344 " float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n"
1345 " // manually project and assign derivatives \n"
1346 " // to avoid gradient issues inside loops \n"
1347 " newUV = newUV / newUV.w; \n"
1348 " float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n"
1349 " if (depth >= 1 || depth >= uv.z)\n"
1350 " shadow += 1.0;\n"
1351 " } \n"
1352
1353 " shadow /= SHADOW_SAMPLES; \n"
1354
1355 " return shadow; \n"
1356 "} \n";
1357 }
1358 else
1359 {
1360 outStream <<
1361 "float calcSimpleShadow(sampler2D shadowMap, float4 shadowMapPos) \n"
1362 "{ \n"
1363 " return tex2Dproj(shadowMap, shadowMapPos).x; \n"
1364 "} \n";
1365 }
1366
1367 if (prof->getReceiveDynamicShadowsPSSM())
1368 {
1369 uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
1370
1372 {
1373 outStream <<
1374 "float calcPSSMDepthShadow(";
1375 }
1376 else
1377 {
1378 outStream <<
1379 "float calcPSSMSimpleShadow(";
1380 }
1381
1382 outStream << "\n ";
1383 for (uint i = 0; i < numTextures; ++i)
1384 outStream << "sampler2D shadowMap" << i << ", ";
1385 outStream << "\n ";
1386 for (uint i = 0; i < numTextures; ++i)
1387 outStream << "float4 lsPos" << i << ", ";
1389 {
1390 outStream << "\n ";
1391 for (uint i = 0; i < numTextures; ++i)
1392 outStream << "float invShadowmapSize" << i << ", ";
1393 }
1394 outStream << "\n"
1395 " float4 pssmSplitPoints, float camDepth) \n"
1396 "{ \n"
1397 " float shadow; \n"
1398 " // calculate shadow \n";
1399
1400 for (uint i = 0; i < numTextures; ++i)
1401 {
1402 if (!i)
1403 outStream << " if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n";
1404 else if (i < numTextures - 1)
1405 outStream << " else if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n";
1406 else
1407 outStream << " else \n";
1408
1409 outStream <<
1410 " { \n";
1412 {
1413 outStream <<
1414 " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << "); \n";
1415 }
1416 else
1417 {
1418 outStream <<
1419 " shadow = calcSimpleShadow(shadowMap" << i << ", lsPos" << i << "); \n";
1420 }
1421 outStream <<
1422 " } \n";
1423 }
1424
1425 outStream <<
1426 " return shadow; \n"
1427 "} \n\n\n";
1428 }
1429}
1430
1431//---------------------------------------------------------------------
1433 uint texCoord, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1434{
1435 // out semantics & params
1436 uint numTextures = 1;
1437 if (prof->getReceiveDynamicShadowsPSSM())
1438 {
1439 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
1440 }
1441 for (uint i = 0; i < numTextures; ++i)
1442 {
1443 outStream <<
1444 ", out float4 oLightSpacePos" << i << " : TEXCOORD" << texCoord++ << " \n" <<
1445 ", uniform float4x4 texViewProjMatrix" << i << " \n";
1446
1447 /*if (prof->getReceiveDynamicShadowsDepth())
1448 {
1449 outStream <<
1450 ", uniform float4 depthRange" << i << " // x = min, y = max, z = range, w = 1/range \n";
1451 }*/
1452 }
1453
1454 return texCoord;
1455}
1456
1457//---------------------------------------------------------------------
1459 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1460{
1461 uint numTextures = 1;
1462 if (prof->getReceiveDynamicShadowsPSSM())
1463 {
1464 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
1465 }
1466
1467 // Calculate the position of vertex in light space
1468 for (uint i = 0; i < numTextures; ++i)
1469 {
1470 outStream <<
1471 " oLightSpacePos" << i << " = mul(texViewProjMatrix" << i << ", worldPos); \n";
1472 /*if (prof->getReceiveDynamicShadowsDepth())
1473 {
1474 // make linear
1475 outStream <<
1476 "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n";
1477
1478 }*/
1479 }
1480
1481 if (prof->getReceiveDynamicShadowsPSSM())
1482 {
1483 outStream <<
1484 " // pass cam depth\n"
1485 " oUVMisc.z = oPos.z;\n";
1486 }
1487}
1488
1489//---------------------------------------------------------------------
1491 uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1492{
1493 if (tt == HIGH_LOD)
1494 mShadowSamplerStartHi = *sampler;
1495 else if (tt == LOW_LOD)
1496 mShadowSamplerStartLo = *sampler;
1497
1498 // in semantics & params
1499 uint numTextures = 1;
1500 if (prof->getReceiveDynamicShadowsPSSM())
1501 {
1502 numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
1503 outStream <<
1504 ", uniform float4 pssmSplitPoints \n";
1505 }
1506 for (uint i = 0; i < numTextures; ++i)
1507 {
1508 outStream <<
1509 ", float4 lightSpacePos" << i << " : TEXCOORD" << *texCoord << " \n" <<
1510 ", uniform sampler2D shadowMap" << i << " : register(s" << *sampler << ") \n";
1511 *sampler = *sampler + 1;
1512 *texCoord = *texCoord + 1;
1514 {
1515 outStream <<
1516 ", uniform float inverseShadowmapSize" << i << " \n";
1517 }
1518 }
1519}
1520
1521//---------------------------------------------------------------------
1523 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, Ogre::StringStream& outStream)
1524{
1525 if (prof->getReceiveDynamicShadowsPSSM())
1526 {
1527 uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
1528 outStream <<
1529 " float camDepth = uvMisc.z;\n";
1530
1532 {
1533 outStream <<
1534 " float rtshadow = calcPSSMDepthShadow(";
1535 }
1536 else
1537 {
1538 outStream <<
1539 " float rtshadow = calcPSSMSimpleShadow(";
1540 }
1541 for (uint i = 0; i < numTextures; ++i)
1542 outStream << "shadowMap" << i << ", ";
1543 outStream << "\n ";
1544
1545 for (uint i = 0; i < numTextures; ++i)
1546 outStream << "lightSpacePos" << i << ", ";
1548 {
1549 outStream << "\n ";
1550 for (uint i = 0; i < numTextures; ++i)
1551 outStream << "inverseShadowmapSize" << i << ", ";
1552 }
1553 outStream << "\n" <<
1554 " pssmSplitPoints, camDepth);\n";
1555 }
1556 else
1557 {
1559 {
1560 outStream <<
1561 " float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0);";
1562 }
1563 else
1564 {
1565 outStream <<
1566 " float rtshadow = calcSimpleShadow(shadowMap0, lightSpacePos0);";
1567 }
1568 }
1569
1570 outStream <<
1571 " shadow = min(shadow, rtshadow);\n";
1572}
1573
1574//---------------------------------------------------------------------
1575//---------------------------------------------------------------------
1576HighLevelGpuProgramPtr
1578 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
1579{
1580 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
1581 String progName = getVertexProgramName(prof, terrain, tt);
1582
1583 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
1584 if (!ret)
1585 {
1586 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
1587 "hlsl", GPT_VERTEX_PROGRAM);
1588 }
1589 else
1590 {
1591 ret->unload();
1592 }
1593
1594 if (prof->_isSM4Available())
1595 ret->setParameter("target", "vs_4_0");
1596 else if (prof->_isSM3Available())
1597 ret->setParameter("target", "vs_3_0");
1598 else
1599 ret->setParameter("target", "vs_2_0");
1600 ret->setParameter("entry_point", "main_vp");
1601
1602 return ret;
1603}
1604
1605//---------------------------------------------------------------------
1606HighLevelGpuProgramPtr
1608 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
1609{
1610 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
1611 String progName = getFragmentProgramName(prof, terrain, tt);
1612
1613 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
1614 if (!ret)
1615 {
1616 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
1617 "hlsl", GPT_FRAGMENT_PROGRAM);
1618 }
1619 else
1620 {
1621 ret->unload();
1622 }
1623
1624 if (prof->_isSM4Available())
1625 ret->setParameter("target", "ps_4_0");
1626 else if (prof->_isSM3Available())
1627 ret->setParameter("target", "ps_3_0");
1628 else
1629 ret->setParameter("target", "ps_2_x");
1630 ret->setParameter("entry_point", "main_fp");
1631
1632 return ret;
1633}
1634
1635//---------------------------------------------------------------------
1636//---------------------------------------------------------------------
1637HighLevelGpuProgramPtr
1639 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
1640{
1641 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
1642 String progName = getVertexProgramName(prof, terrain, tt);
1643
1644 switch (tt)
1645 {
1646 case HIGH_LOD:
1647 progName += "/hlod";
1648 break;
1649 case LOW_LOD:
1650 progName += "/llod";
1651 break;
1652 case RENDER_COMPOSITE_MAP:
1653 progName += "/comp";
1654 break;
1655 }
1656
1657 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
1658 if (!ret)
1659 {
1660 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
1661 "glsl", GPT_VERTEX_PROGRAM);
1662 }
1663 else
1664 {
1665 ret->unload();
1666 }
1667
1668 return ret;
1669}
1670
1671//---------------------------------------------------------------------
1672HighLevelGpuProgramPtr
1674 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
1675{
1676 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
1677 String progName = getFragmentProgramName(prof, terrain, tt);
1678
1679 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
1680 if (!ret)
1681 {
1682 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
1683 "glsl", GPT_FRAGMENT_PROGRAM);
1684 }
1685 else
1686 {
1687 ret->unload();
1688 }
1689
1690 return ret;
1691}
1692
1693//---------------------------------------------------------------------
1694//---------------------------------------------------------------------
1695HighLevelGpuProgramPtr
1697 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
1698{
1699 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
1700 String progName = getVertexProgramName(prof, terrain, tt);
1701
1702 switch (tt)
1703 {
1704 case HIGH_LOD:
1705 progName += "/hlod";
1706 break;
1707 case LOW_LOD:
1708 progName += "/llod";
1709 break;
1710 case RENDER_COMPOSITE_MAP:
1711 progName += "/comp";
1712 break;
1713 }
1714
1715 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
1716 if (!ret)
1717 {
1718 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
1719 "glsles", GPT_VERTEX_PROGRAM);
1720 }
1721 else
1722 {
1723 ret->unload();
1724 }
1725
1726 return ret;
1727}
1728
1729//---------------------------------------------------------------------
1730HighLevelGpuProgramPtr
1732 const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
1733{
1734 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
1735 String progName = getFragmentProgramName(prof, terrain, tt);
1736
1737 HighLevelGpuProgramPtr ret = mgr.getByName(progName);
1738 if (!ret)
1739 {
1740 ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
1741 "glsles", GPT_FRAGMENT_PROGRAM);
1742 }
1743 else
1744 {
1745 ret->unload();
1746 }
1747
1748 return ret;
1749}
1750
1751}
Utility class to help with generating shaders for Cg / HLSL.
uint generateVpDynamicShadowsParams(uint texCoordStart, const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateFpLayer(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, uint layer, Ogre::StringStream &outStream)
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
void generateVpDynamicShadows(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateFpHeader(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateFpDynamicShadowsHelpers(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateFpDynamicShadowsParams(uint *texCoord, uint *sampler, const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateVpFooter(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateVpHeader(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateFpFooter(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
void generateFpDynamicShadows(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
void generateVpLayer(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, uint layer, Ogre::StringStream &outStream)
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
virtual void updateVpParams(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, const GpuProgramParametersSharedPtr &params)
virtual HighLevelGpuProgramPtr generateFragmentProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
virtual void generateFragmentProgramSource(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
virtual void defaultVpParams(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, const HighLevelGpuProgramPtr &prog)
virtual void generateVertexProgramSource(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, Ogre::StringStream &outStream)
virtual HighLevelGpuProgramPtr generateVertexProgram(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
virtual void updateParams(const SM2Profile *prof, const MaterialPtr &mat, const Terrain *terrain, bool compositeMap)
virtual String getFragmentProgramName(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
virtual void updateFpParams(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, const GpuProgramParametersSharedPtr &params)
virtual void defaultFpParams(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt, const HighLevelGpuProgramPtr &prog)
virtual String getVertexProgramName(const SM2Profile *prof, const Terrain *terrain, TechniqueType tt)
void setCompositeMapEnabled(bool enabled)
Whether to use the composite map to provide a lower LOD technique in the distance (default true).
bool isLayerParallaxMappingEnabled() const
Whether to support parallax mapping per layer in the shader (default true).
bool isGlobalColourMapEnabled() const
Whether to support a global colour map over the terrain in the shader, if it's present (default true)...
SM2Profile(TerrainMaterialGenerator *parent, const String &name, const String &desc)
void setReceiveDynamicShadowsLowLod(bool enabled)
Whether to use shadows on low LOD material rendering (when using composite map) (default false).
bool getReceiveDynamicShadowsDepth() const
Whether to use depth shadows (default false).
void updateParams(const MaterialPtr &mat, const Terrain *terrain)
bool isCompositeMapEnabled() const
Whether to use the composite map to provide a lower LOD technique in the distance (default true).
void setReceiveDynamicShadowsEnabled(bool enabled)
Whether to support dynamic texture shadows received from other objects, on the terrain (default true)...
void setReceiveDynamicShadowsDepth(bool enabled)
Whether to use depth shadows (default false).
void setLayerNormalMappingEnabled(bool enabled)
Whether to support normal mapping per layer in the shader (default true).
PSSMShadowCameraSetup * getReceiveDynamicShadowsPSSM() const
Whether to use PSSM support dynamic texture shadows, and if so the settings to use (default 0).
void setLightmapEnabled(bool enabled)
Whether to support a light map over the terrain in the shader, if it's present (default true).
bool isLayerNormalMappingEnabled() const
Whether to support normal mapping per layer in the shader (default true).
void setLayerSpecularMappingEnabled(bool enabled)
Whether to support specular mapping per layer in the shader (default true).
void updateParamsForCompositeMap(const MaterialPtr &mat, const Terrain *terrain)
void setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup *pssmSettings)
Whether to use PSSM support dynamic texture shadows, and if so the settings to use (default 0).
bool isShadowingEnabled(TechniqueType tt, const Terrain *terrain) const
void setGlobalColourMapEnabled(bool enabled)
Whether to support a global colour map over the terrain in the shader, if it's present (default true)...
bool isLightmapEnabled() const
Whether to support a light map over the terrain in the shader, if it's present (default true).
void addTechnique(const MaterialPtr &mat, const Terrain *terrain, TechniqueType tt)
void setLayerParallaxMappingEnabled(bool enabled)
Whether to support parallax mapping per layer in the shader (default true).
bool isLayerSpecularMappingEnabled() const
Whether to support specular mapping per layer in the shader (default true).