Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added support for spotlights

  • Loading branch information...
commit 64735089b4c4390215c86748b9279feb9a6712a8 1 parent b51f752
@lsalzman authored
View
55 data/glsl.cfg
@@ -451,7 +451,6 @@ bumpvariantshader = [
uniform vec4 texgenscroll;
varying mat3 world;
@(gdepthinterp)
- @(if (btopt "o") [result [uniform vec4 orienttangent, orientbinormal;]])
@(if (|| (btopt "t") (btopt "r")) [result [uniform vec4 camera;]])
@(if (btopt "t") [result [varying vec3 camvects;]])
@(if (btopt "r") [result [varying vec3 camvecw;]])
@@ -476,7 +475,6 @@ bumpvariantshader = [
@(if (btopt "t") [result [camvects = (camera.xyz - gl_Vertex.xyz) * world; ]])
@(if (btopt "r") [result [camvecw = camera.xyz - gl_Vertex.xyz;]])
-
@(if (btopt "G") [result [
pulse = abs(fract(millis.x*pulseglowspeed.x)*2.0 - 1.0);
]])
@@ -1286,7 +1284,8 @@ deferredlightvariantshader = [
deferredlighttype = $arg3
numsplits = (+ $arg4 0)
numlights = (+ $arg5 0)
- baselight = (< $arg2 2)
+ baselight = (< (mod $arg2 4) 2)
+ spotlight = (>= $arg2 4)
variantshader 0 $arg1 $arg2 (? (< $arg2 0) [
void main(void)
{
@@ -1317,7 +1316,14 @@ deferredlightvariantshader = [
@(if $numlights [result [
uniform vec4 lightpos[@@numlights];
uniform vec3 lightcolor[@@numlights];
+ @(if $spotlight [result [
+ uniform vec4 spotparams[@@numlights];
+ ]])
@(if (dlopt "p") [result [
+ @(if $spotlight [result [
+ uniform vec3 spotx[@@numlights];
+ uniform vec3 spoty[@@numlights];
+ ]])
uniform vec4 shadowparams[@@numlights];
uniform vec2 shadowoffset[@@numlights];
]])
@@ -1339,7 +1345,13 @@ deferredlightvariantshader = [
@(gdepthunpackparams)
@(if (dlopt "p") [
- if (dlopt "t") [result [
+ if $spotlight [result [
+ vec3 getspottc(vec3 dir, float spotdist, vec3 spotx, vec3 spoty, vec4 shadowparams, vec2 shadowoffset)
+ {
+ vec2 mparams = shadowparams.xy / spotdist;
+ return vec3(vec2(dot(dir, spotx), dot(dir, spoty))*mparams.x + shadowoffset, mparams.y + shadowparams.w);
+ }
+ ]] [if (dlopt "t") [result [
vec3 getshadowtc(vec3 dir, vec4 shadowparams, vec2 shadowoffset)
{
float top = abs(dir.x+dir.y)+dir.z, bottom = abs(dir.x-dir.y)-dir.z;
@@ -1357,7 +1369,7 @@ deferredlightvariantshader = [
vec2 mparams = shadowparams.xy / m;
return vec3(proj.xy * mparams.x + vec2(proj.w, step(proj.z, 0.0)) * shadowparams.z + shadowoffset, mparams.y + shadowparams.w);
}
- ]]
+ ]]]
])
@(if (|| (dlopt "p") (dlopt "c")) [
@@ -1466,21 +1478,34 @@ deferredlightvariantshader = [
float light@[j]facing = dot(light@[j]dir, normal.xyz);
if(light@[j]dist2 < 1.0 && light@[j]facing < 0.0)
{
- @(if (dlopt "p") [result [
- vec3 shadow@[j]tc = getshadowtc(light@[j]dir, shadowparams[@@j], shadowoffset[@@j]);
- float shadow@[j]val = filtershadow(shadow@[j]tc);
- ]])
float light@[j]invdist = inversesqrt(light@[j]dist2);
- float light@[j]atten = light@[j]facing * (1.0 - light@[j]invdist);
- @(if (dlopt "p") [result [
- light@[j]atten *= shadow@[j]val;
+ @(if $spotlight [result [
+ float spot@[j]dist = dot(light@[j]dir, spotparams[@@j].xyz);
+ float spot@[j]atten = light@[j]invdist * spot@[j]dist - spotparams[@@j].w;
+ if(spot@[j]atten > 0.0)
+ {
]])
+ float light@[j]atten = light@[j]facing * (1.0 - light@[j]invdist);
+ @(if $spotlight [
+ if (dlopt "p") [result [
+ vec3 spot@[j]tc = getspottc(light@[j]dir, spot@[j]dist, spotx[@@j], spoty[@@j], shadowparams[@@j], shadowoffset[@@j]);
+ light@[j]atten *= spot@[j]atten * filtershadow(spot@[j]tc);
+ ]] [result [
+ light@[j]atten *= spot@[j]atten;
+ ]]
+ ] [
+ if (dlopt "p") [result [
+ vec3 shadow@[j]tc = getshadowtc(light@[j]dir, shadowparams[@@j], shadowoffset[@@j]);
+ light@[j]atten *= filtershadow(shadow@[j]tc);
+ ]]
+ ])
@(if (dlopt "m") [result [
light += diffuse.rgb * lightcolor[@@j] * light@[j]atten;
]] [result [
float light@[j]spec = pow(max(light@[j]invdist*(dot(camdir, light@[j]dir) - light@[j]facing*facing), 0.0), 8.0) * glow.a;
light += (diffuse.rgb + light@[j]spec) * lightcolor[@@j] * light@[j]atten;
]])
+ @(? $spotlight [}])
}
]])
@(if (dlopt "m") [if $baselight [result [
@@ -1500,7 +1525,7 @@ deferredlightvariantshader = [
])
]])
}
- ] 32
+ ] 64
]
deferredlightshader = [
@@ -1511,6 +1536,10 @@ deferredlightshader = [
deferredlightvariantshader $shadername 1 (concatword $arg1 $arg2 $arg3) $arg4 (+ $i 1) // row 1, shadowed point lights, sunlight
deferredlightvariantshader $shadername 2 $arg1 $arg4 (+ $i 1) // row 2, point lights
deferredlightvariantshader $shadername 3 (concatword $arg1 $arg2) $arg4 (+ $i 1) // row 3, shadowed point lights
+ deferredlightvariantshader $shadername 4 (concatword $arg1 $arg3) $arg4 (+ $i 1) // row 4, spot lights, sunlight
+ deferredlightvariantshader $shadername 5 (concatword $arg1 $arg2 $arg3) $arg4 (+ $i 1) // row 5, shadowed spot lights, sunlight
+ deferredlightvariantshader $shadername 6 $arg1 $arg4 (+ $i 1) // row 6, spot lights
+ deferredlightvariantshader $shadername 7 (concatword $arg1 $arg2) $arg4 (+ $i 1) // row 7, shadowed spot lights
]
]
View
12 src/engine/command.cpp
@@ -2590,9 +2590,17 @@ ICOMMAND(cond, "ee2V", (tagval *args, int numargs),
{
for(int i = 0; i < numargs; i += 2)
{
- if(executebool(args[i].code))
+ if(i+1 < numargs)
{
- if(i+1 < numargs) executeret(args[i+1].code, *commandret);
+ if(executebool(args[i].code))
+ {
+ executeret(args[i+1].code, *commandret);
+ break;
+ }
+ }
+ else
+ {
+ executeret(args[i].code, *commandret);
break;
}
}
View
21 src/engine/engine.h
@@ -349,25 +349,22 @@ static inline void masktiles(uint *tiles, float sx1, float sy1, float sx2, float
for(int ty = ty1; ty < ty2; ty++) tiles[ty] |= ((1<<(tx2-tx1))-1)<<tx1;
}
-enum { SM_NONE = 0, SM_CUBEMAP, SM_TETRA, SM_CASCADE };
+enum { SM_NONE = 0, SM_CUBEMAP, SM_TETRA, SM_CASCADE, SM_SPOT };
extern int shadowmapping;
extern int smtetra, smtetraclip;
extern plane smtetraclipplane;
-extern vec shadoworigin;
+extern vec shadoworigin, shadowdir;
extern float shadowradius, shadowbias;
-extern int shadowside;
+extern int shadowside, shadowspot;
extern void collectlights();
extern void findshadowvas();
extern void findshadowmms();
-extern void findcsmshadowvas();
-extern void findcsmshadowmms();
-
extern void rendershadowmapworld();
extern void batchshadowmapmodels();
@@ -380,6 +377,18 @@ extern int cullfrustumtetra(const vec &lightpos, float lightradius, float size,
extern int calcbbcsmsplits(const ivec &bbmin, const ivec &bbmax);
extern int calcspherecsmsplits(const vec &center, float radius);
+static inline bool sphereinsidespot(const vec &dir, int spot, const vec &center, float radius)
+{
+ const vec2 &sc = sincos360[spot];
+ float cdist = dir.dot(center), cradius = radius + sc.y*cdist;
+ return sc.x*sc.x*(center.dot(center) - cdist*cdist) <= cradius*cradius;
+}
+static inline bool bbinsidespot(const vec &origin, const vec &dir, int spot, const ivec &bbmin, const ivec &bbmax)
+{
+ vec radius = ivec(bbmax).sub(bbmin).tovec().mul(0.5f), center = bbmin.tovec().add(radius);
+ return sphereinsidespot(dir, spot, center.sub(origin), radius.magnitude());
+}
+
extern void loaddeferredlightshaders();
extern void cleardeferredlightshaders();
View
14 src/engine/light.cpp
@@ -673,10 +673,9 @@ void lightreaching(const vec &target, vec &color, vec &dir, bool fast, extentity
intensity -= mag / float(e.attr1);
if(e.attached && e.attached->type==ET_SPOTLIGHT)
{
- vec spot(vec(e.attached->o).sub(e.o).normalize());
- float maxatten = 1-cosf(max(1, min(90, int(e.attached->attr1)))*RAD);
- float spotatten = 1-(1-ray.dot(spot))/maxatten;
- if(spotatten<=0) continue;
+ vec spot = vec(e.attached->o).sub(e.o).normalize();
+ float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
+ if(spotatten <= 0) continue;
intensity *= spotatten;
}
@@ -728,10 +727,9 @@ entity *brightestlight(const vec &target, const vec &dir)
intensity -= mag / float(e.attr1);
if(e.attached && e.attached->type==ET_SPOTLIGHT)
{
- vec spot(vec(e.attached->o).sub(e.o).normalize());
- float maxatten = 1-cosf(max(1, min(90, int(e.attached->attr1)))*RAD);
- float spotatten = 1-(1-ray.dot(spot))/maxatten;
- if(spotatten<=0) continue;
+ vec spot = vec(e.attached->o).sub(e.o).normalize();
+ float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
+ if(spotatten <= 0) continue;
intensity *= spotatten;
}
View
198 src/engine/rendergl.cpp
@@ -2064,7 +2064,9 @@ struct lightinfo
float sx1, sy1, sx2, sy2, sz1, sz2;
int shadowmap, flags;
vec o, color;
- int radius;
+ float radius;
+ vec dir;
+ int spot;
float dist;
occludequery *query;
};
@@ -2073,9 +2075,11 @@ struct shadowcachekey
{
vec o;
float radius;
+ vec dir;
+ int spot;
shadowcachekey() {}
- shadowcachekey(const lightinfo &l) : o(l.o), radius(l.radius) {}
+ shadowcachekey(const lightinfo &l) : o(l.o), radius(l.radius), dir(l.dir), spot(l.spot) {}
};
static inline uint hthash(const shadowcachekey &k)
@@ -2085,7 +2089,7 @@ static inline uint hthash(const shadowcachekey &k)
static inline bool htcmp(const shadowcachekey &x, const shadowcachekey &y)
{
- return x.o == y.o && x.radius == y.radius;
+ return x.o == y.o && x.radius == y.radius && x.dir == y.dir && x.spot == y.spot;
}
struct shadowcacheval;
@@ -2230,6 +2234,7 @@ FVAR(smbias, -1e6f, 0.01f, 1e6f);
FVAR(smprec, 1e-3f, 1, 1e3f);
FVAR(smtetraprec, 1e-3f, SQRT3, 1e3f);
FVAR(smcubeprec, 1e-3f, 1, 1e3f);
+FVAR(smspotprec, 1e-3f, 1, 1e3f);
VAR(smsidecull, 0, 1, 1);
VAR(smviscull, 0, 1, 1);
@@ -2681,7 +2686,7 @@ void resetlights()
{
if(shadowcachefull)
{
- int smw = tetra ? sm.size*2 : sm.size*3, smh = tetra ? sm.size : sm.size*2;
+ int smw = l.spot ? sm.size : (tetra ? sm.size*2 : sm.size*3), smh = l.spot ? sm.size : (tetra ? sm.size : sm.size*2);
if(sm.x < evictx2 && sm.x + smw > evictx && sm.y < evicty2 && sm.y + smh > evicty) continue;
}
shadowcache[1][l] = sm;
@@ -2786,19 +2791,26 @@ void renderlights(float bsx1 = -1, float bsy1 = -1, float bsx2 = 1, float bsy2 =
{
vector<int> &tile = lighttiles[y][x];
- static LocalShaderParam lightpos("lightpos"), lightcolor("lightcolor"), shadowparams("shadowparams"), shadowoffset("shadowoffset");
- static vec4 lightposv[8], shadowparamsv[8];
- static vec lightcolorv[8];
+ static LocalShaderParam lightpos("lightpos"), lightcolor("lightcolor"), spotparams("spotparams"), spotx("spotx"), spoty("spoty"), shadowparams("shadowparams"), shadowoffset("shadowoffset");
+ static vec4 lightposv[8], spotparamsv[8], shadowparamsv[8];
+ static vec lightcolorv[8], spotxv[8], spotyv[8];
static vec2 shadowoffsetv[8];
for(int i = 0;;)
{
int n = min(tile.length() - i, lighttilebatch);
- bool shadowmap = n > 0 && lights[tile[i]].shadowmap >= 0;
+ bool shadowmap = false, spotlight = false;
+ if(n > 0)
+ {
+ lightinfo &l = lights[tile[i]];
+ shadowmap = l.shadowmap >= 0;
+ spotlight = l.spot > 0;
+ }
loopj(n)
{
- if((lights[tile[i+j]].shadowmap >= 0) != shadowmap) { n = j; break; }
+ lightinfo &l = lights[tile[i+j]];
+ if((l.shadowmap >= 0) != shadowmap || (l.spot > 0) != spotlight) { n = j; break; }
}
float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1, sz1 = 1, sz2 = -1;
@@ -2807,16 +2819,40 @@ void renderlights(float bsx1 = -1, float bsy1 = -1, float bsx2 = 1, float bsy2 =
lightinfo &l = lights[tile[i+j]];
lightposv[j] = vec4(l.o.x, l.o.y, l.o.z, 1.0f/l.radius);
lightcolorv[j] = vec(l.color.x*lightscale, l.color.y*lightscale, l.color.z*lightscale);
+ if(spotlight)
+ {
+ float maxatten = sincos360[l.spot].x;
+ spotparamsv[j] = vec4(l.dir, maxatten).div(1 - maxatten);
+ }
if(shadowmap)
{
shadowmapinfo &sm = shadowmaps[l.shadowmap];
float smnearclip = SQRT3 / l.radius, smfarclip = SQRT3,
bias = (smcullside ? smbias : -smbias) * smnearclip * (1024.0f / sm.size);
- shadowparamsv[j] = vec4(
- 0.5f * (sm.size - smborder),
- -smnearclip * smfarclip / (smfarclip - smnearclip) - 0.5f*bias,
- sm.size,
- 0.5f + 0.5f * (smfarclip + smnearclip) / (smfarclip - smnearclip));
+ if(spotlight)
+ {
+ vec adir(fabs(l.dir.x), fabs(l.dir.y), fabs(l.dir.z)), spotx(1, 0, 0), spoty(0, 1, 0);
+ if(adir.x > adir.y) { if(adir.x > adir.z) spotx = vec(0, 0, 1); }
+ else if(adir.y > adir.z) spoty = vec(0, 0, 1);
+ l.dir.orthonormalize(spotx, spoty);
+ const vec2 &sc = sincos360[l.spot];
+ float spotscale = sc.x/sc.y;
+ spotxv[j] = spotx.rescale(spotscale);
+ spotyv[j] = spoty.rescale(spotscale);
+ shadowparamsv[j] = vec4(
+ 0.5f * sm.size / (1 - sc.x),
+ (-smnearclip * smfarclip / (smfarclip - smnearclip) - 0.5f*bias) / (1 - sc.x),
+ sm.size,
+ 0.5f + 0.5f * (smfarclip + smnearclip) / (smfarclip - smnearclip));
+ }
+ else
+ {
+ shadowparamsv[j] = vec4(
+ 0.5f * (sm.size - smborder),
+ -smnearclip * smfarclip / (smfarclip - smnearclip) - 0.5f*bias,
+ sm.size,
+ 0.5f + 0.5f * (smfarclip + smnearclip) / (smfarclip - smnearclip));
+ }
shadowoffsetv[j] = vec2(sm.x + 0.5f*sm.size, sm.y + 0.5f*sm.size);
}
sx1 = min(sx1, l.sx1);
@@ -2831,11 +2867,17 @@ void renderlights(float bsx1 = -1, float bsy1 = -1, float bsx2 = 1, float bsy2 =
if(n)
{
- s->setvariant(n-1, (shadowmap ? 1 : 0) + (i ? 2 : 0));
+ s->setvariant(n-1, (shadowmap ? 1 : 0) + (i ? 2 : 0) + (spotlight ? 4 : 0));
lightpos.set(lightposv, n);
lightcolor.set(lightcolorv, n);
+ if(spotlight) spotparams.set(spotparamsv, n);
if(shadowmap)
{
+ if(spotlight)
+ {
+ spotx.set(spotxv, n);
+ spoty.set(spotyv, n);
+ }
shadowparams.set(shadowparamsv, n);
shadowoffset.set(shadowoffsetv, n);
}
@@ -2922,6 +2964,16 @@ void collectlights()
l.o = e->o;
l.color = vec(e->attr2, e->attr3, e->attr4);
l.radius = e->attr1 > 0 ? e->attr1 : 2*worldsize;
+ if(e->attached && e->attached->type == ET_SPOTLIGHT)
+ {
+ l.dir = vec(e->attached->o).sub(e->o).normalize();
+ l.spot = clamp(int(e->attached->attr1), 1, 89);
+ }
+ else
+ {
+ l.dir = vec(0, 0, 0);
+ l.spot = 0;
+ }
l.dist = camera1->o.dist(e->o);
}
@@ -2952,6 +3004,8 @@ void collectlights()
l.o = o;
l.color = vec(color).mul(255);
l.radius = radius;
+ l.dir = vec(0, 0, 0);
+ l.spot = 0;
l.dist = camera1->o.dist(o);
}
@@ -3003,9 +3057,15 @@ void packlights()
if(l.flags&L_NOSHADOW || l.radius <= smminradius) continue;
if(l.query && l.query->owner == &l && checkquery(l.query)) continue;
- float smlod = clamp(l.radius * smprec / sqrtf(max(1.0f, l.dist/l.radius)), float(smminsize), float(smmaxsize));
- int smsize = clamp(int(ceil(smlod * (tetra ? smtetraprec : smcubeprec))), 1, SHADOWATLAS_SIZE / (tetra ? 2 : 3)),
- smw = tetra ? smsize*2 : smsize*3, smh = tetra ? smsize : smsize*2;
+ float prec = smprec, smlod;
+ int smw, smh;
+ if(l.spot) { smw = 1; smh = 1; const vec2 &sc = sincos360[l.spot]; prec = sc.y/sc.x; smlod = smspotprec; }
+ else if(tetra) { smw = 2; smh = 1; smlod = smtetraprec; }
+ else { smw = 3; smh = 2; smlod = smcubeprec; }
+ smlod *= clamp(l.radius * prec / sqrtf(max(1.0f, l.dist/l.radius)), float(smminsize), float(smmaxsize));
+ int smsize = clamp(int(ceil(smlod)), 1, SHADOWATLAS_SIZE / smw);
+ smw *= smsize;
+ smh *= smsize;
ushort smx = USHRT_MAX, smy = USHRT_MAX;
shadowmapinfo *sm = NULL;
int smidx = -1;
@@ -3018,7 +3078,7 @@ void packlights()
sm->light = idx;
sm->cached = cached;
l.shadowmap = smidx;
- smused += smsize*smsize*(tetra ? 2 : 6);
+ smused += smw*smh;
addlighttiles(l, idx);
}
@@ -3031,9 +3091,15 @@ void packlights()
if(!(l.flags&L_NOSHADOW) && smnoshadow <= 1 && l.radius > smminradius)
{
if(l.query && l.query->owner == &l && checkquery(l.query)) { lightsoccluded++; continue; }
- float smlod = clamp(l.radius * smprec / sqrtf(max(1.0f, l.dist/l.radius)), float(smminsize), float(smmaxsize));
- int smsize = clamp(int(ceil(smlod * (tetra ? smtetraprec : smcubeprec))), 1, SHADOWATLAS_SIZE / (tetra ? 2 : 3)),
- smw = tetra ? smsize*2 : smsize*3, smh = tetra ? smsize : smsize*2;
+ float prec = smprec, smlod;
+ int smw, smh;
+ if(l.spot) { smw = 1; smh = 1; const vec2 &sc = sincos360[l.spot]; prec = sc.y/sc.x; smlod = smspotprec; }
+ else if(tetra) { smw = 2; smh = 1; smlod = smtetraprec; }
+ else { smw = 3; smh = 2; smlod = smcubeprec; }
+ smlod *= clamp(l.radius * prec / sqrtf(max(1.0f, l.dist/l.radius)), float(smminsize), float(smmaxsize));
+ int smsize = clamp(int(ceil(smlod)), 1, SHADOWATLAS_SIZE / smw);
+ smw *= smsize;
+ smh *= smsize;
ushort smx = USHRT_MAX, smy = USHRT_MAX;
shadowmapinfo *sm = NULL;
int smidx = -1;
@@ -3048,7 +3114,7 @@ void packlights()
sm = addshadowmap(smx, smy, smsize, smidx);
sm->light = idx;
l.shadowmap = smidx;
- smused += smsize*smsize*(tetra ? 2 : 6);
+ smused += smw*smh;
addlighttiles(l, idx);
continue;
@@ -3061,7 +3127,7 @@ void packlights()
sm = addshadowmap(smx, smy, smsize, smidx);
sm->light = idx;
l.shadowmap = smidx;
- smused += smsize*smsize*(tetra ? 2 : 6);
+ smused += smw*smh;
}
}
@@ -3075,8 +3141,9 @@ void rendercsmshadowmaps()
{
shadowmapping = SM_CASCADE;
shadoworigin = vec(0, 0, 0);
- shadowradius = 2*worldsize;
- shadowbias = 0;
+ shadowdir = csm.lightview;
+ shadowbias = csm.lightview.project_bb(worldmin, worldmax);
+ shadowradius = fabs(csm.lightview.project_bb(worldmax, worldmin));
if(csmpolyfactor || csmpolyoffset)
{
@@ -3084,8 +3151,8 @@ void rendercsmshadowmaps()
glEnable(GL_POLYGON_OFFSET_FILL);
}
- findcsmshadowvas(); // no culling here
- findcsmshadowmms(); // no culling here
+ findshadowvas();
+ findshadowmms();
shadowmaskbatchedmodels();
batchshadowmapmodels();
@@ -3119,14 +3186,12 @@ void rendercsmshadowmaps()
void rendershadowmaps()
{
- shadowmapping = smtetra && glslversion >= 130 ? SM_TETRA : SM_CUBEMAP;
-
+ bool tetra = smtetra && glslversion >= 130;
if(smpolyfactor || smpolyoffset)
{
glPolygonOffset(smpolyfactor, smpolyoffset);
glEnable(GL_POLYGON_OFFSET_FILL);
}
- if(shadowmapping == SM_TETRA && smtetraclip) glEnable(GL_CLIP_PLANE0);
loopv(shadowmaps)
{
@@ -3135,15 +3200,35 @@ void rendershadowmaps()
lightinfo &l = lights[sm.light];
- int sidemask;
- if(shadowmapping == SM_TETRA) sidemask = smsidecull ? cullfrustumtetra(l.o, l.radius, sm.size, smborder) : 0xF;
- else sidemask = smsidecull ? cullfrustumsides(l.o, l.radius, sm.size, smborder) : 0x3F;
+ int border, sidemask;
+ if(l.spot)
+ {
+ if(shadowmapping == SM_TETRA && smtetraclip) glDisable(GL_CLIP_PLANE0);
+ shadowmapping = SM_SPOT;
+ border = 0;
+ sidemask = 1;
+ }
+ else if(tetra)
+ {
+ if(shadowmapping != SM_TETRA && smtetraclip) glEnable(GL_CLIP_PLANE0);
+ shadowmapping = SM_TETRA;
+ border = smborder;
+ sidemask = smsidecull ? cullfrustumtetra(l.o, l.radius, sm.size, smborder) : 0xF;
+ }
+ else
+ {
+ shadowmapping = SM_CUBEMAP;
+ border = smborder;
+ sidemask = smsidecull ? cullfrustumsides(l.o, l.radius, sm.size, smborder) : 0x3F;
+ }
sm.sidemask = sidemask;
shadoworigin = l.o;
shadowradius = l.radius;
- shadowbias = smborder / float(sm.size - smborder);
+ shadowbias = border / float(sm.size - border);
+ shadowdir = l.dir;
+ shadowspot = l.spot;
findshadowvas();
findshadowmms();
@@ -3176,8 +3261,8 @@ void rendershadowmaps()
float smnearclip = SQRT3 / l.radius, smfarclip = SQRT3;
GLfloat smprojmatrix[16] =
{
- float(sm.size - smborder) / sm.size, 0, 0, 0,
- 0, float(sm.size - smborder) / sm.size, 0, 0,
+ float(sm.size - border) / sm.size, 0, 0, 0,
+ 0, float(sm.size - border) / sm.size, 0, 0,
0, 0, -(smfarclip + smnearclip) / (smfarclip - smnearclip), -1,
0, 0, -2*smnearclip*smfarclip / (smfarclip - smnearclip), 0
};
@@ -3195,7 +3280,44 @@ void rendershadowmaps()
glmatrixf smviewmatrix;
- if(shadowmapping == SM_TETRA)
+ if(shadowmapping == SM_SPOT)
+ {
+ glViewport(sm.x, sm.y, sm.size, sm.size);
+ glScissor(sm.x, sm.y, sm.size, sm.size);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ vec adir(fabs(l.dir.x), fabs(l.dir.y), fabs(l.dir.z)), spotx(1, 0, 0), spoty(0, 1, 0);
+ int dim = 2;
+ if(adir.x > adir.y)
+ {
+ if(adir.x > adir.z) { dim = 0; spotx = vec(0, 0, 1); }
+ }
+ else if(adir.y > adir.z) { dim = 1; spoty = vec(0, 0, 1); }
+ l.dir.orthonormalize(spotx, spoty);
+ const vec2 &sc = sincos360[l.spot];
+ float spotscale = sc.x/sc.y;
+ spotx.rescale(spotscale);
+ spoty.rescale(spotscale);
+
+ GLfloat spotmatrix[16] =
+ {
+ spotx.x, spoty.x, -l.dir.x, 0,
+ spotx.y, spoty.y, -l.dir.y, 0,
+ spotx.z, spoty.z, -l.dir.z, 0,
+ 0, 0, 0, 1
+ };
+ smviewmatrix.mul(spotmatrix, lightmatrix);
+ glLoadMatrixf(smviewmatrix.v);
+
+ int side = 2*dim + (l.dir[dim] < 0 ? 1 : 0);
+ glCullFace((side & 1) ^ (side >> 2) ^ smcullside ? GL_FRONT : GL_BACK);
+
+ shadowside = 0;
+
+ rendershadowmapworld();
+ rendermodelbatches();
+ }
+ else if(shadowmapping == SM_TETRA)
{
if(!cachemask)
{
View
23 src/engine/rendermodel.cpp
@@ -575,14 +575,27 @@ static inline int shadowmaskmodel(const vec &center, float radius)
switch(shadowmapping)
{
case SM_TETRA:
- if(center.dist(shadoworigin) >= radius + shadowradius) return 0;
- return calcspheretetramask(vec(center).sub(shadoworigin).div(shadowradius), radius/shadowradius, shadowbias);
- break;
+ {
+ vec scenter = vec(center).sub(shadoworigin);
+ float sradius = radius + shadowradius;
+ if(scenter.squaredlen() >= sradius*sradius) return 0;
+ return calcspheretetramask(scenter, radius, shadowbias*shadowradius);
+ }
case SM_CUBEMAP:
- if(center.dist(shadoworigin) >= radius + shadowradius) return 0;
- return calcspheresidemask(vec(center).sub(shadoworigin).div(shadowradius), radius/shadowradius, shadowbias);
+ {
+ vec scenter = vec(center).sub(shadoworigin);
+ float sradius = radius + shadowradius;
+ if(scenter.squaredlen() >= sradius*sradius) return 0;
+ return calcspheresidemask(scenter, radius, shadowbias);
+ }
case SM_CASCADE:
return calcspherecsmsplits(center, radius);
+ case SM_SPOT:
+ {
+ vec scenter = vec(center).sub(shadoworigin);
+ float sradius = radius + shadowradius;
+ return scenter.squaredlen() < sradius*sradius && sphereinsidespot(shadowdir, shadowspot, scenter, radius) ? 1 : 0;
+ }
}
return 0;
}
View
78 src/engine/renderva.cpp
@@ -963,9 +963,9 @@ VAR(smbbcull, 0, 1, 1);
VAR(smdistcull, 0, 1, 1);
VAR(smnodraw, 0, 0, 1);
-vec shadoworigin(0, 0, 0);
+vec shadoworigin(0, 0, 0), shadowdir(0, 0, 0);
float shadowradius = 0, shadowbias = 0;
-int shadowside = 0;
+int shadowside = 0, shadowspot = 0;
vtxarray *shadowva = NULL;
@@ -1033,14 +1033,6 @@ void findshadowvas(vector<vtxarray *> &vas)
}
}
-void findshadowvas()
-{
- memset(vasort, 0, sizeof(vasort));
- if(shadowmapping == SM_TETRA) findtetrashadowvas(varoot);
- else findshadowvas(varoot);
- sortshadowvas();
-}
-
void findcsmshadowvas(vector<vtxarray *> &vas)
{
loopv(vas)
@@ -1052,17 +1044,40 @@ void findcsmshadowvas(vector<vtxarray *> &vas)
v.shadowmask = calcbbcsmsplits(bbmin, bbmax);
if(v.shadowmask)
{
- float dist = sunlightdir.project_bb(bbmin, bbmax);
+ float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias;
addshadowva(&v, dist);
if(v.children.length()) findcsmshadowvas(v.children);
}
}
}
-void findcsmshadowvas()
+void findspotshadowvas(vector<vtxarray *> &vas)
+{
+ loopv(vas)
+ {
+ vtxarray &v = *vas[i];
+ float dist = vadist(&v, shadoworigin);
+ if(dist < shadowradius || !smdistcull)
+ {
+ v.shadowmask = !smbbcull || (v.children.length() || v.mapmodels.length() ?
+ bbinsidespot(shadoworigin, shadowdir, shadowspot, v.bbmin, v.bbmax) :
+ bbinsidespot(shadoworigin, shadowdir, shadowspot, v.geommin, v.geommax)) ? 1 : 0;
+ addshadowva(&v, dist);
+ if(v.children.length()) findspotshadowvas(v.children);
+ }
+ }
+}
+
+void findshadowvas()
{
memset(vasort, 0, sizeof(vasort));
- findcsmshadowvas(varoot);
+ switch(shadowmapping)
+ {
+ case SM_CUBEMAP: findshadowvas(varoot); break;
+ case SM_TETRA: findtetrashadowvas(varoot); break;
+ case SM_CASCADE: findcsmshadowvas(varoot); break;
+ case SM_SPOT: findspotshadowvas(varoot); break;
+ }
sortshadowvas();
}
@@ -1115,10 +1130,23 @@ void findshadowmms()
loopvj(va->mapmodels)
{
octaentities *oe = va->mapmodels[j];
- if(smdistcull)
+ switch(shadowmapping)
{
- if(shadoworigin.dist_to_bb(oe->bbmin, oe->bbmax) >= shadowradius)
- continue;
+ case SM_CASCADE:
+ if(!calcbbcsmsplits(oe->bbmin, oe->bbmax))
+ continue;
+ break;
+ case SM_TETRA:
+ case SM_CUBEMAP:
+ if(smdistcull && shadoworigin.dist_to_bb(oe->bbmin, oe->bbmax) >= shadowradius)
+ continue;
+ break;
+ case SM_SPOT:
+ if(smdistcull && shadoworigin.dist_to_bb(oe->bbmin, oe->bbmax) >= shadowradius)
+ continue;
+ if(smbbcull && !bbinsidespot(shadoworigin, shadowdir, shadowspot, oe->bbmin, oe->bbmax))
+ continue;
+ break;
}
oe->rnext = NULL;
*lastmms = oe;
@@ -1127,24 +1155,6 @@ void findshadowmms()
}
}
-void findcsmshadowmms()
-{
- shadowmms = NULL;
- octaentities **lastmms = &shadowmms;
- for(vtxarray *va = shadowva; va; va = va->rnext)
- {
- loopvj(va->mapmodels)
- {
- octaentities *oe = va->mapmodels[j];
- if(!calcbbcsmsplits(oe->bbmin, oe->bbmax))
- continue;
- oe->rnext = NULL;
- *lastmms = oe;
- lastmms = &oe->rnext;
- }
- }
-}
-
void batchshadowmapmodels()
{
if(!shadowmms) return;
View
2  src/engine/texture.h
@@ -208,7 +208,7 @@ enum
};
#define MAXSHADERDETAIL 3
-#define MAXVARIANTROWS 5
+#define MAXVARIANTROWS 8
extern int shaderdetail;
View
2  src/engine/world.cpp
@@ -627,7 +627,7 @@ void renderentradius(extentity &e, bool color)
float radius = e.attached->attr1;
if(!radius) radius = 2*e.o.dist(e.attached->o);
vec dir = vec(e.o).sub(e.attached->o).normalize();
- float angle = max(1, min(90, int(e.attr1)));
+ float angle = clamp(int(e.attr1), 1, 89);
renderentattachment(e);
renderentcone(*e.attached, dir, radius, angle);
}
View
BIN  tesseract/packages/base/refract-test.ogz
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.