SO3Engine
SO3RtssCustom.cpp
Go to the documentation of this file.
1
10#include "SO3Material/SO3Pass.h"
13
14namespace SO3
15{
16
17 /************************************************************************/
18 /* */
19 /************************************************************************/
20 const Ogre::String SRS_ADV_COOK_TORRANCE_LIGHTING = "AdvancedCookTorranceLighting";
21
22 //-----------------------------------------------------------------------
23 AdvancedCookTorranceLighting::AdvancedCookTorranceLighting() : mUseOcclusion(false), mLightCount(0), mMRMapSamplerIndex(0), mLtcLUT1SamplerIndex(-1) {}
24
25 //-----------------------------------------------------------------------
27 //-----------------------------------------------------------------------
28 bool AdvancedCookTorranceLighting::createCpuSubPrograms(Ogre::RTShader::ProgramSet* programSet)
29 {
30 Ogre::RTShader::Program* vsProgram = programSet->getCpuProgram(Ogre::GPT_VERTEX_PROGRAM);
31 Ogre::RTShader::Function* vsMain = vsProgram->getEntryPointFunction();
32 Ogre::RTShader::Program* psProgram = programSet->getCpuProgram(Ogre::GPT_FRAGMENT_PROGRAM);
33 Ogre::RTShader::Function* psMain = psProgram->getEntryPointFunction();
34
35 vsProgram->addDependency(FFP_LIB_TRANSFORM);
36
37 psProgram->addDependency(FFP_LIB_TRANSFORM);
38 psProgram->addDependency(FFP_LIB_TEXTURING);
39 psProgram->addDependency("SGXLib_CookTorrance");
40 psProgram->addPreprocessorDefines(Ogre::StringUtil::format("LIGHT_COUNT=%d", mLightCount));
41
42 // Resolve texture coordinates.
43 auto vsOutTexcoord = vsMain->getOutputParameter(Ogre::RTShader::Parameter::SPC_TEXTURE_COORDINATE0, Ogre::GCT_FLOAT2); // allow override by others
44 Ogre::RTShader::ParameterPtr vsInTexcoord;
45 if (!vsOutTexcoord)
46 {
47 vsInTexcoord = vsMain->resolveInputParameter(Ogre::RTShader::Parameter::SPC_TEXTURE_COORDINATE0, Ogre::GCT_FLOAT2);
48 vsOutTexcoord = vsMain->resolveOutputParameter(Ogre::RTShader::Parameter::SPC_TEXTURE_COORDINATE0, Ogre::GCT_FLOAT2);
49 }
50 auto psInTexcoord = psMain->resolveInputParameter(vsOutTexcoord);
51
52 // resolve view position
53 auto vsInPosition = vsMain->getLocalParameter(Ogre::RTShader::Parameter::SPC_POSITION_OBJECT_SPACE);
54 if (!vsInPosition)
55 vsInPosition = vsMain->resolveInputParameter(Ogre::RTShader::Parameter::SPC_POSITION_OBJECT_SPACE);
56 auto vsOutViewPos = vsMain->resolveOutputParameter(Ogre::RTShader::Parameter::SPC_POSITION_VIEW_SPACE);
57 auto viewPos = psMain->resolveInputParameter(vsOutViewPos);
58 auto worldViewMatrix = vsProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX);
59
60 // Resolve normal.
61 auto viewNormal = psMain->getLocalParameter(Ogre::RTShader::Parameter::SPC_NORMAL_VIEW_SPACE);
62 Ogre::RTShader::ParameterPtr vsInNormal, vsOutNormal;
63
64 if (!viewNormal)
65 {
66 // Resolve input vertex shader normal.
67 vsInNormal = vsMain->resolveInputParameter(Ogre::RTShader::Parameter::SPC_NORMAL_OBJECT_SPACE);
68
69 // Resolve output vertex shader normal.
70 vsOutNormal = vsMain->resolveOutputParameter(Ogre::RTShader::Parameter::SPC_NORMAL_VIEW_SPACE);
71
72 // Resolve input pixel shader normal.
73 viewNormal = psMain->resolveInputParameter(vsOutNormal);
74 }
75
76 // resolve light params
77 auto outDiffuse = psMain->resolveOutputParameter(Ogre::RTShader::Parameter::SPC_COLOR_DIFFUSE);
78 auto outSpecular = psMain->resolveLocalParameter(Ogre::RTShader::Parameter::SPC_COLOR_SPECULAR);
79
80 // insert after texturing
81 auto vstage = vsMain->getStage(Ogre::RTShader::FFP_PS_COLOUR_BEGIN + 1);
82 auto fstage = psMain->getStage(Ogre::RTShader::FFP_PS_COLOUR_END + 50);
83
84 // Forward texture coordinates
85 if (vsInTexcoord)
86 vstage.assign(vsInTexcoord, vsOutTexcoord);
87 vstage.callFunction(FFP_FUNC_TRANSFORM, worldViewMatrix, vsInPosition, vsOutViewPos);
88
89 // transform normal in VS
90 if (vsOutNormal)
91 {
92 auto worldViewITMatrix = vsProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_NORMAL_MATRIX);
93 vstage.callBuiltin("mul", worldViewITMatrix, vsInNormal, vsOutNormal);
94 }
95
96 auto sceneCol = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_DERIVED_SCENE_COLOUR);
97 auto litResult = psMain->resolveLocalParameter(Ogre::GCT_FLOAT4, "litResult");
98 auto diffuse = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
99 auto baseColor = psMain->resolveLocalParameter(Ogre::GCT_FLOAT4, "baseColor");
100 auto ambientColor = psMain->resolveLocalParameter(Ogre::GCT_FLOAT4, "ambientColor");
101
102 fstage.assign(Ogre::RTShader::In(sceneCol), Ogre::RTShader::Out(ambientColor));
103
104 // add the lighting computation
105 auto mrparams = psMain->resolveLocalParameter(Ogre::GCT_FLOAT2, "metalRoughness");
106 if (!mMetalRoughnessMapName.empty())
107 {
108 auto metalRoughnessSampler =
109 psProgram->resolveParameter(Ogre::GCT_SAMPLER2D, "metalRoughnessSampler", mMRMapSamplerIndex);
110 auto mrSample = psMain->resolveLocalParameter(Ogre::GCT_FLOAT4, "mrSample");
111 // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
112 // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
113 fstage.sampleTexture(metalRoughnessSampler, psInTexcoord, mrSample);
114 fstage.assign(Ogre::RTShader::In(mrSample).mask(Ogre::RTShader::Operand::OPM_YZ), mrparams);
115 // Apply occlusion from 'r' channel
116 // strange gltf texture are black on R channel when not using occlusion
117 if(mUseOcclusion)
118 fstage.mul(Ogre::RTShader::In(ambientColor).xyz(), Ogre::RTShader::In(mrSample).x(), Ogre::RTShader::Out(ambientColor).xyz());
119 }
120 else
121 {
122 auto specular = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_SURFACE_SPECULAR_COLOUR);
123 fstage.assign(Ogre::RTShader::In(specular).xy(), mrparams);
124 }
125
126 auto pixelParams = psMain->resolveLocalStructParameter("PixelParams", "pixel");
127
128 fstage.mul(Ogre::RTShader::In(diffuse).xyz(), Ogre::RTShader::In(outDiffuse).xyz(), Ogre::RTShader::Out(baseColor).xyz());
129 fstage.assign(Ogre::Vector3(0), Ogre::RTShader::Out(outDiffuse).xyz());
130 //use basecolor alpha and diffuse alpha
131 fstage.mul(Ogre::RTShader::In(diffuse).w(), Ogre::RTShader::In(outDiffuse).w(), Ogre::RTShader::Out(outDiffuse).w());
132 fstage.callFunction("PBR_MakeParams", { Ogre::RTShader::In(baseColor).xyz(), Ogre::RTShader::In(mrparams), Ogre::RTShader::InOut(pixelParams) });
133
134 fstage = psMain->getStage(Ogre::RTShader::FFP_PS_COLOUR_END + 60); // make gap to inject IBL here
135 if (mLightCount > 0)
136 {
137 auto lightPos = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_LIGHT_POSITION_VIEW_SPACE_ARRAY, mLightCount);
138 auto lightDiffuse = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR_POWER_SCALED_ARRAY, mLightCount);
139 auto pointParams = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_LIGHT_ATTENUATION_ARRAY, mLightCount);
140 auto spotParams = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_SPOTLIGHT_PARAMS_ARRAY, mLightCount);
141 auto lightDirView = psProgram->resolveParameter(Ogre::GpuProgramParameters::ACT_LIGHT_DIRECTION_VIEW_SPACE_ARRAY, mLightCount);
142
143 std::vector<Ogre::RTShader::Operand> params = { Ogre::RTShader::In(viewNormal), Ogre::RTShader::In(viewPos), Ogre::RTShader::In(ambientColor), Ogre::RTShader::In(lightPos),
144 Ogre::RTShader::In(lightDiffuse), Ogre::RTShader::In(pointParams), Ogre::RTShader::In(lightDirView), Ogre::RTShader::In(spotParams),
145 Ogre::RTShader::In(pixelParams), Ogre::RTShader::InOut(outDiffuse).xyz() };
146
147 if (mLtcLUT1SamplerIndex > -1)
148 {
149 auto ltcLUT1 = psProgram->resolveParameter(Ogre::GCT_SAMPLER2D, "ltcLUT1Sampler", mLtcLUT1SamplerIndex);
150 auto ltcLUT2 = psProgram->resolveParameter(Ogre::GCT_SAMPLER2D, "ltcLUT2Sampler", mLtcLUT1SamplerIndex + 1);
151 params.insert(params.begin(), { Ogre::RTShader::In(ltcLUT1), Ogre::RTShader::In(ltcLUT2) });
152 psProgram->addPreprocessorDefines("HAVE_AREA_LIGHTS");
153 }
154
155 if (auto shadowFactor = psMain->getLocalParameter("lShadowFactor"))
156 {
157 params.insert(params.begin(), Ogre::RTShader::In(shadowFactor));
158 }
159
160 fstage.callFunction("PBR_Lights", params);
161 }
162
163 return true;
164 }
165
166 //-----------------------------------------------------------------------
167 void AdvancedCookTorranceLighting::copyFrom(const Ogre::RTShader::SubRenderState& rhs)
168 {
169 const AdvancedCookTorranceLighting& rhsLighting = static_cast<const AdvancedCookTorranceLighting&>(rhs);
170 mMetalRoughnessMapName = rhsLighting.mMetalRoughnessMapName;
171 mUseOcclusion = rhsLighting.mUseOcclusion;
172 mLightCount = rhsLighting.mLightCount;
173 }
174
175 //-----------------------------------------------------------------------
176 bool AdvancedCookTorranceLighting::preAddToRenderState(const Ogre::RTShader::RenderState* renderState, Ogre::Pass* srcPass, Ogre::Pass* dstPass)
177 {
178 if (!srcPass->getLightingEnabled())
179 return false;
180
181 mLightCount = renderState->getLightCount();
182
183 if (renderState->haveAreaLights())
184 mLtcLUT1SamplerIndex = Ogre::RTShader::ensureLtcLUTPresent(dstPass);
185
186 if (mMetalRoughnessMapName.empty())
187 return true;
188
189 dstPass->createTextureUnitState(mMetalRoughnessMapName);
190 mMRMapSamplerIndex = dstPass->getNumTextureUnitStates() - 1;
191
192 return true;
193 }
194
195 bool AdvancedCookTorranceLighting::setParameter(const Ogre::String& name, const Ogre::String& value)
196 {
197 if (name == "texture" && !value.empty())
198 {
199 mMetalRoughnessMapName = value;
200 return true;
201 }
202 else if (name == "occlusion" && !value.empty())
203 {
204 mUseOcclusion = (value == "ON" || value == "YES") ? true : false;
205 return true;
206 }
207
208 return false;
209 }
210
211 //-----------------------------------------------------------------------
213
214 //-----------------------------------------------------------------------
215 Ogre::RTShader::SubRenderState* AdvancedCookTorranceLightingFactory::createInstance(Ogre::ScriptCompiler* compiler, Ogre::PropertyAbstractNode* prop,
216 Ogre::Pass* pass, Ogre::RTShader::SGScriptTranslator* translator)
217 {
218 if (prop->name == "lighting_stage" && prop->values.size() >= 1)
219 {
220 Ogre::String strValue;
221 Ogre::AbstractNodeList::const_iterator it = prop->values.begin();
222
223 // Read light model type.
224 if ((*it++)->getString() != "metal_roughness")
225 return NULL;
226
227 auto subRenderState = createOrRetrieveInstance(translator);
228
229 if (prop->values.size() < 3)
230 return subRenderState;
231
232 if ((*it++)->getString() != "texture")
233 {
234 compiler->addError(Ogre::ScriptCompiler::CE_INVALIDPARAMETERS, prop->file, prop->line);
235 return subRenderState;
236 }
237
238 if (!subRenderState->setParameter("texture", (*it++)->getString()))
239 compiler->addError(Ogre::ScriptCompiler::CE_INVALIDPARAMETERS, prop->file, prop->line);
240
241 return subRenderState;
242 }
243
244 return NULL;
245 }
246
247 //-----------------------------------------------------------------------
248 void AdvancedCookTorranceLightingFactory::writeInstance(Ogre::MaterialSerializer* ser, Ogre::RTShader::SubRenderState* subRenderState, Ogre::Pass* srcPass,
249 Ogre::Pass* dstPass)
250 {
251 auto ctSubRenderState = static_cast<AdvancedCookTorranceLighting*>(subRenderState);
252
253 ser->writeAttribute(4, "lighting_stage");
254 ser->writeValue("metal_roughness");
255 if (ctSubRenderState->getMetalRoughnessMapName().empty())
256 return;
257 ser->writeValue("texture");
258 ser->writeValue(ctSubRenderState->getMetalRoughnessMapName());
259 }
260
261 //-----------------------------------------------------------------------
263
264}
SCOL_EXPORT int cbmachine w
Definition SO3SCOL.cpp:5150
void writeInstance(Ogre::MaterialSerializer *ser, Ogre::RTShader::SubRenderState *subRenderState, Ogre::Pass *srcPass, Ogre::Pass *dstPass) override
const Ogre::String & getType() const override
Ogre::RTShader::SubRenderState * createInstance(Ogre::ScriptCompiler *compiler, Ogre::PropertyAbstractNode *prop, Ogre::Pass *pass, Ogre::RTShader::SGScriptTranslator *translator) override
Ogre::RTShader::SubRenderState * createInstanceImpl() override
const Ogre::String & getType() const override
bool createCpuSubPrograms(Ogre::RTShader::ProgramSet *programSet) override
bool preAddToRenderState(const Ogre::RTShader::RenderState *renderState, Ogre::Pass *srcPass, Ogre::Pass *dstPass) override
void copyFrom(const Ogre::RTShader::SubRenderState &rhs) override
bool setParameter(const Ogre::String &name, const Ogre::String &value) override
const Ogre::String SRS_ADV_COOK_TORRANCE_LIGHTING