1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsStandardDeferred.h"
4#include "Material/BsGpuParamsSet.h"
5#include "Mesh/BsMesh.h"
6#include "Renderer/BsSkybox.h"
7#include "Renderer/BsReflectionProbe.h"
8#include "Renderer/BsRendererUtility.h"
9#include "BsRendererScene.h"
10#include "BsRendererView.h"
11
12namespace bs { namespace ct {
13 PerLightParamDef gPerLightParamDef;
14
15 DeferredDirectionalLightMat::DeferredDirectionalLightMat()
16 :mGBufferParams(GPT_FRAGMENT_PROGRAM, mParams)
17 {
18 mParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
19 }
20
21 void DeferredDirectionalLightMat::bind(const GBufferTextures& gBufferInput, const SPtr<Texture>& lightOcclusion,
22 const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<GpuParamBlockBuffer>& perLight)
23 {
24 mGBufferParams.bind(gBufferInput);
25 mLightOcclusionTexParam.set(lightOcclusion);
26 mParams->setParamBlockBuffer("PerCamera", perCamera);
27 mParams->setParamBlockBuffer("PerLight", perLight);
28
29 RendererMaterial::bind();
30 }
31
32 DeferredDirectionalLightMat* DeferredDirectionalLightMat::getVariation(bool msaa, bool singleSampleMSAA)
33 {
34 if (msaa)
35 {
36 if (singleSampleMSAA)
37 return get(getVariation<true, true>());
38 else
39 return get(getVariation<true, false>());
40 }
41
42 return get(getVariation<false, false>());
43 }
44
45 DeferredPointLightMat::DeferredPointLightMat()
46 :mGBufferParams(GPT_FRAGMENT_PROGRAM, mParams)
47 {
48 mParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
49 }
50
51 void DeferredPointLightMat::bind(const GBufferTextures& gBufferInput, const SPtr<Texture>& lightOcclusion,
52 const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<GpuParamBlockBuffer>& perLight)
53 {
54 mGBufferParams.bind(gBufferInput);
55 mLightOcclusionTexParam.set(lightOcclusion);
56 mParams->setParamBlockBuffer("PerCamera", perCamera);
57 mParams->setParamBlockBuffer("PerLight", perLight);
58
59 RendererMaterial::bind();
60 }
61
62 DeferredPointLightMat* DeferredPointLightMat::getVariation(bool inside, bool msaa, bool singleSampleMSAA)
63 {
64 if(msaa)
65 {
66 if (inside)
67 {
68 if (singleSampleMSAA)
69 return get(getVariation<true, true, true>());
70
71 return get(getVariation<true, true, false>());
72 }
73 else
74 {
75 if (singleSampleMSAA)
76 return get(getVariation<false, true, true>());
77
78 return get(getVariation<false, true, false>());
79 }
80 }
81 else
82 {
83 if (inside)
84 return get(getVariation<true, false, false>());
85 else
86 return get(getVariation<false, false, false>());
87 }
88 }
89
90 PerProbeParamDef gPerProbeParamDef;
91
92 DeferredIBLSetupMat::DeferredIBLSetupMat()
93 :mGBufferParams(GPT_FRAGMENT_PROGRAM, mParams)
94 {
95 mIBLParams.populate(mParams, GPT_FRAGMENT_PROGRAM, true, false, false);
96 }
97
98 void DeferredIBLSetupMat::bind(const GBufferTextures& gBufferInput, const SPtr<GpuParamBlockBuffer>& perCamera,
99 const SPtr<Texture>& ssr, const SPtr<Texture>& ao, const SPtr<GpuParamBlockBuffer>& reflProbeParams)
100 {
101 mGBufferParams.bind(gBufferInput);
102
103 mParams->setParamBlockBuffer("PerCamera", perCamera);
104 mParams->setParamBlockBuffer("ReflProbeParams", reflProbeParams);
105
106 mIBLParams.ambientOcclusionTexParam.set(ao);
107 mIBLParams.ssrTexParam.set(ssr);
108
109 RendererMaterial::bind();
110 }
111
112 DeferredIBLSetupMat* DeferredIBLSetupMat::getVariation(bool msaa, bool singleSampleMSAA)
113 {
114 if(msaa)
115 {
116 if (singleSampleMSAA)
117 return get(getVariation<true, true>());
118
119 return get(getVariation<true, false>());
120 }
121 else
122 {
123 return get(getVariation<false, false>());
124 }
125 }
126
127 DeferredIBLProbeMat::DeferredIBLProbeMat()
128 :mGBufferParams(GPT_FRAGMENT_PROGRAM, mParams)
129 {
130 mIBLParams.populate(mParams, GPT_FRAGMENT_PROGRAM, true, false, false);
131
132 mParamBuffer = gPerProbeParamDef.createBuffer();
133 mParams->setParamBlockBuffer("PerProbe", mParamBuffer);
134 }
135
136 void DeferredIBLProbeMat::bind(const GBufferTextures& gBufferInput, const SPtr<GpuParamBlockBuffer>& perCamera,
137 const SceneInfo& sceneInfo, const ReflProbeData& probeData, const SPtr<GpuParamBlockBuffer>& reflProbeParams)
138 {
139 mGBufferParams.bind(gBufferInput);
140
141 mParams->setParamBlockBuffer("PerCamera", perCamera);
142 mParams->setParamBlockBuffer("ReflProbeParams", reflProbeParams);
143
144 gPerProbeParamDef.gPosition.set(mParamBuffer, probeData.position);
145
146 if(probeData.type == 1)
147 gPerProbeParamDef.gExtents.set(mParamBuffer, probeData.boxExtents);
148 else
149 {
150 Vector3 extents(probeData.radius, probeData.radius, probeData.radius);
151 gPerProbeParamDef.gExtents.set(mParamBuffer, extents);
152 }
153
154 gPerProbeParamDef.gTransitionDistance.set(mParamBuffer, probeData.transitionDistance);
155 gPerProbeParamDef.gInvBoxTransform.set(mParamBuffer, probeData.invBoxTransform);
156 gPerProbeParamDef.gCubemapIdx.set(mParamBuffer, probeData.cubemapIdx);
157 gPerProbeParamDef.gType.set(mParamBuffer, probeData.type);
158
159 mIBLParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
160
161 RendererMaterial::bind();
162 }
163
164 DeferredIBLProbeMat* DeferredIBLProbeMat::getVariation(bool inside, bool msaa, bool singleSampleMSAA)
165 {
166 if(msaa)
167 {
168 if (inside)
169 {
170 if (singleSampleMSAA)
171 return get(getVariation<true, true, true>());
172
173 return get(getVariation<true, true, false>());
174 }
175 else
176 {
177 if (singleSampleMSAA)
178 return get(getVariation<false, true, true>());
179
180 return get(getVariation<false, true, false>());
181 }
182 }
183 else
184 {
185 if (inside)
186 return get(getVariation<true, false, false>());
187 else
188 return get(getVariation<false, false, false>());
189 }
190 }
191
192 DeferredIBLSkyMat::DeferredIBLSkyMat()
193 :mGBufferParams(GPT_FRAGMENT_PROGRAM, mParams)
194 {
195 mIBLParams.populate(mParams, GPT_FRAGMENT_PROGRAM, true, false, false);
196 }
197
198 void DeferredIBLSkyMat::bind(const GBufferTextures& gBufferInput, const SPtr<GpuParamBlockBuffer>& perCamera,
199 const Skybox* skybox, const SPtr<GpuParamBlockBuffer>& reflProbeParams)
200 {
201 mGBufferParams.bind(gBufferInput);
202
203 mParams->setParamBlockBuffer("PerCamera", perCamera);
204 mParams->setParamBlockBuffer("ReflProbeParams", reflProbeParams);
205
206 if(skybox != nullptr)
207 mIBLParams.skyReflectionsTexParam.set(skybox->getFilteredRadiance());
208
209 RendererMaterial::bind();
210 }
211
212 DeferredIBLSkyMat* DeferredIBLSkyMat::getVariation(bool msaa, bool singleSampleMSAA)
213 {
214 if(msaa)
215 {
216 if (singleSampleMSAA)
217 return get(getVariation<true, true>());
218
219 return get(getVariation<true, false>());
220 }
221 else
222 {
223 return get(getVariation<false, false>());
224 }
225 }
226
227 DeferredIBLFinalizeMat::DeferredIBLFinalizeMat()
228 :mGBufferParams(GPT_FRAGMENT_PROGRAM, mParams)
229 {
230 mParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gIBLRadianceTex", mIBLRadiance);
231
232 mIBLParams.populate(mParams, GPT_FRAGMENT_PROGRAM, true, false, false);
233 }
234
235 void DeferredIBLFinalizeMat::bind(const GBufferTextures& gBufferInput, const SPtr<GpuParamBlockBuffer>& perCamera,
236 const SPtr<Texture>& iblRadiance, const SPtr<Texture>& preintegratedBrdf,
237 const SPtr<GpuParamBlockBuffer>& reflProbeParams)
238 {
239 mGBufferParams.bind(gBufferInput);
240
241 mParams->setParamBlockBuffer("PerCamera", perCamera);
242 mParams->setParamBlockBuffer("ReflProbeParams", reflProbeParams);
243
244 mIBLParams.preintegratedEnvBRDFParam.set(preintegratedBrdf);
245
246 mIBLRadiance.set(iblRadiance);
247
248 RendererMaterial::bind();
249 }
250
251 DeferredIBLFinalizeMat* DeferredIBLFinalizeMat::getVariation(bool msaa, bool singleSampleMSAA)
252 {
253 if(msaa)
254 {
255 if (singleSampleMSAA)
256 return get(getVariation<true, true>());
257
258 return get(getVariation<true, false>());
259 }
260 else
261 {
262 return get(getVariation<false, false>());
263 }
264 }
265
266 StandardDeferred::StandardDeferred()
267 {
268 mPerLightBuffer = gPerLightParamDef.createBuffer();
269 }
270
271 void StandardDeferred::renderLight(LightType lightType, const RendererLight& light, const RendererView& view,
272 const GBufferTextures& gBufferInput, const SPtr<Texture>& lightOcclusion)
273 {
274 const auto& viewProps = view.getProperties();
275
276 bool isMSAA = view.getProperties().target.numSamples > 1;
277 SPtr<GpuParamBlockBuffer> perViewBuffer = view.getPerViewBuffer();
278
279 light.getParameters(mPerLightBuffer);
280
281 if (lightType == LightType::Directional)
282 {
283 DeferredDirectionalLightMat* material = DeferredDirectionalLightMat::getVariation(isMSAA, true);
284 material->bind(gBufferInput, lightOcclusion, perViewBuffer, mPerLightBuffer);
285
286 gRendererUtility().drawScreenQuad();
287
288 // Draw pixels requiring per-sample evaluation
289 if(isMSAA)
290 {
291 DeferredDirectionalLightMat* msaaMaterial = DeferredDirectionalLightMat::getVariation(true, false);
292 msaaMaterial->bind(gBufferInput, lightOcclusion, perViewBuffer, mPerLightBuffer);
293
294 gRendererUtility().drawScreenQuad();
295 }
296 }
297 else // Radial or spot
298 {
299 // Check if viewer is inside the light volume
300 float distSqrd = (light.internal->getBounds().getCenter() - viewProps.viewOrigin).squaredLength();
301
302 // Extend the bounds slighty to cover the case when the viewer is outside, but the near plane is intersecting
303 // the light bounds. We need to be conservative since the material for rendering outside will not properly
304 // render the inside of the light volume.
305 float boundRadius = light.internal->getBounds().getRadius() + viewProps.nearPlane * 3.0f;
306
307 bool isInside = distSqrd < (boundRadius * boundRadius);
308
309 SPtr<Mesh> stencilMesh;
310 if(lightType == LightType::Radial)
311 stencilMesh = RendererUtility::instance().getSphereStencil();
312 else // Spot
313 stencilMesh = RendererUtility::instance().getSpotLightStencil();
314
315 DeferredPointLightMat* material = DeferredPointLightMat::getVariation(isInside, isMSAA, true);
316 material->bind(gBufferInput, lightOcclusion, perViewBuffer, mPerLightBuffer);
317
318 // Note: If MSAA is enabled this will be rendered multisampled (on polygon edges), see if this can be avoided
319 gRendererUtility().draw(stencilMesh);
320
321 // Draw pixels requiring per-sample evaluation
322 if(isMSAA)
323 {
324 DeferredPointLightMat* msaaMaterial = DeferredPointLightMat::getVariation(isInside, true, false);
325 msaaMaterial->bind(gBufferInput, lightOcclusion, perViewBuffer, mPerLightBuffer);
326
327 gRendererUtility().draw(stencilMesh);
328 }
329 }
330 }
331 void StandardDeferred::renderReflProbe(const ReflProbeData& probeData, const RendererView& view,
332 const GBufferTextures& gBufferInput, const SceneInfo& sceneInfo, const SPtr<GpuParamBlockBuffer>& reflProbeParams)
333 {
334 const auto& viewProps = view.getProperties();
335 bool isMSAA = viewProps.target.numSamples > 1;
336
337 SPtr<GpuParamBlockBuffer> perViewBuffer = view.getPerViewBuffer();
338
339 // When checking if viewer is inside the volume extend the bounds slighty to cover the case when the viewer is
340 // outside, but the near plane is intersecting the bounds. We need to be conservative since the material for
341 // rendering outside will not properly render the inside of the volume.
342 float radiusBuffer = viewProps.nearPlane * 3.0f;
343
344 SPtr<Mesh> stencilMesh;
345 bool isInside;
346 if(probeData.type == 0) // Sphere
347 {
348 // Check if viewer is inside the light volume
349 float distSqrd = (probeData.position - viewProps.viewOrigin).squaredLength();
350 float boundRadius = probeData.radius + radiusBuffer;
351
352 isInside = distSqrd < (boundRadius * boundRadius);
353 stencilMesh = RendererUtility::instance().getSphereStencil();
354 }
355 else // Box
356 {
357 Vector3 extents = probeData.boxExtents + radiusBuffer;
358 AABox box(probeData.position - extents, probeData.position + extents);
359
360 isInside = box.contains(viewProps.viewOrigin);
361 stencilMesh = RendererUtility::instance().getBoxStencil();
362 }
363
364 DeferredIBLProbeMat* material = DeferredIBLProbeMat::getVariation(isInside, isMSAA, true);
365 material->bind(gBufferInput, perViewBuffer, sceneInfo, probeData, reflProbeParams);
366
367 // Note: If MSAA is enabled this will be rendered multisampled (on polygon edges), see if this can be avoided
368 gRendererUtility().draw(stencilMesh);
369
370 // Draw pixels requiring per-sample evaluation
371 if (isMSAA)
372 {
373 DeferredIBLProbeMat* msaaMaterial = DeferredIBLProbeMat::getVariation(isInside, true, false);
374 msaaMaterial->bind(gBufferInput, perViewBuffer, sceneInfo, probeData, reflProbeParams);
375
376 gRendererUtility().draw(stencilMesh);
377 }
378 }
379}}
380