Line data Source code
1 : /**
2 : * @file radiancehints.cpp
3 : * @brief radiance hints global illumination
4 : *
5 : * Libprimis supports global illumination via the Radiance Hints algorithm. This
6 : * global illumination is rendered using a reflective shadow map mapped from the
7 : * sun's location.
8 : *
9 : * For performance reasons, the radiance hints algorithm is only run on the global
10 : * sunlight. Running radiance hints on point lights would require complex, expensive
11 : * shadowmapping similar to standard lighting, and not perform particularly well.
12 : *
13 : * By only allowing the sunlight to be lit, Libprimis' global illumination only
14 : * has to worry about a single RSM (reflective shadow map) rather than 6 sided cube
15 : * maps (as point lights would require).
16 : */
17 : #include "../libprimis-headers/cube.h"
18 : #include "../../shared/geomexts.h"
19 : #include "../../shared/glemu.h"
20 : #include "../../shared/glexts.h"
21 :
22 : #include "csm.h"
23 : #include "hdr.h"
24 : #include "octarender.h"
25 : #include "radiancehints.h"
26 : #include "rendergl.h"
27 : #include "renderlights.h"
28 : #include "rendermodel.h"
29 : #include "rendertimers.h"
30 : #include "renderva.h"
31 : #include "renderwindow.h"
32 : #include "shader.h"
33 : #include "shaderparam.h"
34 : #include "texture.h"
35 :
36 : #include "interface/control.h"
37 :
38 : #include "world/light.h"
39 : #include "world/world.h"
40 :
41 : std::array<GLuint, 8> rhtex = { 0, 0, 0, 0, 0, 0, 0, 0 };
42 : GLuint rhfbo = 0;
43 : constexpr int rhmaxgrid = 64; //subdivision count for radiance hints
44 :
45 : //radiance hints (global illumination) vars
46 0 : VARF(rhsplits, 1, 2, rhmaxsplits, { cleardeferredlightshaders(); cleanupradiancehints(); }); //`r`adiance `h`ints `splits`: number of radiance hints subdivisions
47 :
48 : //distance at which to render global illumination in cubits
49 0 : VARFR(gidist, 0, 384, 1024,
50 : {
51 : clearradiancehintscache();
52 : cleardeferredlightshaders();
53 : if(!gidist)
54 : {
55 : cleanupradiancehints();
56 : }
57 : });
58 :
59 0 : FVARFR(giscale, 0, 1.5f, 1e3f,
60 : {
61 : cleardeferredlightshaders();
62 : if(!giscale)
63 : {
64 : cleanupradiancehints();
65 : }
66 : }); //`g`lobal `i`llumination `scale`
67 :
68 : FVARR(giaoscale, 0, 3, 1e3f); //`g`lobal `i`llumination `a`mbient `o`cclusion `scale`: scale of ambient occlusion (corner darkening) on globally illuminated surfaces
69 0 : VARFP(gi, 0, 1, 1, { cleardeferredlightshaders(); cleanupradiancehints(); }); //`g`lobal `i`llumination toggle: 0 disables global illumination
70 :
71 : //debugrsm/rh used extern in renderlights
72 : VAR(debugrsm, 0, 0, 2); //displays the `r`adiance hints `s`hadow `m`ap in the bottom right of the screen; 1 for view from sun pos, 2 for view from sun pos, normal map
73 : VAR(debugrh, -1, 0, rhmaxsplits*(rhmaxgrid + 2));
74 : VAR(rsmcull, 0, 1, 1); //`r`eflective `s`hadow `m`ap `cull`ing
75 :
76 : ReflectiveShadowMap rsm;
77 : RadianceHints rh;
78 : Shader *rsmworldshader = nullptr;
79 :
80 : namespace //internal functionality
81 : {
82 0 : VARF(rhrect, 0, 0, 1, cleanupradiancehints());
83 0 : VARF(rhborder, 0, 1, 1, cleanupradiancehints());
84 0 : VARF(rsmsize, 64, 512, 2048, cleanupradiancehints()); //`r`eflective `s`hadow `m`ap `size`: resolution (squared) of global illumination
85 0 : VARF(rhnearplane, 1, 1, 16, clearradiancehintscache()); //`r`adiance `h`ints `near plane`: distance in gridpower 0 cubes before global illumination gets rendered
86 0 : VARF(rhfarplane, 64, 1024, 16384, clearradiancehintscache()); //`r`adiance `h`ints `far plane`: distance in gridpower 0 cubes whereafter global illumination no longer gets calculated
87 0 : FVARF(rsmpradiustweak, 1e-3f, 1, 1e3f, clearradiancehintscache()); //`r`eflective `s`hadow `m`ap `p`robe `radius tweak`
88 0 : FVARF(rhpradiustweak, 1e-3f, 1, 1e3f, clearradiancehintscache()); //`r`adiance `h`ints `p`robe `radius tweak`
89 0 : FVARF(rsmdepthrange, 0, 1024, 1e6f, clearradiancehintscache()); //`r`eflective `s`hadow `m`ap `depth range`
90 0 : FVARF(rsmdepthmargin, 0, 0.1f, 1e3f, clearradiancehintscache()); //`r`eflective `s`hadow `m`ap `depth margin`
91 0 : VARFP(rhprec, 0, 0, 1, cleanupradiancehints()); //`r`adiance `h`ints `prec`ision: toggles between rgba16 or rgba8 map for radiance hints
92 0 : VARFP(rsmprec, 0, 0, 3, cleanupradiancehints()); //`r`eflective `s`hadow `m`ap `prec`ision: toggles the rsm bit depth between rgb8 (0,1) , r11g11b10 (rgb 32bit) (2), or rgb16 (3)
93 0 : VARFP(rsmdepthprec, 0, 0, 2, cleanupradiancehints()); //`r`eflective `s`hadow `m`ap `depth` `prec`ision: toggles the rsm depth map (buffer) between 16b, 24b, or 32b
94 : FVAR(rhnudge, 0, 0.5f, 4); //`r`adiance `h`ints `nudge`: (minor) factor for rsmsplits offset
95 0 : FVARF(rhworldbias, 0, 0.5f, 10, clearradiancehintscache()); //`r`adiance `h`ints `worldbias`: (minor) factor for radiance hints nudge
96 0 : FVARF(rhsplitweight, 0.20f, 0.6f, 0.95f, clearradiancehintscache()); //`r`adiance `h`ints `split weight`
97 0 : VARF(rhgrid, 3, 27, rhmaxgrid, cleanupradiancehints()); //`r`adiance `h`ints `grid`: subdivisions for the radiance hints to calculate
98 0 : FVARF(rsmspread, 0, 0.35f, 1, clearradiancehintscache()); //smoothness of `r`adiance hints `s`hadow `m`ap: higher is more blurred
99 : VAR(rhclipgrid, 0, 1, 1); //`r`adiance `h`ints `clip` `grid`: determines whether the radiance hints clips to grid
100 0 : VARF(rhcache, 0, 1, 1, cleanupradiancehints()); //`r`adiance `h`ints `cache`: determines whether to create cache textures and use the cache shader
101 0 : VARF(rhforce, 0, 0, 1, cleanupradiancehints());
102 0 : VARFP(rhtaps, 0, 20, 32, cleanupradiancehints()); //`r`adiance `h`ints `taps`: number of sample points for global illumination
103 : VAR(rhdyntex, 0, 0, 1); //`r`adiance `h`ints `dyn`amic `tex`tures
104 : VAR(rhdynmm, 0, 0, 1); //`r`adiance `h`ints `dyn`amic `m`ap `m`odels
105 :
106 : uint rhclearmasks[2][rhmaxsplits][(rhmaxgrid+2+31)/32];
107 : //reflective shadow map buffers, rendered from sun location
108 : GLuint rsmdepthtex = 0,
109 : rsmcolortex = 0,
110 : rsmnormaltex = 0,
111 : rsmfbo = 0;
112 : std::array<GLuint, 4> rhrb = {0, 0, 0, 0};
113 :
114 : Shader *radiancehintsshader = nullptr;
115 :
116 0 : void loadrhshaders()
117 : {
118 0 : if(rhborder)
119 : {
120 0 : useshaderbyname("radiancehintsborder");
121 : }
122 0 : if(rhcache)
123 : {
124 0 : useshaderbyname("radiancehintscached");
125 : }
126 0 : useshaderbyname("radiancehintsdisable");
127 0 : std::string name = std::string("radiancehints").append(std::to_string(rhtaps));
128 0 : radiancehintsshader = generateshader(name, "radiancehintsshader %d", rhtaps);
129 0 : rsmworldshader = useshaderbyname("rsmworld");
130 0 : useshaderbyname("rsmsky");
131 0 : }
132 :
133 0 : void clearrhshaders()
134 : {
135 0 : radiancehintsshader = nullptr;
136 0 : rsmworldshader = nullptr;
137 0 : }
138 :
139 : //defines a rectangle with corners at x1...y2
140 0 : void rhquad(float x1, float y1, float x2, float y2, float tx1, float ty1, float tx2, float ty2, float tz)
141 : {
142 0 : gle::begin(GL_TRIANGLE_STRIP);
143 0 : gle::attribf(x2, y1); gle::attribf(tx2, ty1, tz);
144 0 : gle::attribf(x1, y1); gle::attribf(tx1, ty1, tz);
145 0 : gle::attribf(x2, y2); gle::attribf(tx2, ty2, tz);
146 0 : gle::attribf(x1, y2); gle::attribf(tx1, ty2, tz);
147 0 : gle::end();
148 0 : }
149 :
150 0 : void rhquad(float dx1, float dy1, float dx2, float dy2, float dtx1, float dty1, float dtx2, float dty2, float dtz,
151 : float px1, float py1, float px2, float py2, float ptx1, float pty1, float ptx2, float pty2, float ptz)
152 : {
153 0 : gle::begin(GL_TRIANGLE_STRIP);
154 0 : gle::attribf(dx2, dy1); gle::attribf(dtx2, dty1, dtz);
155 0 : gle::attribf(px2, py1); gle::attribf(ptx2, pty1, ptz);
156 :
157 0 : gle::attribf(dx1, dy1); gle::attribf(dtx1, dty1, dtz);
158 0 : gle::attribf(px1, py1); gle::attribf(ptx1, pty1, ptz);
159 :
160 0 : gle::attribf(dx1, dy2); gle::attribf(dtx1, dty2, dtz);
161 0 : gle::attribf(px1, py2); gle::attribf(ptx1, pty2, ptz);
162 :
163 0 : gle::attribf(dx2, dy2); gle::attribf(dtx2, dty2, dtz);
164 0 : gle::attribf(px2, py2); gle::attribf(ptx2, pty2, ptz);
165 :
166 0 : gle::attribf(dx2, dy1); gle::attribf(dtx2, dty1, dtz);
167 0 : gle::attribf(px2, py1); gle::attribf(ptx2, pty1, ptz);
168 0 : gle::end();
169 0 : }
170 : }
171 :
172 : //externally relevant functionality
173 :
174 0 : void viewrsm()
175 : {
176 0 : int w = std::min(hudw(), hudh())/2,
177 0 : h = (w*hudh())/hudw(),
178 0 : x = hudw()-w,
179 0 : y = hudh()-h;
180 0 : SETSHADER(hudrect);
181 0 : gle::colorf(1, 1, 1);
182 0 : glBindTexture(GL_TEXTURE_RECTANGLE, debugrsm == 2 ? rsmnormaltex : rsmcolortex);
183 0 : debugquad(x, y, w, h, 0, 0, rsmsize, rsmsize);
184 0 : }
185 :
186 0 : void setupradiancehints()
187 : {
188 0 : GLenum rhformat = rhprec >= 1 ? GL_RGBA16F : GL_RGBA8;
189 0 : for(int i = 0; i < (!rhrect && rhcache ? 8 : 4); ++i)
190 : {
191 0 : if(!rhtex[i])
192 : {
193 0 : glGenTextures(1, &rhtex[i]);
194 : }
195 0 : create3dtexture(rhtex[i], rhgrid+2*rhborder, rhgrid+2*rhborder, (rhgrid+2*rhborder)*rhsplits, nullptr, 7, 1, rhformat);
196 0 : if(rhborder)
197 : {
198 0 : glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
199 0 : glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
200 0 : glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
201 0 : std::array<GLfloat, 4> border = { 0.5f, 0.5f, 0.5f, 0 };
202 0 : glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, border.data());
203 : }
204 : }
205 0 : if(!rhfbo)
206 : {
207 0 : glGenFramebuffers(1, &rhfbo);
208 : }
209 0 : glBindFramebuffer(GL_FRAMEBUFFER, rhfbo);
210 :
211 0 : if(rhrect)
212 : {
213 0 : for(size_t i = 0; i < rhrb.size(); ++i)
214 : {
215 0 : if(!rhrb[i])
216 : {
217 0 : glGenRenderbuffers(1, &rhrb[i]);
218 : }
219 0 : glBindRenderbuffer(GL_RENDERBUFFER, rhrb[i]);
220 0 : glRenderbufferStorage(GL_RENDERBUFFER, rhformat, (rhgrid + 2*rhborder)*(rhgrid + 2*rhborder), (rhgrid + 2*rhborder)*rhsplits);
221 0 : glBindRenderbuffer(GL_RENDERBUFFER, 0);
222 0 : glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, rhrb[i]);
223 : }
224 : }
225 : else
226 : {
227 0 : for(int i = 0; i < 4; ++i)
228 : {
229 0 : glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_3D, rhtex[i], 0, 0);
230 : }
231 : }
232 :
233 : static const std::array<GLenum, 4> drawbufs =
234 : {
235 : GL_COLOR_ATTACHMENT0,
236 : GL_COLOR_ATTACHMENT1,
237 : GL_COLOR_ATTACHMENT2,
238 : GL_COLOR_ATTACHMENT3
239 : };
240 0 : glDrawBuffers(4, drawbufs.data());
241 :
242 0 : if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
243 : {
244 0 : fatal("failed allocating radiance hints buffer!");
245 : }
246 :
247 0 : if(!rsmdepthtex)
248 : {
249 0 : glGenTextures(1, &rsmdepthtex);
250 : }
251 0 : if(!rsmcolortex)
252 : {
253 0 : glGenTextures(1, &rsmcolortex);
254 : }
255 0 : if(!rsmnormaltex)
256 : {
257 0 : glGenTextures(1, &rsmnormaltex);
258 : }
259 0 : if(!rsmfbo)
260 : {
261 0 : glGenFramebuffers(1, &rsmfbo);
262 : }
263 :
264 0 : glBindFramebuffer(GL_FRAMEBUFFER, rsmfbo);
265 0 : GLenum rsmformat = gethdrformat(rsmprec, GL_RGBA8);
266 :
267 0 : createtexture(rsmdepthtex, rsmsize, rsmsize, nullptr, 3, 0, rsmdepthprec > 1 ? GL_DEPTH_COMPONENT32 : (rsmdepthprec ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16), GL_TEXTURE_RECTANGLE);
268 0 : createtexture(rsmcolortex, rsmsize, rsmsize, nullptr, 3, 0, rsmformat, GL_TEXTURE_RECTANGLE);
269 0 : createtexture(rsmnormaltex, rsmsize, rsmsize, nullptr, 3, 0, rsmformat, GL_TEXTURE_RECTANGLE);
270 :
271 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, rsmdepthtex, 0);
272 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, rsmcolortex, 0);
273 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, rsmnormaltex, 0);
274 :
275 0 : glDrawBuffers(2, drawbufs.data());
276 :
277 0 : if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
278 : {
279 0 : fatal("failed allocating RSM buffer!");
280 : }
281 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
282 0 : loadrhshaders();
283 0 : clearradiancehintscache();
284 0 : }
285 :
286 0 : void cleanupradiancehints()
287 : {
288 0 : clearradiancehintscache();
289 :
290 0 : for(GLuint &i : rhtex)
291 : {
292 0 : if(i)
293 : {
294 0 : glDeleteTextures(1, &i);
295 0 : i = 0;
296 : }
297 : }
298 0 : for(GLuint &i : rhrb)
299 : {
300 0 : if(i)
301 : {
302 0 : glDeleteRenderbuffers(1, &i);
303 0 : i = 0;
304 : }
305 : }
306 0 : if(rhfbo)
307 : {
308 0 : glDeleteFramebuffers(1, &rhfbo);
309 0 : rhfbo = 0;
310 : }
311 0 : if(rsmdepthtex)
312 : {
313 0 : glDeleteTextures(1, &rsmdepthtex);
314 0 : rsmdepthtex = 0;
315 : }
316 0 : if(rsmcolortex)
317 : {
318 0 : glDeleteTextures(1, &rsmcolortex);
319 0 : rsmcolortex = 0;
320 : }
321 0 : if(rsmnormaltex)
322 : {
323 0 : glDeleteTextures(1, &rsmnormaltex);
324 0 : rsmnormaltex = 0;
325 : }
326 0 : if(rsmfbo)
327 : {
328 0 : glDeleteFramebuffers(1, &rsmfbo);
329 0 : rsmfbo = 0;
330 : }
331 :
332 0 : clearrhshaders();
333 0 : }
334 :
335 0 : void viewrh()
336 : {
337 0 : int w = std::min(hudw(), hudh())/2,
338 0 : h = (w*hudh())/hudw(),
339 0 : x = hudw()-w,
340 0 : y = hudh()-h;
341 0 : gle::colorf(1, 1, 1);
342 0 : if(debugrh < 0 && rhrect)
343 : {
344 0 : SETSHADER(hudrect);
345 0 : glBindTexture(GL_TEXTURE_RECTANGLE, rhtex[5]);
346 0 : float tw = (rhgrid+2*rhborder)*(rhgrid+2*rhborder),
347 0 : th = (rhgrid+2*rhborder)*rhsplits;
348 0 : gle::defvertex(2);
349 0 : gle::deftexcoord0(2);
350 0 : gle::begin(GL_TRIANGLE_STRIP);
351 0 : gle::attribf(x, y); gle::attribf(0, 0);
352 0 : gle::attribf(x+w, y); gle::attribf(tw, 0);
353 0 : gle::attribf(x, y+h); gle::attribf(0, th);
354 0 : gle::attribf(x+w, y+h); gle::attribf(tw, th);
355 0 : gle::end();
356 0 : }
357 : else
358 : {
359 0 : SETSHADER(hud3d);
360 0 : glBindTexture(GL_TEXTURE_3D, rhtex[1]);
361 0 : float z = (std::max(debugrh, 1)-1+0.5f)/static_cast<float>((rhgrid+2*rhborder)*rhsplits);
362 0 : gle::defvertex(2);
363 0 : gle::deftexcoord0(3);
364 0 : gle::begin(GL_TRIANGLE_STRIP);
365 0 : gle::attribf(x, y); gle::attribf(0, 0, z);
366 0 : gle::attribf(x+w, y); gle::attribf(1, 0, z);
367 0 : gle::attribf(x, y+h); gle::attribf(0, 1, z);
368 0 : gle::attribf(x+w, y+h); gle::attribf(1, 1, z);
369 0 : gle::end();
370 : }
371 0 : }
372 :
373 1 : void clearradiancehintscache()
374 : {
375 1 : rh.clearcache();
376 1 : std::memset(rhclearmasks, 0, sizeof(rhclearmasks));
377 1 : }
378 :
379 0 : bool useradiancehints()
380 : {
381 0 : return !sunlight.iszero() && csm.getcsmproperty(cascadedshadowmap::ShadowMap) && gi && giscale && gidist;
382 : }
383 :
384 : //============================= radiance hints object ==========================//
385 :
386 0 : void RadianceHints::updatesplitdist()
387 : {
388 0 : const float lambda = rhsplitweight,
389 0 : nd = rhnearplane,
390 0 : fd = rhfarplane,
391 0 : ratio = fd/nd;
392 0 : splits[0].nearplane = nd;
393 0 : for(int i = 1; i < rhsplits; ++i)
394 : {
395 0 : const float si = i / static_cast<float>(rhsplits);
396 0 : splits[i].nearplane = lambda*(nd*std::pow(ratio, si)) + (1-lambda)*(nd + (fd - nd)*si);
397 0 : splits[i-1].farplane = splits[i].nearplane * 1.005f;
398 : }
399 0 : splits[rhsplits-1].farplane = fd;
400 0 : }
401 :
402 0 : void RadianceHints::setup()
403 : {
404 0 : updatesplitdist();
405 :
406 0 : for(int i = 0; i < rhsplits; ++i)
407 : {
408 0 : SplitInfo &split = splits[i];
409 :
410 0 : vec c;
411 0 : const float radius = calcfrustumboundsphere(split.nearplane, split.farplane, camera1->o, camdir(), c);
412 :
413 : // compute the projected bounding box of the sphere
414 0 : const float pradius = std::ceil(radius * rhpradiustweak),
415 0 : step = (2*pradius) / rhgrid;
416 0 : vec offset = vec(c).sub(pradius).div(step);
417 0 : offset.x = std::floor(offset.x);
418 0 : offset.y = std::floor(offset.y);
419 0 : offset.z = std::floor(offset.z);
420 0 : split.cached = split.bounds == pradius ? split.center : vec(-1e16f, -1e16f, -1e16f);
421 0 : split.center = vec(offset).mul(step).add(pradius);
422 0 : split.bounds = pradius;
423 :
424 : // modify mvp with a scale and offset
425 : // now compute the update model view matrix for this split
426 0 : split.scale = vec(1/(step*(rhgrid+2*rhborder)), 1/(step*(rhgrid+2*rhborder)), 1/(step*(rhgrid+2*rhborder)*rhsplits));
427 0 : split.offset = vec(-(offset.x-rhborder)/(rhgrid+2*rhborder), -(offset.y-rhborder)/(rhgrid+2*rhborder), (i - (offset.z-rhborder)/(rhgrid+2*rhborder))/static_cast<float>(rhsplits));
428 : }
429 0 : }
430 :
431 0 : void RadianceHints::bindparams() const
432 : {
433 0 : float step = 2*splits[0].bounds/rhgrid;
434 0 : GLOBALPARAMF(rhnudge, rhnudge*step);
435 0 : static GlobalShaderParam rhtc("rhtc");
436 0 : vec4<float> *rhtcv = rhtc.reserve<vec4<float>>();
437 0 : for(int i = 0; i < rhsplits; ++i)
438 : {
439 0 : const SplitInfo &split = splits[i];
440 0 : rhtcv[i] = vec4<float>(vec(split.center).mul(-split.scale.x), split.scale.x);//split.bounds*(1 + rhborder*2*0.5f/rhgrid));
441 : }
442 0 : GLOBALPARAMF(rhbounds, 0.5f*(rhgrid + rhborder)/static_cast<float>(rhgrid + 2*rhborder));
443 0 : }
444 :
445 1 : void RadianceHints::clearcache()
446 : {
447 5 : for(SplitInfo &i : splits)
448 : {
449 4 : i.clearcache();
450 : }
451 1 : }
452 :
453 0 : bool RadianceHints::allcached() const
454 : {
455 0 : for(const SplitInfo &i : splits)
456 : {
457 0 : if(i.cached != i.center)
458 : {
459 0 : return false;
460 : }
461 : }
462 0 : return true;
463 : }
464 :
465 0 : void RadianceHints::rotatedynlimits()
466 : {
467 0 : prevdynmin = dynmin;
468 0 : prevdynmax = dynmax;
469 0 : }
470 :
471 0 : bool RadianceHints::checkprevbounds() const
472 : {
473 0 : return prevdynmin.z < rh.prevdynmax.z;
474 : }
475 :
476 0 : static void bindslice(int sx, int sy, int sw, int sh, int i, int j)
477 : {
478 0 : if(rhrect)
479 : {
480 0 : glViewport(sx, sy, sw, sh);
481 0 : glScissor(sx, sy, sw, sh);
482 : }
483 : else
484 : {
485 0 : glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, rhtex[0], 0, i*sh + j);
486 0 : glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, rhtex[1], 0, i*sh + j);
487 0 : glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, rhtex[2], 0, i*sh + j);
488 0 : glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, rhtex[3], 0, i*sh + j);
489 : }
490 0 : }
491 :
492 0 : void RadianceHints::renderslices()
493 : {
494 0 : int sw = rhgrid+2*rhborder,
495 0 : sh = rhgrid+2*rhborder;
496 0 : glBindFramebuffer(GL_FRAMEBUFFER, rhfbo);
497 0 : if(!rhrect)
498 : {
499 0 : glViewport(0, 0, sw, sh);
500 0 : if(rhcache)
501 : {
502 0 : for(size_t i = 0; i < rhtex.size()/2; ++i)
503 : {
504 0 : std::swap(rhtex[i], rhtex[i+rhtex.size()/2]);
505 : }
506 : uint clearmasks[rhmaxsplits][(rhmaxgrid+2+31)/32];
507 0 : std::memcpy(clearmasks, rhclearmasks[0], sizeof(clearmasks));
508 0 : std::memcpy(rhclearmasks[0], rhclearmasks[1], sizeof(clearmasks));
509 0 : std::memcpy(rhclearmasks[1], clearmasks, sizeof(clearmasks));
510 : }
511 : }
512 :
513 0 : GLOBALPARAMF(rhatten, 1.0f/(gidist*gidist));
514 0 : GLOBALPARAMF(rsmspread, gidist*rsmspread*rsm.scale.x, gidist*rsmspread*rsm.scale.y);
515 0 : GLOBALPARAMF(rhaothreshold, splits[0].bounds/rhgrid);
516 0 : GLOBALPARAMF(rhaoatten, 1.0f/(gidist*rsmspread));
517 0 : GLOBALPARAMF(rhaoheight, gidist*rsmspread);
518 :
519 0 : matrix4 rsmtcmatrix;
520 0 : rsmtcmatrix.identity();
521 0 : rsmtcmatrix.settranslation(rsm.offset);
522 0 : rsmtcmatrix.setscale(rsm.scale);
523 0 : rsmtcmatrix.mul(rsm.model);
524 0 : GLOBALPARAM(rsmtcmatrix, rsmtcmatrix);
525 :
526 0 : matrix4 rsmworldmatrix;
527 0 : rsmworldmatrix.invert(rsmtcmatrix);
528 0 : GLOBALPARAM(rsmworldmatrix, rsmworldmatrix);
529 :
530 0 : glBindTexture(GL_TEXTURE_RECTANGLE, rsmdepthtex);
531 0 : glActiveTexture(GL_TEXTURE1);
532 0 : glBindTexture(GL_TEXTURE_RECTANGLE, rsmcolortex);
533 0 : glActiveTexture(GL_TEXTURE2);
534 0 : glBindTexture(GL_TEXTURE_RECTANGLE, rsmnormaltex);
535 0 : if(rhborder)
536 : {
537 0 : for(size_t i = 0; i < rhtex.size()/2; ++i)
538 : {
539 0 : glActiveTexture(GL_TEXTURE3 + i);
540 0 : glBindTexture(GL_TEXTURE_3D, rhtex[i]);
541 : }
542 : }
543 0 : if(rhcache)
544 : {
545 0 : for(size_t i = 0; i < rhtex.size()/2; ++i)
546 : {
547 0 : glActiveTexture(GL_TEXTURE7 + i);
548 0 : glBindTexture(GL_TEXTURE_3D, rhtex[rhrect ? i : rhtex.size()/2+i]);
549 : }
550 : }
551 0 : glActiveTexture(GL_TEXTURE0);
552 0 : glClearColor(0.5f, 0.5f, 0.5f, 0);
553 0 : if(rhrect)
554 : {
555 0 : glEnable(GL_SCISSOR_TEST);
556 : }
557 0 : gle::defvertex(2);
558 0 : gle::deftexcoord0(3);
559 :
560 0 : bool prevcached = true;
561 0 : int cx = -1,
562 0 : cy = -1;
563 0 : for(int i = rhsplits; --i >= 0;) //reverse iterate through rhsplits
564 : {
565 0 : SplitInfo &split = splits[i];
566 0 : float cellradius = split.bounds/rhgrid,
567 0 : step = 2*cellradius,
568 0 : nudge = rhnudge*2*splits[0].bounds/rhgrid + rhworldbias*step;
569 0 : vec cmin, cmax,
570 0 : dmin( 1e16f, 1e16f, 1e16f),
571 0 : dmax(-1e16f, -1e16f, -1e16f),
572 0 : bmin( 1e16f, 1e16f, 1e16f),
573 0 : bmax(-1e16f, -1e16f, -1e16f);
574 0 : for(int k = 0; k < 3; ++k)
575 : {
576 0 : cmin[k] = std::floor((worldmin[k] - nudge - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
577 0 : cmax[k] = std::ceil((worldmax[k] + nudge - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
578 : }
579 0 : if(prevdynmin.z < prevdynmax.z)
580 : {
581 0 : for(int k = 0; k < 3; ++k)
582 : {
583 0 : dmin[k] = std::min(dmin[k], static_cast<float>(std::floor((prevdynmin[k] - gidist - cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
584 0 : dmax[k] = std::max(dmax[k], static_cast<float>(std::ceil((prevdynmax[k] + gidist + cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
585 : }
586 : }
587 0 : if(dynmin.z < dynmax.z)
588 : {
589 0 : for(int k = 0; k < 3; ++k)
590 : {
591 0 : dmin[k] = std::min(dmin[k], static_cast<float>(std::floor((dynmin[k] - gidist - cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
592 0 : dmax[k] = std::max(dmax[k], static_cast<float>(std::ceil((dynmax[k] + gidist + cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
593 : }
594 : }
595 0 : if((rhrect || !rhcache || hasCI) && split.cached == split.center && (!rhborder || prevcached) && !rhforce &&
596 0 : (dmin.x > split.center.x + split.bounds || dmax.x < split.center.x - split.bounds ||
597 0 : dmin.y > split.center.y + split.bounds || dmax.y < split.center.y - split.bounds ||
598 0 : dmin.z > split.center.z + split.bounds || dmax.z < split.center.z - split.bounds))
599 : {
600 0 : if(rhrect || !rhcache || split.copied)
601 : {
602 0 : continue;
603 : }
604 0 : split.copied = true;
605 0 : for(size_t k = 0; k < rhtex.size()/2; ++k)
606 : {
607 0 : glCopyImageSubData_(rhtex[rhtex.size()/2+k], GL_TEXTURE_3D, 0, 0, 0, i*sh, rhtex[k], GL_TEXTURE_3D, 0, 0, 0, i*sh, sw, sh, sh);
608 : }
609 0 : continue;
610 0 : }
611 :
612 0 : prevcached = false;
613 0 : split.copied = false;
614 :
615 0 : GLOBALPARAM(rhcenter, split.center);
616 0 : GLOBALPARAMF(rhbounds, split.bounds);
617 0 : GLOBALPARAMF(rhspread, cellradius);
618 :
619 0 : if(rhborder && i + 1 < rhsplits)
620 : {
621 0 : GLOBALPARAMF(bordercenter, 0.5f, 0.5f, static_cast<float>(i+1 + 0.5f)/rhsplits);
622 0 : GLOBALPARAMF(borderrange, 0.5f - 0.5f/(rhgrid+2), 0.5f - 0.5f/(rhgrid+2), (0.5f - 0.5f/(rhgrid+2))/rhsplits);
623 0 : GLOBALPARAMF(borderscale, rhgrid+2, rhgrid+2, (rhgrid+2)*rhsplits);
624 :
625 0 : SplitInfo &next = splits[i+1];
626 0 : for(int k = 0; k < 3; ++k)
627 : {
628 0 : bmin[k] = std::floor((std::max(static_cast<float>(worldmin[k] - nudge), next.center[k] - next.bounds) - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
629 0 : bmax[k] = std::ceil((std::min(static_cast<float>(worldmax[k] + nudge), next.center[k] + next.bounds) - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
630 : }
631 : }
632 :
633 : std::array<uint, (rhmaxgrid+2+31)/32> clearmasks;
634 0 : std::memset(clearmasks.data(), 0xFF, clearmasks.size()*sizeof(uint));
635 :
636 0 : int sy = rhrect ? i*sh : 0;
637 0 : for(int j = sh; --j >= 0;) //note reverse iteration
638 : {
639 0 : int sx = rhrect ? j*sw : 0;
640 :
641 0 : float x1 = split.center.x - split.bounds,
642 0 : x2 = split.center.x + split.bounds,
643 0 : y1 = split.center.y - split.bounds,
644 0 : y2 = split.center.y + split.bounds,
645 0 : z = split.center.z - split.bounds + (j-rhborder+0.5f)*step,
646 0 : vx1 = -1 + rhborder*2.0f/(rhgrid+2),
647 0 : vx2 = 1 - rhborder*2.0f/(rhgrid+2),
648 0 : vy1 = -1 + rhborder*2.0f/(rhgrid+2),
649 0 : vy2 = 1 - rhborder*2.0f/(rhgrid+2),
650 0 : tx1 = x1,
651 0 : tx2 = x2,
652 0 : ty1 = y1,
653 0 : ty2 = y2;
654 0 : bool clipped = false;
655 :
656 0 : if(rhborder && i + 1 < rhsplits)
657 : {
658 0 : const SplitInfo &next = splits[i+1];
659 0 : float bx1 = x1-step,
660 0 : bx2 = x2+step,
661 0 : by1 = y1-step,
662 0 : by2 = y2+step,
663 0 : bz = z,
664 0 : bvx1 = -1,
665 0 : bvx2 = 1,
666 0 : bvy1 = -1,
667 0 : bvy2 = 1,
668 0 : btx1 = bx1,
669 0 : btx2 = bx2,
670 0 : bty1 = by1,
671 0 : bty2 = by2;
672 :
673 0 : if(rhclipgrid)
674 : {
675 0 : if(bz < bmin.z || bz > bmax.z)
676 : {
677 0 : goto noborder;
678 : }
679 0 : if(bx1 < bmin.x || bx2 > bmax.x || by1 < bmin.y || by2 > bmax.y)
680 : {
681 0 : btx1 = std::max(bx1, bmin.x);
682 0 : btx2 = std::min(bx2, bmax.x);
683 0 : bty1 = std::max(by1, bmin.y);
684 0 : bty2 = std::min(by2, bmax.y);
685 0 : if(btx1 > tx2 || bty1 > bty2)
686 : {
687 0 : goto noborder;
688 : }
689 0 : bvx1 += 2*(btx1 - bx1)/(bx2 - bx1);
690 0 : bvx2 += 2*(btx2 - bx2)/(bx2 - bx1);
691 0 : bvy1 += 2*(bty1 - by1)/(by2 - by1);
692 0 : bvy2 += 2*(bty2 - by2)/(by2 - by1);
693 0 : clipped = true;
694 : }
695 : }
696 0 : btx1 = btx1*next.scale.x + next.offset.x;
697 0 : btx2 = btx2*next.scale.x + next.offset.x;
698 0 : bty1 = bty1*next.scale.y + next.offset.y;
699 0 : bty2 = bty2*next.scale.y + next.offset.y;
700 0 : bz = bz*next.scale.z + next.offset.z;
701 0 : bindslice(sx, sy, sw, sh, i, j);
702 0 : if(clipped)
703 : {
704 0 : glClear(GL_COLOR_BUFFER_BIT);
705 : }
706 0 : SETSHADER(radiancehintsborder);
707 0 : rhquad(bvx1, bvy1, bvx2, bvy2, btx1, bty1, btx2, bty2, bz);
708 0 : clearmasks[j/32] &= ~(1 << (j%32));
709 : }
710 :
711 0 : noborder:
712 0 : if(j < rhborder || j >= rhgrid + rhborder)
713 : {
714 0 : skipped:
715 0 : if(clearmasks[j/32] & (1 << (j%32)) && (!rhrect || cx < 0) && !(rhclearmasks[0][i][j/32] & (1 << (j%32))))
716 : {
717 0 : bindslice(sx, sy, sw, sh, i, j);
718 0 : glClear(GL_COLOR_BUFFER_BIT);
719 0 : cx = sx;
720 0 : cy = sy;
721 : }
722 0 : continue;
723 : }
724 :
725 0 : if(rhclipgrid)
726 : {
727 0 : if(z < cmin.z || z > cmax.z)
728 : {
729 0 : goto skipped;
730 : }
731 0 : if(x1 < cmin.x || x2 > cmax.x || y1 < cmin.y || y2 > cmax.y)
732 : {
733 0 : tx1 = std::max(x1, cmin.x);
734 0 : tx2 = std::min(x2, cmax.x);
735 0 : ty1 = std::max(y1, cmin.y);
736 0 : ty2 = std::min(y2, cmax.y);
737 0 : if(tx1 > tx2 || ty1 > ty2)
738 : {
739 0 : goto skipped;
740 : }
741 0 : vx1 += 2*rhgrid/static_cast<float>(sw)*(tx1 - x1)/(x2 - x1);
742 0 : vx2 += 2*rhgrid/static_cast<float>(sw)*(tx2 - x2)/(x2 - x1);
743 0 : vy1 += 2*rhgrid/static_cast<float>(sh)*(ty1 - y1)/(y2 - y1);
744 0 : vy2 += 2*rhgrid/static_cast<float>(sh)*(ty2 - y2)/(y2 - y1);
745 0 : clipped = true;
746 : }
747 : }
748 0 : if(clearmasks[j/32] & (1 << (j%32)))
749 : {
750 0 : bindslice(sx, sy, sw, sh, i, j);
751 0 : if(clipped || (rhborder && i + 1 >= rhsplits))
752 : {
753 0 : glClear(GL_COLOR_BUFFER_BIT);
754 : }
755 0 : clearmasks[j/32] &= ~(1 << (j%32));
756 : }
757 :
758 0 : if(rhcache && z > split.cached.z - split.bounds && z < split.cached.z + split.bounds)
759 : {
760 0 : float px1 = std::max(tx1, split.cached.x - split.bounds),
761 0 : px2 = std::min(tx2, split.cached.x + split.bounds),
762 0 : py1 = std::max(ty1, split.cached.y - split.bounds),
763 0 : py2 = std::min(ty2, split.cached.y + split.bounds);
764 0 : if(px1 < px2 && py1 < py2)
765 : {
766 0 : float pvx1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(px1 - x1)/(x2 - x1),
767 0 : pvx2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(px2 - x2)/(x2 - x1),
768 0 : pvy1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(py1 - y1)/(y2 - y1),
769 0 : pvy2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(py2 - y2)/(y2 - y1),
770 0 : ptx1 = (px1 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
771 0 : ptx2 = (px2 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
772 0 : pty1 = (py1 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
773 0 : pty2 = (py2 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
774 0 : pz = (z + split.center.z - split.cached.z)*split.scale.z + split.offset.z;
775 0 : if(px1 != tx1 || px2 != tx2 || py1 != ty1 || py2 != ty2)
776 : {
777 0 : radiancehintsshader->set();
778 0 : rhquad(pvx1, pvy1, pvx2, pvy2, px1, py1, px2, py2, z,
779 : vx1, vy1, vx2, vy2, tx1, ty1, tx2, ty2, z);
780 : }
781 0 : if(z > dmin.z && z < dmax.z)
782 : {
783 0 : float dx1 = std::max(px1, dmin.x),
784 0 : dx2 = std::min(px2, dmax.x),
785 0 : dy1 = std::max(py1, dmin.y),
786 0 : dy2 = std::min(py2, dmax.y);
787 0 : if(dx1 < dx2 && dy1 < dy2)
788 : {
789 0 : float dvx1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(dx1 - x1)/(x2 - x1),
790 0 : dvx2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(dx2 - x2)/(x2 - x1),
791 0 : dvy1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(dy1 - y1)/(y2 - y1),
792 0 : dvy2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(dy2 - y2)/(y2 - y1),
793 0 : dtx1 = (dx1 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
794 0 : dtx2 = (dx2 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
795 0 : dty1 = (dy1 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
796 0 : dty2 = (dy2 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
797 0 : dz = (z + split.center.z - split.cached.z)*split.scale.z + split.offset.z;
798 0 : if(dx1 != px1 || dx2 != px2 || dy1 != py1 || dy2 != py2)
799 : {
800 0 : SETSHADER(radiancehintscached);
801 0 : rhquad(dvx1, dvy1, dvx2, dvy2, dtx1, dty1, dtx2, dty2, dz,
802 : pvx1, pvy1, pvx2, pvy2, ptx1, pty1, ptx2, pty2, pz);
803 : }
804 0 : radiancehintsshader->set();
805 0 : rhquad(dvx1, dvy1, dvx2, dvy2, dx1, dy1, dx2, dy2, z);
806 0 : goto maskslice;
807 : }
808 : }
809 0 : SETSHADER(radiancehintscached);
810 0 : rhquad(pvx1, pvy1, pvx2, pvy2, ptx1, pty1, ptx2, pty2, pz);
811 0 : goto maskslice;
812 : }
813 : }
814 0 : radiancehintsshader->set();
815 0 : rhquad(vx1, vy1, vx2, vy2, tx1, ty1, tx2, ty2, z);
816 0 : maskslice:
817 0 : if(i)
818 : {
819 0 : continue;
820 : }
821 0 : if(gle::attribbuf.empty())
822 : {
823 0 : continue;
824 : }
825 0 : SETSHADER(radiancehintsdisable);
826 0 : if(rhborder)
827 : {
828 0 : glScissor(sx + rhborder, sy + rhborder, sw - 2*rhborder, sh - 2*rhborder);
829 0 : if(!rhrect)
830 : {
831 0 : glEnable(GL_SCISSOR_TEST);
832 : }
833 : }
834 0 : gle::defvertex(2);
835 0 : gle::begin(GL_TRIANGLES);
836 0 : gle::end();
837 0 : if(rhborder && !rhrect)
838 : {
839 0 : glDisable(GL_SCISSOR_TEST);
840 : }
841 0 : gle::defvertex(2);
842 0 : gle::deftexcoord0(3);
843 : }
844 0 : if(rhrect)
845 : {
846 0 : for(int k = 0; k < 4; ++k)
847 : {
848 0 : glReadBuffer(GL_COLOR_ATTACHMENT0+k);
849 0 : glBindTexture(GL_TEXTURE_3D, rhtex[k]);
850 0 : for(int j = 0; j < sh; ++j)
851 : {
852 0 : if(clearmasks[j/32] & (1 << (j%32)))
853 : {
854 0 : if(!(rhclearmasks[0][i][j/32] & (1 << (j%32))))
855 : {
856 0 : glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, sy+j, cx, cy, sw, sh);
857 : }
858 0 : continue;
859 : }
860 0 : glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, sy+j, j*sw, sy, sw, sh);
861 : }
862 : }
863 : }
864 0 : std::memcpy(rhclearmasks[0][i], clearmasks.data(), clearmasks.size()*sizeof(uint));
865 : }
866 0 : if(rhrect)
867 : {
868 0 : glDisable(GL_SCISSOR_TEST);
869 : }
870 0 : }
871 :
872 0 : void GBuffer::renderradiancehints() const
873 : {
874 0 : if(rhinoq && !inoq && shouldworkinoq())
875 : {
876 0 : return;
877 : }
878 0 : if(!useradiancehints())
879 : {
880 0 : return;
881 : }
882 0 : timer *rhcputimer = begintimer("radiance hints", false),
883 0 : *rhtimer = begintimer("radiance hints"); //implicit true
884 :
885 0 : rh.setup();
886 0 : rsm.setup();
887 :
888 0 : shadowmapping = ShadowMap_Reflect;
889 0 : shadowside = 0;
890 0 : shadoworigin = vec(0, 0, 0);
891 0 : shadowdir = rsm.lightview;
892 0 : shadowbias = rsm.lightview.project_bb(worldmin, worldmax);
893 0 : shadowradius = std::fabs(rsm.lightview.project_bb(worldmax, worldmin));
894 :
895 0 : findshadowvas();
896 0 : findshadowmms();
897 :
898 0 : batching::shadowmaskbatchedmodels(false);
899 0 : batchshadowmapmodels();
900 :
901 0 : rh.rotatedynlimits();
902 0 : rh.dynmin = vec(1e16f, 1e16f, 1e16f);
903 0 : rh.dynmax = vec(-1e16f, -1e16f, -1e16f);
904 0 : if(rhdyntex)
905 : {
906 0 : dynamicshadowvabounds(1<<shadowside, rh.dynmin, rh.dynmax);
907 : }
908 0 : if(rhdynmm)
909 : {
910 0 : batching::batcheddynamicmodelbounds(1<<shadowside, rh.dynmin, rh.dynmax);
911 : }
912 0 : if(rhforce || rh.checkprevbounds() || rh.dynmin.z < rh.dynmax.z || !rh.allcached())
913 : {
914 0 : if(inoq)
915 : {
916 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
917 0 : glDepthMask(GL_TRUE);
918 : }
919 0 : glBindFramebuffer(GL_FRAMEBUFFER, rsmfbo);
920 0 : shadowmatrix.mul(rsm.proj, rsm.model);
921 0 : GLOBALPARAM(rsmmatrix, shadowmatrix);
922 0 : GLOBALPARAMF(rsmdir, -rsm.lightview.x, -rsm.lightview.y, -rsm.lightview.z);
923 :
924 0 : glViewport(0, 0, rsmsize, rsmsize);
925 0 : glClearColor(0, 0, 0, 0);
926 0 : glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
927 :
928 0 : renderrsmgeom(rhdyntex!=0);
929 0 : batching::rendershadowmodelbatches(rhdynmm!=0);
930 0 : rh.renderslices();
931 0 : if(inoq)
932 : {
933 0 : glBindFramebuffer(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
934 0 : glViewport(0, 0, vieww, viewh);
935 :
936 0 : glFlush();
937 : }
938 : }
939 :
940 0 : batching::clearbatchedmapmodels();
941 0 : shadowmapping = 0;
942 0 : endtimer(rhtimer);
943 0 : endtimer(rhcputimer);
944 : }
945 :
946 : // ============================ reflective shadow map =========================//
947 : //the reflective shadow map caches the terrain albedo for use by the radiance
948 : //hints algorithm: it needs to know how bright the surfaces the sun is shining on
949 0 : void ReflectiveShadowMap::setup()
950 : {
951 0 : getmodelmatrix();
952 0 : getprojmatrix();
953 0 : gencullplanes();
954 0 : }
955 :
956 0 : void ReflectiveShadowMap::getmodelmatrix()
957 : {
958 0 : model = viewmatrix; //copy global view matrix
959 0 : model.rotate_around_x(sunlightpitch/RAD); //orient camera in same yaw as sunlight
960 0 : model.rotate_around_z((180-sunlightyaw)/RAD); //orient camera in same pitch as sunlight
961 0 : }
962 :
963 0 : void ReflectiveShadowMap::getprojmatrix()
964 : {
965 0 : lightview = vec(sunlightdir).neg();
966 : // find z extent
967 0 : float minz = lightview.project_bb(worldmin, worldmax),
968 0 : maxz = lightview.project_bb(worldmax, worldmin),
969 0 : zmargin = std::max((maxz - minz)*rsmdepthmargin, 0.5f*(rsmdepthrange - (maxz - minz)));
970 0 : minz -= zmargin;
971 0 : maxz += zmargin;
972 0 : vec c;
973 0 : const float radius = calcfrustumboundsphere(rhnearplane, rhfarplane, camera1->o, camdir(), c);
974 : // compute the projected bounding box of the sphere
975 0 : vec tc;
976 0 : model.transform(c, tc);
977 0 : const float pradius = std::ceil((radius + gidist) * rsmpradiustweak),
978 0 : step = (2*pradius) / rsmsize;
979 0 : vec2 tcoff = vec2(tc).sub(pradius).div(step);
980 0 : tcoff.x = std::floor(tcoff.x);
981 0 : tcoff.y = std::floor(tcoff.y);
982 0 : center = vec(vec2(tcoff).mul(step).add(pradius), -0.5f*(minz + maxz));
983 0 : bounds = vec(pradius, pradius, 0.5f*(maxz - minz));
984 :
985 0 : scale = vec(1/step, 1/step, -1/(maxz - minz));
986 0 : offset = vec(-tcoff.x, -tcoff.y, -minz/(maxz - minz));
987 :
988 0 : proj.identity();
989 0 : proj.settranslation(2*offset.x/rsmsize - 1, 2*offset.y/rsmsize - 1, 2*offset.z - 1);
990 0 : proj.setscale(2*scale.x/rsmsize, 2*scale.y/rsmsize, 2*scale.z);
991 0 : }
992 :
993 : //sets the culling plane objects' location within the reflectiveshadowmap object
994 0 : void ReflectiveShadowMap::gencullplanes()
995 : {
996 0 : matrix4 mvp;
997 0 : mvp.mul(proj, model);
998 0 : vec4<float> px = mvp.rowx(),
999 0 : py = mvp.rowy(),
1000 0 : pw = mvp.roww();
1001 0 : cull[0] = plane(vec4<float>(pw).add(px)).normalize(); // left plane
1002 0 : cull[1] = plane(vec4<float>(pw).sub(px)).normalize(); // right plane
1003 0 : cull[2] = plane(vec4<float>(pw).add(py)).normalize(); // bottom plane
1004 0 : cull[3] = plane(vec4<float>(pw).sub(py)).normalize(); // top plane
1005 0 : }
1006 :
1007 : //=========================== end reflective shadow map =======================//
|