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 | |
12 | namespace 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 | |