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