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