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 "BsRendererReflectionProbe.h"
4#include "Material/BsMaterial.h"
5#include "RenderAPI/BsGpuBuffer.h"
6#include "Renderer/BsReflectionProbe.h"
7#include "BsRenderBeast.h"
8#include "Renderer/BsRendererUtility.h"
9#include "Renderer/BsSkybox.h"
10
11namespace bs { namespace ct
12{
13 static const UINT32 REFL_PROBE_BUFFER_INCREMENT = 16 * sizeof(ReflProbeData);
14
15 ReflProbeParamsParamDef gReflProbeParamsParamDef;
16
17 void VisibleReflProbeData::update(const SceneInfo& sceneInfo, const RendererViewGroup& viewGroup)
18 {
19 mReflProbeData.clear();
20
21 const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
22
23 // Generate refl. probe data for the visible ones
24 UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
25 for(UINT32 i = 0; i < numProbes; i++)
26 {
27 if (!visibility.reflProbes[i])
28 continue;
29
30 mReflProbeData.push_back(ReflProbeData());
31 sceneInfo.reflProbes[i].getParameters(mReflProbeData.back());
32 }
33
34 // Sort probes so bigger ones get accessed first, this way we overlay smaller ones on top of biggers ones when
35 // rendering
36 auto sorter = [](const ReflProbeData& lhs, const ReflProbeData& rhs)
37 {
38 return rhs.radius < lhs.radius;
39 };
40
41 std::sort(mReflProbeData.begin(), mReflProbeData.end(), sorter);
42
43 mNumProbes = (UINT32)mReflProbeData.size();
44
45 // Move refl. probe data into a GPU buffer
46 bool supportsStructuredBuffers = gRenderBeast()->getFeatureSet() == RenderBeastFeatureSet::Desktop;
47 if(supportsStructuredBuffers)
48 {
49 UINT32 size = mNumProbes * sizeof(ReflProbeData);
50 UINT32 curBufferSize;
51
52 if (mProbeBuffer != nullptr)
53 curBufferSize = mProbeBuffer->getSize();
54 else
55 curBufferSize = 0;
56
57 if (size > curBufferSize || curBufferSize == 0)
58 {
59 // Allocate at least one block even if no probes, to avoid issues with null buffers
60 UINT32 bufferSize = std::max(1, Math::ceilToInt(size / (float) REFL_PROBE_BUFFER_INCREMENT)) * REFL_PROBE_BUFFER_INCREMENT;
61
62 GPU_BUFFER_DESC bufferDesc;
63 bufferDesc.type = GBT_STRUCTURED;
64 bufferDesc.elementCount = bufferSize / sizeof(ReflProbeData);
65 bufferDesc.elementSize = sizeof(ReflProbeData);
66 bufferDesc.format = BF_UNKNOWN;
67
68 mProbeBuffer = GpuBuffer::create(bufferDesc);
69 }
70
71 if (size > 0)
72 mProbeBuffer->writeData(0, size, mReflProbeData.data(), BWT_DISCARD);
73 }
74 }
75
76 RendererReflectionProbe::RendererReflectionProbe(ReflectionProbe* probe)
77 :probe(probe)
78 {
79 arrayIdx = -1;
80 arrayDirty = true;
81 errorFlagged = false;
82 }
83
84 void RendererReflectionProbe::getParameters(ReflProbeData& output) const
85 {
86 output.type = probe->getType() == ReflectionProbeType::Sphere ? 0
87 : probe->getType() == ReflectionProbeType::Box ? 1 : 2;
88
89 const Transform& tfrm = probe->getTransform();
90 output.position = tfrm.getPosition();
91 output.boxExtents = probe->getExtents();
92
93 if (probe->getType() == ReflectionProbeType::Sphere)
94 output.radius = probe->getRadius();
95 else
96 output.radius = output.boxExtents.length();
97
98 output.transitionDistance = probe->getTransitionDistance();
99 output.cubemapIdx = arrayIdx;
100 output.invBoxTransform.setInverseTRS(output.position, tfrm.getRotation(), output.boxExtents);
101 }
102
103 void ImageBasedLightingParams::populate(const SPtr<GpuParams>& params, GpuProgramType programType, bool optional,
104 bool gridIndices, bool probeArray)
105 {
106 // Sky
107 if (!optional || params->hasTexture(programType, "gSkyReflectionTex"))
108 params->getTextureParam(programType, "gSkyReflectionTex", skyReflectionsTexParam);
109
110 // Reflections
111 if (!optional || params->hasTexture(programType, "gReflProbeCubemaps"))
112 {
113 params->getTextureParam(programType, "gReflProbeCubemaps", reflectionProbeCubemapsTexParam);
114
115 if(probeArray)
116 params->getBufferParam(programType, "gReflectionProbes", reflectionProbesParam);
117 }
118
119 if (!optional || params->hasTexture(programType, "gPreintegratedEnvBRDF"))
120 params->getTextureParam(programType, "gPreintegratedEnvBRDF", preintegratedEnvBRDFParam);
121
122 // AO
123 if (params->hasTexture(programType, "gAmbientOcclusionTex"))
124 params->getTextureParam(programType, "gAmbientOcclusionTex", ambientOcclusionTexParam);
125
126 // SSR
127 if (params->hasTexture(programType, "gSSRTex"))
128 params->getTextureParam(programType, "gSSRTex", ssrTexParam);
129
130 if(gridIndices)
131 {
132 if (!optional || params->hasBuffer(programType, "gReflectionProbeIndices"))
133 params->getBufferParam(programType, "gReflectionProbeIndices", reflectionProbeIndicesParam);
134 }
135
136 params->getParamInfo()->getBinding(
137 programType,
138 GpuPipelineParamInfoBase::ParamType::ParamBlock,
139 "ReflProbeParams",
140 reflProbeParamBindings
141 );
142
143 params->getParamInfo()->getBinding(
144 programType,
145 GpuPipelineParamInfoBase::ParamType::ParamBlock,
146 "ReflectionProbes",
147 reflProbesBinding
148 );
149 }
150
151 ReflProbeParamBuffer::ReflProbeParamBuffer()
152 {
153 buffer = gReflProbeParamsParamDef.createBuffer();
154 }
155
156 void ReflProbeParamBuffer::populate(const Skybox* sky, UINT32 numProbes, const SPtr<Texture>& reflectionCubemaps,
157 bool capturingReflections)
158 {
159 float brightness = 1.0f;
160 UINT32 skyReflectionsAvailable = 0;
161 UINT32 numSkyMips = 0;
162
163 if(sky != nullptr)
164 {
165 SPtr<Texture> filteredReflections = sky->getFilteredRadiance();
166 if (filteredReflections)
167 {
168 numSkyMips = filteredReflections->getProperties().getNumMipmaps() + 1;
169 skyReflectionsAvailable = 1;
170 }
171
172 brightness = sky->getBrightness();
173 }
174
175 gReflProbeParamsParamDef.gSkyCubemapNumMips.set(buffer, numSkyMips);
176 gReflProbeParamsParamDef.gSkyCubemapAvailable.set(buffer, skyReflectionsAvailable);
177 gReflProbeParamsParamDef.gNumProbes.set(buffer, numProbes);
178
179 UINT32 numReflProbeMips = 0;
180 if (reflectionCubemaps != nullptr)
181 numReflProbeMips = reflectionCubemaps->getProperties().getNumMipmaps() + 1;
182
183 gReflProbeParamsParamDef.gReflCubemapNumMips.set(buffer, numReflProbeMips);
184 gReflProbeParamsParamDef.gUseReflectionMaps.set(buffer, capturingReflections ? 0 : 1);
185 gReflProbeParamsParamDef.gSkyBrightness.set(buffer, brightness);
186 }
187
188 ReflProbesParamDef gReflProbesParamDef;
189}}
190