/src/ogre/Components/RTShaderSystem/src/OgreShaderExIntegratedPSSM3.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreShaderPrecompiledHeaders.h" |
29 | | #ifdef RTSHADER_SYSTEM_BUILD_EXT_SHADERS |
30 | | |
31 | 0 | #define SGX_LIB_INTEGRATEDPSSM "SGXLib_IntegratedPSSM" |
32 | | |
33 | | namespace Ogre { |
34 | | namespace RTShader { |
35 | | |
36 | | /************************************************************************/ |
37 | | /* */ |
38 | | /************************************************************************/ |
39 | | String IntegratedPSSM3::Type = "SGX_IntegratedPSSM3"; |
40 | | const String SRS_INTEGRATED_PSSM3 = "SGX_IntegratedPSSM3"; |
41 | | const String SRS_SHADOW_MAPPING = "SGX_IntegratedPSSM3"; |
42 | | |
43 | | //----------------------------------------------------------------------- |
44 | | IntegratedPSSM3::IntegratedPSSM3() |
45 | 0 | { |
46 | 0 | mPCFxSamples = 2; |
47 | 0 | mUseTextureCompare = false; |
48 | 0 | mUseColourShadows = false; |
49 | 0 | mDebug = false; |
50 | 0 | mIsD3D9 = false; |
51 | 0 | mUseArrayTexture = false; |
52 | 0 | mShadowTextureParamsList.resize(1); // normal single texture depth shadowmapping |
53 | 0 | mMultiLightCount = 1; |
54 | 0 | } |
55 | | |
56 | | //----------------------------------------------------------------------- |
57 | | int IntegratedPSSM3::getExecutionOrder() const |
58 | 0 | { |
59 | 0 | return FFP_LIGHTING - 1; |
60 | 0 | } |
61 | | |
62 | | //----------------------------------------------------------------------- |
63 | | void IntegratedPSSM3::updateGpuProgramsParams(Renderable* rend, const Pass* pass, |
64 | | const AutoParamDataSource* source, |
65 | | const LightList* pLightList) |
66 | 0 | { |
67 | 0 | if (mMultiLightCount > 1) |
68 | 0 | return; |
69 | | |
70 | 0 | Vector4 vSplitPoints; |
71 | |
|
72 | 0 | for(size_t i = 0; i < mShadowTextureParamsList.size() - 1; i++) |
73 | 0 | { |
74 | 0 | vSplitPoints[i] = mShadowTextureParamsList[i].mMaxRange; |
75 | 0 | } |
76 | 0 | vSplitPoints[3] = mShadowTextureParamsList.back().mMaxRange; |
77 | |
|
78 | 0 | const Matrix4& proj = source->getProjectionMatrix(); |
79 | |
|
80 | 0 | for(int i = 0; i < 4; i++) |
81 | 0 | { |
82 | 0 | auto tmp = proj * Vector4(0, 0, -vSplitPoints[i], 1); |
83 | 0 | vSplitPoints[i] = tmp[2] / tmp[3]; |
84 | 0 | } |
85 | | |
86 | |
|
87 | 0 | mPSSplitPoints->setGpuParameter(vSplitPoints); |
88 | |
|
89 | 0 | } |
90 | | |
91 | | //----------------------------------------------------------------------- |
92 | | void IntegratedPSSM3::copyFrom(const SubRenderState& rhs) |
93 | 0 | { |
94 | 0 | const IntegratedPSSM3& rhsPssm= static_cast<const IntegratedPSSM3&>(rhs); |
95 | |
|
96 | 0 | mPCFxSamples = rhsPssm.mPCFxSamples; |
97 | 0 | mUseTextureCompare = rhsPssm.mUseTextureCompare; |
98 | 0 | mUseColourShadows = rhsPssm.mUseColourShadows; |
99 | 0 | mDebug = rhsPssm.mDebug; |
100 | 0 | mMultiLightCount = rhsPssm.mMultiLightCount; |
101 | 0 | mUseArrayTexture = rhsPssm.mUseArrayTexture; |
102 | 0 | mShadowTextureParamsList.resize(rhsPssm.mShadowTextureParamsList.size()); |
103 | |
|
104 | 0 | ShadowTextureParamsConstIterator itSrc = rhsPssm.mShadowTextureParamsList.begin(); |
105 | 0 | for (auto& p : mShadowTextureParamsList) |
106 | 0 | { |
107 | 0 | p.mMaxRange = itSrc->mMaxRange; |
108 | 0 | ++itSrc; |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | //----------------------------------------------------------------------- |
113 | | bool IntegratedPSSM3::preAddToRenderState(const RenderState* renderState, |
114 | | Pass* srcPass, Pass* dstPass) |
115 | 0 | { |
116 | 0 | if (!srcPass->getParent()->getParent()->getReceiveShadows() || |
117 | 0 | renderState->getLightCount() == 0) |
118 | 0 | return false; |
119 | | |
120 | 0 | mIsD3D9 = ShaderGenerator::getSingleton().getTargetLanguage() == "hlsl" && |
121 | 0 | !GpuProgramManager::getSingleton().isSyntaxSupported("vs_4_0_level_9_1"); |
122 | |
|
123 | 0 | PixelFormat shadowTexFormat = PF_UNKNOWN; |
124 | 0 | const auto& configs = ShaderGenerator::getSingleton().getActiveSceneManager()->getShadowTextureConfigList(); |
125 | 0 | if (!configs.empty()) |
126 | 0 | shadowTexFormat = configs[0].format; // assume first texture is representative |
127 | 0 | mUseTextureCompare = PixelUtil::isDepth(shadowTexFormat) && !mIsD3D9; |
128 | 0 | mUseColourShadows = PixelUtil::getComponentType(shadowTexFormat) == PCT_BYTE; // use colour shadowmaps for byte textures |
129 | |
|
130 | 0 | if(mMultiLightCount > 1) |
131 | 0 | mShadowTextureParamsList.resize(mMultiLightCount); |
132 | |
|
133 | 0 | auto shadowSampler = TextureManager::getSingleton().getSampler(mUseTextureCompare ? "Ogre/DepthShadowSampler" |
134 | 0 | : "Ogre/ShadowSampler"); |
135 | 0 | for (auto& p : mShadowTextureParamsList) |
136 | 0 | { |
137 | 0 | TextureUnitState* curShadowTexture = dstPass->createTextureUnitState(); |
138 | 0 | curShadowTexture->setContentType(TextureUnitState::CONTENT_SHADOW); |
139 | 0 | curShadowTexture->setSampler(shadowSampler); |
140 | 0 | p.mTextureSamplerIndex = dstPass->getNumTextureUnitStates() - 1; |
141 | 0 | } |
142 | |
|
143 | 0 | return true; |
144 | 0 | } |
145 | | |
146 | | //----------------------------------------------------------------------- |
147 | | void IntegratedPSSM3::setSplitPoints(const SplitPointList& newSplitPoints) |
148 | 0 | { |
149 | 0 | OgreAssert(newSplitPoints.size() <= 5, "at most 5 split points are supported"); |
150 | | |
151 | 0 | mShadowTextureParamsList.resize(newSplitPoints.size() - 1); |
152 | |
|
153 | 0 | for (size_t i = 1; i < newSplitPoints.size(); ++i) |
154 | 0 | { |
155 | 0 | mShadowTextureParamsList[i - 1].mMaxRange = newSplitPoints[i]; |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | bool IntegratedPSSM3::setParameter(const String& name, const String& value) |
160 | 0 | { |
161 | 0 | if(name == "debug") |
162 | 0 | { |
163 | 0 | return StringConverter::parse(value, mDebug); |
164 | 0 | } |
165 | 0 | else if (name == "filter") |
166 | 0 | { |
167 | 0 | if(value == "pcf4") |
168 | 0 | mPCFxSamples = 2; |
169 | 0 | else if(value == "pcf16") |
170 | 0 | mPCFxSamples = 4; |
171 | 0 | else |
172 | 0 | return false; |
173 | | |
174 | 0 | return true; |
175 | 0 | } |
176 | 0 | else if (name == "light_count") |
177 | 0 | { |
178 | 0 | mMultiLightCount = StringConverter::parseInt(value); |
179 | 0 | return true; |
180 | 0 | } |
181 | 0 | else if (name == "array_texture") |
182 | 0 | { |
183 | 0 | return StringConverter::parse(value, mUseArrayTexture); |
184 | 0 | } |
185 | | |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | | void IntegratedPSSM3::setParameter(const String& name, const Any& value) |
190 | 0 | { |
191 | 0 | if(name == "split_points") |
192 | 0 | { |
193 | 0 | setSplitPoints(any_cast<SplitPointList>(value)); |
194 | 0 | return; |
195 | 0 | } |
196 | 0 | else if (name == "debug") |
197 | 0 | { |
198 | 0 | mDebug = any_cast<bool>(value); |
199 | 0 | return; |
200 | 0 | } |
201 | 0 | else if (name == "array_texture") |
202 | 0 | { |
203 | 0 | mUseArrayTexture = any_cast<bool>(value); |
204 | 0 | return; |
205 | 0 | } |
206 | | |
207 | 0 | SubRenderState::setParameter(name, value); |
208 | 0 | } |
209 | | |
210 | | //----------------------------------------------------------------------- |
211 | | bool IntegratedPSSM3::resolveParameters(ProgramSet* programSet) |
212 | 0 | { |
213 | 0 | Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM); |
214 | 0 | Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM); |
215 | 0 | Function* vsMain = vsProgram->getEntryPointFunction(); |
216 | 0 | Function* psMain = psProgram->getEntryPointFunction(); |
217 | | |
218 | | // Get input position parameter. |
219 | 0 | mVSInPos = vsMain->getLocalParameter(Parameter::SPC_POSITION_OBJECT_SPACE); |
220 | 0 | if(!mVSInPos) |
221 | 0 | mVSInPos = vsMain->getInputParameter(Parameter::SPC_POSITION_OBJECT_SPACE); |
222 | | |
223 | | // Get output position parameter. |
224 | 0 | mVSOutPos = vsMain->getOutputParameter(Parameter::SPC_POSITION_PROJECTIVE_SPACE); |
225 | |
|
226 | 0 | if (mIsD3D9) |
227 | 0 | { |
228 | 0 | mVSOutPos = vsMain->resolveOutputParameter(Parameter::SPC_UNKNOWN, GCT_FLOAT4); |
229 | 0 | } |
230 | | |
231 | | // Resolve input depth parameter. |
232 | 0 | mPSInDepth = psMain->resolveInputParameter(mVSOutPos); |
233 | | |
234 | | // Resolve computed local shadow colour parameter. |
235 | 0 | mPSLocalShadowFactor = psMain->resolveLocalParameter(GCT_FLOAT1, "lShadowFactor", mMultiLightCount); |
236 | | |
237 | | // Resolve computed local shadow colour parameter. |
238 | 0 | mPSSplitPoints = psProgram->resolveParameter(GCT_FLOAT4, "pssm_split_points"); |
239 | |
|
240 | 0 | int lightIndex = 0; |
241 | |
|
242 | 0 | auto stype = GCT_SAMPLER2D; |
243 | 0 | if(mUseTextureCompare) |
244 | 0 | { |
245 | 0 | stype = mUseArrayTexture ? GCT_SAMPLER2DARRAYSHADOW : GCT_SAMPLER2DSHADOW; |
246 | 0 | } |
247 | 0 | else { |
248 | 0 | stype = mUseArrayTexture ? GCT_SAMPLER2DARRAY : GCT_SAMPLER2D; |
249 | 0 | } |
250 | |
|
251 | 0 | mWorldViewProjMatrices = vsProgram->resolveParameter(GpuProgramParameters::ACT_TEXTURE_WORLDVIEWPROJ_MATRIX_ARRAY, |
252 | 0 | mShadowTextureParamsList.size()); |
253 | 0 | for (auto& p : mShadowTextureParamsList) |
254 | 0 | { |
255 | 0 | p.mVSOutLightPosition = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_LIGHT_SPACE0 + lightIndex); |
256 | 0 | p.mPSInLightPosition = psMain->resolveInputParameter(p.mVSOutLightPosition); |
257 | 0 | if(mUseArrayTexture) |
258 | 0 | p.mTextureSamplerIndex = mShadowTextureParamsList[0].mTextureSamplerIndex; |
259 | 0 | p.mTextureSampler = psProgram->resolveParameter(stype, "shadow_map", p.mTextureSamplerIndex); |
260 | 0 | p.mInvTextureSize = psProgram->resolveParameter(GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, p.mTextureSamplerIndex); |
261 | 0 | ++lightIndex; |
262 | 0 | } |
263 | |
|
264 | 0 | if (!(mVSInPos.get()) || !(mVSOutPos.get())) |
265 | 0 | { |
266 | 0 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Not all parameters could be constructed for the sub-render state."); |
267 | 0 | } |
268 | | |
269 | 0 | return true; |
270 | 0 | } |
271 | | |
272 | | //----------------------------------------------------------------------- |
273 | | bool IntegratedPSSM3::resolveDependencies(ProgramSet* programSet) |
274 | 0 | { |
275 | 0 | Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM); |
276 | 0 | psProgram->addDependency(SGX_LIB_INTEGRATEDPSSM); |
277 | |
|
278 | 0 | psProgram->addPreprocessorDefines(StringUtil::format("PSSM_NUM_SPLITS=%zu,PCF_XSAMPLES=%.1f,SHADOWLIGHT_COUNT=%d", |
279 | 0 | mShadowTextureParamsList.size(), mPCFxSamples, mMultiLightCount)); |
280 | |
|
281 | 0 | if(mDebug) |
282 | 0 | psProgram->addPreprocessorDefines("DEBUG_PSSM"); |
283 | |
|
284 | 0 | if(mUseTextureCompare) |
285 | 0 | psProgram->addPreprocessorDefines("PSSM_SAMPLE_CMP"); |
286 | |
|
287 | 0 | if(mUseColourShadows) |
288 | 0 | psProgram->addPreprocessorDefines("PSSM_SAMPLE_COLOUR"); |
289 | |
|
290 | 0 | if(mUseArrayTexture) |
291 | 0 | psProgram->addPreprocessorDefines("PSSM_ARRAY_TEXTURE"); |
292 | |
|
293 | 0 | return true; |
294 | 0 | } |
295 | | |
296 | | //----------------------------------------------------------------------- |
297 | | bool IntegratedPSSM3::addFunctionInvocations(ProgramSet* programSet) |
298 | 0 | { |
299 | 0 | Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM); |
300 | 0 | Function* vsMain = vsProgram->getEntryPointFunction(); |
301 | 0 | Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM); |
302 | | |
303 | | // Add vertex shader invocations. |
304 | 0 | if (false == addVSInvocation(vsMain, FFP_VS_TEXTURING + 1)) |
305 | 0 | return false; |
306 | | |
307 | | // Add pixel shader invocations. |
308 | 0 | if (false == addPSInvocation(psProgram, FFP_PS_COLOUR_BEGIN)) |
309 | 0 | return false; |
310 | | |
311 | 0 | return true; |
312 | 0 | } |
313 | | |
314 | | //----------------------------------------------------------------------- |
315 | | bool IntegratedPSSM3::addVSInvocation(Function* vsMain, const int groupOrder) |
316 | 0 | { |
317 | 0 | auto stage = vsMain->getStage(groupOrder); |
318 | |
|
319 | 0 | if(mIsD3D9) |
320 | 0 | { |
321 | 0 | auto vsOutPos = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_PROJECTIVE_SPACE); |
322 | 0 | stage.assign(vsOutPos, mVSOutPos); |
323 | 0 | } |
324 | | |
325 | | // Compute world space position. |
326 | 0 | int idx = 0; |
327 | 0 | for (auto& p : mShadowTextureParamsList) |
328 | 0 | { |
329 | 0 | stage.callBuiltin("mul", {In(mWorldViewProjMatrices), At(idx++), In(mVSInPos), Out(p.mVSOutLightPosition)}); |
330 | 0 | } |
331 | |
|
332 | 0 | return true; |
333 | 0 | } |
334 | | |
335 | | //----------------------------------------------------------------------- |
336 | | bool IntegratedPSSM3::addPSInvocation(Program* psProgram, const int groupOrder) |
337 | 0 | { |
338 | 0 | Function* psMain = psProgram->getEntryPointFunction(); |
339 | 0 | auto stage = psMain->getStage(groupOrder); |
340 | |
|
341 | 0 | if(mShadowTextureParamsList.size() < 2 || mMultiLightCount > 1) |
342 | 0 | { |
343 | 0 | for(uchar i = 0; i < mMultiLightCount; ++i) |
344 | 0 | { |
345 | 0 | ShadowTextureParams& params = mShadowTextureParamsList[i]; |
346 | 0 | stage.callFunction("SGX_ShadowPCF4", |
347 | 0 | {In(params.mTextureSampler), In(params.mPSInLightPosition), |
348 | 0 | In(params.mInvTextureSize).xy(), Out(mPSLocalShadowFactor), At(i)}); |
349 | 0 | } |
350 | 0 | } |
351 | 0 | else |
352 | 0 | { |
353 | 0 | auto fdepth = psMain->resolveLocalParameter(GCT_FLOAT1, "fdepth"); |
354 | 0 | if(mIsD3D9) |
355 | 0 | stage.div(In(mPSInDepth).z(), In(mPSInDepth).w(), fdepth); |
356 | 0 | else |
357 | 0 | stage.assign(In(mPSInDepth).z(), fdepth); |
358 | 0 | std::vector<Operand> params = {In(fdepth), In(mPSSplitPoints)}; |
359 | |
|
360 | 0 | for(auto& texp : mShadowTextureParamsList) |
361 | 0 | { |
362 | 0 | params.push_back(In(texp.mPSInLightPosition)); |
363 | 0 | params.push_back(In(texp.mTextureSampler)); |
364 | 0 | params.push_back(In(texp.mInvTextureSize).xy()); |
365 | 0 | } |
366 | |
|
367 | 0 | params.push_back(Out(mPSLocalShadowFactor)); |
368 | 0 | params.push_back(At(0)); |
369 | |
|
370 | 0 | if(mDebug) |
371 | 0 | { |
372 | 0 | auto sceneCol = psProgram->resolveParameter(GpuProgramParameters::ACT_DERIVED_SCENE_COLOUR); |
373 | 0 | params.push_back(InOut(sceneCol)); |
374 | 0 | } |
375 | | |
376 | | // Compute shadow factor. |
377 | 0 | stage.callFunction("SGX_ComputeShadowFactor_PSSM3", params); |
378 | 0 | } |
379 | | |
380 | | // shadow factor is applied by lighting stages |
381 | 0 | return true; |
382 | 0 | } |
383 | | |
384 | | //----------------------------------------------------------------------- |
385 | | SubRenderState* IntegratedPSSM3Factory::createInstance(const ScriptProperty& prop, Pass* pass, SGScriptTranslator* translator) |
386 | 0 | { |
387 | 0 | if (prop.name == "integrated_pssm4") |
388 | 0 | { |
389 | 0 | translator->emitError("integrated_pssm4. Use shadow_mapping instead.", ScriptCompiler::CE_DEPRECATEDSYMBOL); |
390 | |
|
391 | 0 | SubRenderState* subRenderState = createOrRetrieveInstance(translator); |
392 | |
|
393 | 0 | if (prop.values.size() >= 4) |
394 | 0 | { |
395 | 0 | IntegratedPSSM3::SplitPointList splitPointList(4); |
396 | 0 | for(int i = 0; i < 4; ++i) |
397 | 0 | { |
398 | 0 | if (!StringConverter::parse(prop.values[i], splitPointList[i])) |
399 | 0 | { |
400 | 0 | translator->emitError(); |
401 | 0 | } |
402 | 0 | } |
403 | 0 | subRenderState->setParameter("split_points", splitPointList); |
404 | 0 | } |
405 | |
|
406 | 0 | auto it = prop.values.begin() + 4; |
407 | 0 | for (; it != prop.values.end(); ++it) |
408 | 0 | { |
409 | 0 | const auto& val = (*it); |
410 | 0 | if(val == "debug") |
411 | 0 | { |
412 | 0 | subRenderState->setParameter("debug", "true"); |
413 | 0 | } |
414 | 0 | else if(val == "pcf16") |
415 | 0 | { |
416 | 0 | subRenderState->setParameter("filter", "pcf16"); |
417 | 0 | } |
418 | 0 | } |
419 | |
|
420 | 0 | return subRenderState; |
421 | 0 | } |
422 | | |
423 | 0 | if (prop.name == "shadow_mapping") |
424 | 0 | { |
425 | 0 | SubRenderState* subRenderState = createOrRetrieveInstance(translator); |
426 | |
|
427 | 0 | auto it = prop.values.begin(); |
428 | 0 | while(it != prop.values.end()) |
429 | 0 | { |
430 | 0 | String paramName = (*it); |
431 | 0 | String paramValue = (*++it); |
432 | |
|
433 | 0 | if (!subRenderState->setParameter(paramName, paramValue)) |
434 | 0 | { |
435 | 0 | translator->emitError(paramName); |
436 | 0 | return subRenderState; |
437 | 0 | } |
438 | 0 | it++; |
439 | 0 | } |
440 | | |
441 | 0 | return subRenderState; |
442 | 0 | } |
443 | | |
444 | 0 | return NULL; |
445 | 0 | } |
446 | | |
447 | | //----------------------------------------------------------------------- |
448 | | SubRenderState* IntegratedPSSM3Factory::createInstanceImpl() |
449 | 0 | { |
450 | | return OGRE_NEW IntegratedPSSM3; |
451 | 0 | } |
452 | | |
453 | | } |
454 | | } |
455 | | |
456 | | #endif |