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