Coverage Report

Created: 2026-02-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}