/src/ogre/Components/Terrain/src/OgreTerrainRTShaderSRS.cpp
Line | Count | Source |
1 | | // This file is part of the OGRE project. |
2 | | // It is subject to the license terms in the LICENSE file found in the top-level directory |
3 | | // of this distribution and at https://www.ogre3d.org/licensing. |
4 | | // SPDX-License-Identifier: MIT |
5 | | #include "OgreTerrainRTShaderSRS.h" |
6 | | |
7 | | #include "OgrePass.h" |
8 | | #include "OgreShaderProgramSet.h" |
9 | | #include "OgreShaderParameter.h" |
10 | | #include "OgreMaterialSerializer.h" |
11 | | #include "OgreShaderGenerator.h" |
12 | | #include "OgreShaderFunction.h" |
13 | | #include "OgreShaderProgram.h" |
14 | | #include "OgreTerrainQuadTreeNode.h" |
15 | | #include "OgreTextureManager.h" |
16 | | |
17 | | namespace Ogre { |
18 | | using namespace RTShader; |
19 | | |
20 | | /************************************************************************/ |
21 | | /* */ |
22 | | /************************************************************************/ |
23 | | String TerrainTransform::Type = "TerrainTransform"; |
24 | | |
25 | | bool TerrainTransform::preAddToRenderState(const RenderState* renderState, Pass* srcPass, Pass* dstPass) |
26 | 0 | { |
27 | 0 | auto terrainAny = srcPass->getUserObjectBindings().getUserAny("Terrain"); |
28 | 0 | mTerrain = any_cast<const Terrain*>(terrainAny); |
29 | 0 | mCompressed = mTerrain->_getUseVertexCompression(); |
30 | 0 | mAlign = mTerrain->getAlignment(); |
31 | 0 | return true; |
32 | 0 | } |
33 | | |
34 | | void TerrainTransform::updateParams() |
35 | 0 | { |
36 | 0 | if(!mCompressed) |
37 | 0 | return; |
38 | | |
39 | 0 | mPointTrans->setGpuParameter(mTerrain->getPointTransform()); |
40 | |
|
41 | 0 | float baseUVScale = 1.0f / (mTerrain->getSize() - 1); |
42 | 0 | mBaseUVScale->setGpuParameter(baseUVScale); |
43 | 0 | } |
44 | | |
45 | | //----------------------------------------------------------------------- |
46 | | bool TerrainTransform::createCpuSubPrograms(ProgramSet* programSet) |
47 | 0 | { |
48 | 0 | static Operand::OpMask heightAxis[3] = {Operand::OPM_Y, Operand::OPM_Z, Operand::OPM_X}; |
49 | |
|
50 | 0 | Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM); |
51 | 0 | Function* vsEntry = vsProgram->getEntryPointFunction(); |
52 | |
|
53 | 0 | auto posType = mCompressed ? GCT_INT2 : GCT_FLOAT4; |
54 | |
|
55 | 0 | auto wvpMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); |
56 | |
|
57 | 0 | auto lodMorph = vsProgram->resolveAutoParameterInt(GpuProgramParameters::ACT_CUSTOM, GCT_FLOAT2, Terrain::LOD_MORPH_CUSTOM_PARAM); |
58 | |
|
59 | 0 | auto positionIn = vsEntry->resolveInputParameter(Parameter::SPC_POSITION_OBJECT_SPACE, posType); |
60 | 0 | auto positionOut = vsEntry->resolveOutputParameter(Parameter::SPC_POSITION_PROJECTIVE_SPACE); |
61 | 0 | auto uv = vsEntry->resolveOutputParameter(Parameter::SPC_TEXTURE_COORDINATE0, GCT_FLOAT2); |
62 | 0 | auto delta = vsEntry->resolveInputParameter(Parameter::SPC_TEXTURE_COORDINATE1, GCT_FLOAT2); |
63 | | |
64 | | // Add dependency. |
65 | 0 | vsProgram->addDependency("FFPLib_Transform"); |
66 | 0 | vsProgram->addDependency("TerrainTransforms"); |
67 | |
|
68 | 0 | auto stage = vsEntry->getStage(FFP_VS_TRANSFORM); |
69 | |
|
70 | 0 | if(mCompressed) |
71 | 0 | { |
72 | 0 | mPointTrans = vsProgram->resolveParameter(GCT_MATRIX_4X4, "pointTrans"); |
73 | 0 | mBaseUVScale = vsProgram->resolveParameter(GCT_FLOAT1, "baseUVScale"); |
74 | 0 | auto height = vsEntry->resolveInputParameter(Parameter::SPC_TEXTURE_COORDINATE0, GCT_FLOAT1); |
75 | 0 | auto position = vsEntry->resolveLocalParameter(Parameter::SPC_POSITION_OBJECT_SPACE); |
76 | |
|
77 | 0 | stage.callFunction("expandVertex", |
78 | 0 | {In(mPointTrans), In(mBaseUVScale), In(positionIn), In(height), Out(position), Out(uv)}); |
79 | 0 | positionIn = position; |
80 | 0 | } |
81 | 0 | else |
82 | 0 | { |
83 | 0 | auto uvin = vsEntry->resolveInputParameter(Parameter::SPC_TEXTURE_COORDINATE0, GCT_FLOAT2); |
84 | 0 | stage.assign(In(uvin).xy(), uv); |
85 | 0 | } |
86 | |
|
87 | 0 | stage.callBuiltin("mul", wvpMatrix, positionIn, positionOut); |
88 | 0 | stage.callFunction("applyLODMorph", {In(delta), In(lodMorph), InOut(positionOut).mask(heightAxis[mAlign])}); |
89 | |
|
90 | 0 | return true; |
91 | 0 | } |
92 | | |
93 | | String TerrainSurface::Type = "TerrainSurface"; |
94 | | |
95 | | bool TerrainSurface::setParameter(const String& name, const String& value) |
96 | 0 | { |
97 | 0 | if(name == "for_composite_map") |
98 | 0 | { |
99 | 0 | return StringConverter::parse(value, mForCompositeMap); |
100 | 0 | } |
101 | 0 | else if (name == "use_parallax_mapping") |
102 | 0 | { |
103 | 0 | return StringConverter::parse(value, mUseParallaxMapping); |
104 | 0 | } |
105 | 0 | else if (name == "use_parallax_occlusion_mapping") |
106 | 0 | { |
107 | 0 | return StringConverter::parse(value, mUseParallaxOcclusionMapping); |
108 | 0 | } |
109 | 0 | else if (name == "use_specular_mapping") |
110 | 0 | { |
111 | 0 | return StringConverter::parse(value, mUseSpecularMapping); |
112 | 0 | } |
113 | 0 | else if (name == "use_normal_mapping") |
114 | 0 | { |
115 | 0 | return StringConverter::parse(value, mUseNormalMapping); |
116 | 0 | } |
117 | | |
118 | 0 | return false; |
119 | 0 | } |
120 | | |
121 | | bool TerrainSurface::preAddToRenderState(const RenderState* renderState, Pass* srcPass, Pass* dstPass) |
122 | 0 | { |
123 | 0 | mTerrain = any_cast<const Terrain*>(srcPass->getUserObjectBindings().getUserAny("Terrain")); |
124 | |
|
125 | 0 | SamplerPtr clampSampler = TextureManager::getSingleton().createSampler(); |
126 | 0 | clampSampler->setAddressingMode(TAM_CLAMP); |
127 | 0 | clampSampler->setFiltering(FT_MIP, FO_NONE); |
128 | |
|
129 | 0 | auto tu = dstPass->createTextureUnitState(); |
130 | 0 | tu->setTexture(mTerrain->getTerrainNormalMap()); |
131 | 0 | tu->setSampler(clampSampler); |
132 | |
|
133 | 0 | if (auto cm = mTerrain->getGlobalColourMap()) |
134 | 0 | { |
135 | 0 | tu = dstPass->createTextureUnitState(); |
136 | 0 | tu->setTexture(cm); |
137 | 0 | tu->setSampler(clampSampler); |
138 | 0 | } |
139 | |
|
140 | 0 | if(auto lm = mTerrain->getLightmap()) |
141 | 0 | { |
142 | 0 | tu = dstPass->createTextureUnitState(); |
143 | 0 | tu->setTexture(lm); |
144 | 0 | tu->setSampler(clampSampler); |
145 | 0 | } |
146 | |
|
147 | 0 | for(auto bt : mTerrain->getBlendTextures()) |
148 | 0 | { |
149 | 0 | tu = srcPass->createTextureUnitState(); |
150 | 0 | tu->setTexture(bt); |
151 | 0 | tu->setSampler(clampSampler); |
152 | 0 | } |
153 | |
|
154 | 0 | mUVMul.resize((mTerrain->getLayerCount() + 3) / 4); // integer ceil |
155 | |
|
156 | 0 | mUseNormalMapping = mUseNormalMapping && !mTerrain->getLayerTextureName(0, 1).empty(); |
157 | 0 | for (int i = 0; i < mTerrain->getLayerCount(); ++i) |
158 | 0 | { |
159 | 0 | srcPass->createTextureUnitState(mTerrain->getLayerTextureName(i, 0)); |
160 | 0 | if (mUseNormalMapping) |
161 | 0 | srcPass->createTextureUnitState(mTerrain->getLayerTextureName(i, 1)); |
162 | 0 | } |
163 | |
|
164 | 0 | return true; |
165 | 0 | } |
166 | | |
167 | | void TerrainSurface::updateParams() |
168 | 0 | { |
169 | 0 | for (size_t i = 0; i < mUVMul.size(); i++) |
170 | 0 | { |
171 | 0 | Vector4 uvMul(mTerrain->getLayerUVMultiplier(i + 0), mTerrain->getLayerUVMultiplier(i + 1), |
172 | 0 | mTerrain->getLayerUVMultiplier(i + 2), mTerrain->getLayerUVMultiplier(i + 3)); |
173 | 0 | mUVMul[i]->setGpuParameter(uvMul); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | static Operand::OpMask channel[4] = {Operand::OPM_X, Operand::OPM_Y, Operand::OPM_Z, Operand::OPM_W}; |
178 | | |
179 | | //----------------------------------------------------------------------- |
180 | | bool TerrainSurface::createCpuSubPrograms(ProgramSet* programSet) |
181 | 0 | { |
182 | 0 | Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM); |
183 | 0 | Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM); |
184 | 0 | Function* psMain = psProgram->getMain(); |
185 | 0 | Function* vsMain = vsProgram->getMain(); |
186 | |
|
187 | 0 | psProgram->addDependency("FFPLib_Transform"); |
188 | 0 | psProgram->addDependency("SGXLib_NormalMap"); |
189 | 0 | psProgram->addDependency("SGXLib_IntegratedPSSM"); |
190 | 0 | psProgram->addDependency("TerrainSurface"); |
191 | |
|
192 | 0 | if(mUseNormalMapping) |
193 | 0 | psProgram->addPreprocessorDefines("TERRAIN_NORMAL_MAPPING"); |
194 | |
|
195 | 0 | auto uvVS = vsMain->resolveOutputParameter(Parameter::SPC_TEXTURE_COORDINATE0, GCT_FLOAT2); |
196 | |
|
197 | 0 | if (mForCompositeMap) |
198 | 0 | { |
199 | 0 | auto uvIn = vsMain->resolveInputParameter(Parameter::SPC_TEXTURE_COORDINATE0, GCT_FLOAT2); |
200 | | // forward texcoords in VS |
201 | 0 | vsMain->getStage(FFP_VS_TEXTURING).assign(uvIn, uvVS); |
202 | 0 | } |
203 | |
|
204 | 0 | ParameterPtr viewPos; |
205 | 0 | if (mUseNormalMapping && mUseParallaxMapping) |
206 | 0 | { |
207 | 0 | psProgram->addPreprocessorDefines("TERRAIN_PARALLAX_MAPPING"); |
208 | 0 | if (mUseParallaxOcclusionMapping) |
209 | 0 | { |
210 | 0 | psProgram->addPreprocessorDefines("POM_MAX_DISTANCE=400.0,POM_LAYER_COUNT=32"); |
211 | 0 | } |
212 | | |
213 | | // assuming: lighting stage computed this |
214 | 0 | auto vsOutViewPos = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_VIEW_SPACE); |
215 | 0 | viewPos = psMain->resolveInputParameter(vsOutViewPos); |
216 | 0 | } |
217 | |
|
218 | 0 | auto uvPS = psMain->resolveInputParameter(uvVS); |
219 | 0 | uvPS->setHighP(true); |
220 | |
|
221 | 0 | for(auto& uvMul : mUVMul) |
222 | 0 | { |
223 | 0 | uvMul = psProgram->resolveParameter(GCT_FLOAT4, "uvMul"); |
224 | 0 | } |
225 | |
|
226 | 0 | int texUnit = 0; |
227 | 0 | auto globalNormal = psProgram->resolveParameter(GCT_SAMPLER2D, "globalNormal", texUnit++); |
228 | |
|
229 | 0 | ParameterPtr globalColourMap; |
230 | 0 | if (mTerrain->getGlobalColourMap()) |
231 | 0 | globalColourMap = psProgram->resolveParameter(GCT_SAMPLER2D, "globalColour", texUnit++); |
232 | |
|
233 | 0 | ParameterPtr lightMap; |
234 | 0 | if(mTerrain->getLightmap()) |
235 | 0 | lightMap = psProgram->resolveParameter(GCT_SAMPLER2D, "lightMap", texUnit++); |
236 | |
|
237 | 0 | auto normal = psMain->resolveLocalParameter(Parameter::SPC_NORMAL_VIEW_SPACE); |
238 | 0 | auto ITMat = psProgram->resolveParameter(GpuProgramParameters::ACT_NORMAL_MATRIX); |
239 | |
|
240 | 0 | auto diffuse = psMain->resolveLocalParameter(Parameter::SPC_COLOR_DIFFUSE); |
241 | 0 | auto diffuseSpec = psMain->resolveLocalParameter(GCT_FLOAT4, "diffuseSpec"); |
242 | 0 | auto TSnormal = psMain->resolveLocalParameter(GCT_FLOAT3, "TSnormal"); |
243 | 0 | auto texTmp = psMain->resolveLocalParameter(GCT_FLOAT4, "texTmp"); |
244 | |
|
245 | 0 | auto outDiffuse = psMain->resolveOutputParameter(Parameter::SPC_COLOR_DIFFUSE); |
246 | |
|
247 | 0 | auto stage = psMain->getStage(FFP_PS_COLOUR_BEGIN); |
248 | 0 | stage.assign(Vector4(1), outDiffuse); // FFPColour logic |
249 | 0 | stage.callFunction("SGX_FetchNormal", globalNormal, uvPS, normal); |
250 | 0 | stage.callBuiltin("mul", ITMat, normal, normal); |
251 | |
|
252 | 0 | auto psSpecular = psMain->resolveLocalParameter(Parameter::SPC_COLOR_SPECULAR); |
253 | 0 | stage.assign(Vector4::ZERO, psSpecular); |
254 | |
|
255 | 0 | std::vector<ParameterPtr> blendWeights; |
256 | 0 | for(auto bt : mTerrain->getBlendTextures()) |
257 | 0 | { |
258 | 0 | auto weight = psMain->resolveLocalParameter(GCT_FLOAT4, StringUtil::format("blendWeight%d", texUnit)); |
259 | 0 | auto blendTex = psProgram->resolveParameter(GCT_SAMPLER2D, "blendTex", texUnit++); |
260 | 0 | stage.sampleTexture(blendTex, uvPS, weight); |
261 | 0 | blendWeights.push_back(weight); |
262 | 0 | } |
263 | | |
264 | | // Call TBN calculation |
265 | 0 | auto psOutTBN = psMain->resolveLocalParameter(GpuConstantType::GCT_MATRIX_3X3, "TBN"); |
266 | 0 | stage.callFunction("SGX_CalculateTerrainTBN", {In(normal), In(ITMat), Out(psOutTBN)}); |
267 | |
|
268 | 0 | stage.assign(Vector4::ZERO, diffuseSpec); |
269 | 0 | stage.assign(Vector3(0, 0, 1), TSnormal); |
270 | 0 | for (int l = 0; l < mTerrain->getLayerCount(); ++l) |
271 | 0 | { |
272 | 0 | auto blendWeight = l == 0 ? In(1.0f) : In(blendWeights[(l - 1) / 4]).mask(channel[(l - 1) % 4]); |
273 | 0 | auto difftex = psProgram->resolveParameter(GCT_SAMPLER2D, "difftex", texUnit++); |
274 | 0 | std::vector<Operand> args = {blendWeight, In(uvPS), In(mUVMul[l/4]).mask(channel[l % 4])}; |
275 | 0 | if (mUseNormalMapping) |
276 | 0 | { |
277 | 0 | if (mUseParallaxMapping) |
278 | 0 | { |
279 | 0 | args.push_back(In(viewPos)); |
280 | 0 | args.push_back(In(0.04)); //Scale |
281 | 0 | args.push_back(In(psOutTBN)); |
282 | 0 | } |
283 | |
|
284 | 0 | auto normtex = psProgram->resolveParameter(GCT_SAMPLER2D, "normtex", texUnit++); |
285 | 0 | args.push_back(In(normtex)); |
286 | 0 | args.push_back(Out(TSnormal)); |
287 | 0 | } |
288 | 0 | args.push_back(In(difftex)); |
289 | 0 | args.push_back(Out(diffuseSpec)); |
290 | 0 | stage.callFunction("blendTerrainLayer", {args}); |
291 | 0 | } |
292 | |
|
293 | 0 | if(mUseNormalMapping) |
294 | 0 | stage.callFunction("transformToTS", {In(TSnormal), In(ITMat), InOut(normal)}); |
295 | | |
296 | | // fake vertexcolour input for TVC_SPECULAR |
297 | 0 | if(mUseSpecularMapping) |
298 | 0 | stage.mul(In(diffuseSpec).w(), Vector4(1), diffuse); |
299 | |
|
300 | 0 | if(lightMap) |
301 | 0 | { |
302 | 0 | auto shadowFactor = psMain->getLocalParameter("lShadowFactor"); |
303 | 0 | if(!shadowFactor) |
304 | 0 | { |
305 | 0 | shadowFactor = psMain->resolveLocalParameter(GCT_FLOAT1, "lShadowFactor", 1); |
306 | 0 | psProgram->addPreprocessorDefines("SHADOWLIGHT_COUNT=1"); |
307 | 0 | } |
308 | 0 | stage = psMain->getStage(FFP_PS_COLOUR_BEGIN - 1); // before the PSSM stage |
309 | 0 | stage.assign({In(1), Out(shadowFactor), At(0)}); |
310 | |
|
311 | 0 | stage = psMain->getStage(FFP_PS_COLOUR_BEGIN + 1); // after the PSSM stage |
312 | 0 | stage.callFunction("getShadowFactor", {In(lightMap), In(uvPS), InOut(shadowFactor), At(0)}); |
313 | 0 | } |
314 | |
|
315 | 0 | if(globalColourMap) |
316 | 0 | { |
317 | 0 | stage = psMain->getStage(FFP_PS_COLOUR_BEGIN + 2); // after lighting calculations |
318 | 0 | stage.sampleTexture(globalColourMap, uvPS, texTmp); |
319 | 0 | stage.mul(In(diffuseSpec).xyz(), In(texTmp).xyz(), Out(diffuseSpec).xyz()); |
320 | 0 | } |
321 | |
|
322 | 0 | stage = psMain->getStage(FFP_PS_TEXTURING); |
323 | 0 | stage.mul(diffuseSpec, outDiffuse, outDiffuse); |
324 | | |
325 | | // FFPColour logic |
326 | 0 | psMain->getStage(FFP_PS_COLOUR_END) |
327 | 0 | .add(In(outDiffuse).xyz(), In(psSpecular).xyz(), Out(outDiffuse).xyz()); |
328 | 0 | return true; |
329 | 0 | } |
330 | | |
331 | | //----------------------------------------------------------------------- |
332 | | const String& TerrainTransformFactory::getType() const |
333 | 0 | { |
334 | 0 | return TerrainTransform::Type; |
335 | 0 | } |
336 | | SubRenderState* TerrainTransformFactory::createInstanceImpl() |
337 | 0 | { |
338 | 0 | return OGRE_NEW TerrainTransform(); |
339 | 0 | } |
340 | | |
341 | | const String& TerrainSurfaceFactory::getType() const |
342 | 0 | { |
343 | 0 | return TerrainSurface::Type; |
344 | 0 | } |
345 | | SubRenderState* TerrainSurfaceFactory::createInstanceImpl() |
346 | 0 | { |
347 | 0 | return OGRE_NEW TerrainSurface(); |
348 | 0 | } |
349 | | |
350 | | } |