3D View: support non-uniform scaled lamps
D1378 by @youle Non-uniform scaled lamps now cast oval/rectangular shadows, viewport & BGE.
This commit is contained in:
parent
3de81314fa
commit
e60d535443
@ -277,6 +277,12 @@ GLSL Lamp Uniforms
|
||||
|
||||
:type: float
|
||||
|
||||
.. data:: GPU_DYNAMIC_LAMP_SPOTSCALE
|
||||
|
||||
Represents the SpotLamp local scale.
|
||||
|
||||
:type: float2
|
||||
|
||||
|
||||
GLSL Sampler Uniforms
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1198,7 +1198,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
|
||||
Object *ob = base->object;
|
||||
const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
|
||||
Lamp *la = ob->data;
|
||||
float vec[3], lvec[3], vvec[3], circrad, x, y, z;
|
||||
float vec[3], lvec[3], vvec[3], circrad;
|
||||
float lampsize;
|
||||
float imat[4][4];
|
||||
|
||||
@ -1345,7 +1345,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
|
||||
/* skip drawing extra info */
|
||||
}
|
||||
else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
|
||||
|
||||
float x, y, z, z_abs;
|
||||
copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
|
||||
copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
|
||||
mul_transposed_mat3_m4_v3(ob->obmat, vvec);
|
||||
@ -1358,46 +1358,75 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
|
||||
mul_v3_fl(lvec, x);
|
||||
mul_v3_fl(vvec, x);
|
||||
|
||||
/* draw the angled sides of the cone */
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex3fv(vvec);
|
||||
glVertex3fv(vec);
|
||||
glVertex3fv(lvec);
|
||||
glEnd();
|
||||
|
||||
x *= y;
|
||||
|
||||
/* draw the circle/square at the end of the cone */
|
||||
glTranslatef(0.0, 0.0, x);
|
||||
z_abs = fabsf(z);
|
||||
|
||||
if (la->mode & LA_SQUARE) {
|
||||
float tvec[3];
|
||||
float z_abs = fabsf(z);
|
||||
/* draw pyramid */
|
||||
const float vertices[5][3] = {
|
||||
/* 5 of vertex coords of pyramid */
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{z_abs, z_abs, x},
|
||||
{-z_abs, -z_abs, x},
|
||||
{z_abs, -z_abs, x},
|
||||
{-z_abs, z_abs, x},
|
||||
};
|
||||
const unsigned char indices[] = {
|
||||
0, 1, 3,
|
||||
0, 3, 2,
|
||||
0, 2, 4,
|
||||
0, 1, 4,
|
||||
};
|
||||
|
||||
tvec[0] = tvec[1] = z_abs;
|
||||
tvec[2] = 0.0;
|
||||
/* Draw call:
|
||||
* activate and specify pointer to vertex array */
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vertices);
|
||||
/* draw the pyramid */
|
||||
glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices);
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3fv(tvec);
|
||||
tvec[1] = -z_abs; /* neg */
|
||||
glVertex3fv(tvec);
|
||||
tvec[0] = -z_abs; /* neg */
|
||||
glVertex3fv(tvec);
|
||||
tvec[1] = z_abs; /* pos */
|
||||
glVertex3fv(tvec);
|
||||
glEnd();
|
||||
/* deactivate vertex arrays after drawing */
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glTranslatef(0.0f, 0.0f, x);
|
||||
|
||||
/* draw the square representing spotbl */
|
||||
if (la->type == LA_SPOT) {
|
||||
float blend = z_abs * (1.0f - pow2f(la->spotblend));
|
||||
|
||||
/* hide line if it is zero size or overlaps with outer border,
|
||||
* previously it adjusted to always to show it but that seems
|
||||
* confusing because it doesn't show the actual blend size */
|
||||
if (blend != 0.0f && blend != z_abs) {
|
||||
fdrawbox(blend, -blend, -blend, blend);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
circ(0.0, 0.0, fabsf(z));
|
||||
}
|
||||
|
||||
/* draw the circle/square representing spotbl */
|
||||
if (la->type == LA_SPOT) {
|
||||
float spotblcirc = fabsf(z) * (1.0f - pow2f(la->spotblend));
|
||||
/* hide line if it is zero size or overlaps with outer border,
|
||||
* previously it adjusted to always to show it but that seems
|
||||
* confusing because it doesn't show the actual blend size */
|
||||
if (spotblcirc != 0 && spotblcirc != fabsf(z))
|
||||
circ(0.0, 0.0, spotblcirc);
|
||||
/* draw the angled sides of the cone */
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex3fv(vvec);
|
||||
glVertex3fv(vec);
|
||||
glVertex3fv(lvec);
|
||||
glEnd();
|
||||
|
||||
/* draw the circle at the end of the cone */
|
||||
glTranslatef(0.0f, 0.0f, x);
|
||||
circ(0.0f, 0.0f, z_abs);
|
||||
|
||||
/* draw the circle representing spotbl */
|
||||
if (la->type == LA_SPOT) {
|
||||
float blend = z_abs * (1.0f - pow2f(la->spotblend));
|
||||
|
||||
/* hide line if it is zero size or overlaps with outer border,
|
||||
* previously it adjusted to always to show it but that seems
|
||||
* confusing because it doesn't show the actual blend size */
|
||||
if (blend != 0.0f && blend != z_abs) {
|
||||
circ(0.0f, 0.0f, blend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drawcone)
|
||||
|
@ -160,6 +160,7 @@ typedef enum GPUDynamicType {
|
||||
GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP,
|
||||
GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP,
|
||||
GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP,
|
||||
GPU_DYNAMIC_LAMP_SPOTSCALE = 12 | GPU_DYNAMIC_GROUP_LAMP,
|
||||
|
||||
GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER,
|
||||
GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER,
|
||||
|
@ -141,6 +141,7 @@ struct GPULamp {
|
||||
float dynimat[4][4];
|
||||
|
||||
float spotsi, spotbl, k;
|
||||
float spotvec[2];
|
||||
float dyndist, dynatt1, dynatt2;
|
||||
float dist, att1, att2;
|
||||
float shadow_color[3];
|
||||
@ -536,12 +537,15 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
|
||||
|
||||
if (lamp->type == LA_SPOT) {
|
||||
if (lamp->mode & LA_SQUARE) {
|
||||
mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_IMAT;
|
||||
GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), *lv, &inpr);
|
||||
mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
|
||||
GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
|
||||
GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
|
||||
}
|
||||
else {
|
||||
mat->dynproperty |= DYN_LAMP_VEC;
|
||||
GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), *lv, &inpr);
|
||||
mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
|
||||
GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
|
||||
GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
|
||||
GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
|
||||
}
|
||||
|
||||
GPU_link(mat, "lamp_visibility_spot", GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), inpr, visifac, &visifac);
|
||||
@ -1854,24 +1858,41 @@ static void gpu_lamp_calc_winmat(GPULamp *lamp)
|
||||
temp = 0.5f * lamp->size * cosf(angle) / sinf(angle);
|
||||
pixsize = lamp->d / temp;
|
||||
wsize = pixsize * 0.5f * lamp->size;
|
||||
perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
|
||||
if (lamp->type & LA_SPOT) {
|
||||
/* compute shadows according to X and Y scaling factors */
|
||||
perspective_m4(
|
||||
lamp->winmat,
|
||||
-wsize * lamp->spotvec[0], wsize * lamp->spotvec[0],
|
||||
-wsize * lamp->spotvec[1], wsize * lamp->spotvec[1],
|
||||
lamp->d, lamp->clipend);
|
||||
}
|
||||
else {
|
||||
perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
|
||||
{
|
||||
float mat[4][4];
|
||||
float obmat_scale[3];
|
||||
|
||||
lamp->lay = lay;
|
||||
lamp->hide = hide;
|
||||
|
||||
copy_m4_m4(mat, obmat);
|
||||
normalize_m4(mat);
|
||||
normalize_m4_m4_ex(mat, obmat, obmat_scale);
|
||||
|
||||
copy_v3_v3(lamp->vec, mat[2]);
|
||||
copy_v3_v3(lamp->co, mat[3]);
|
||||
copy_m4_m4(lamp->obmat, mat);
|
||||
invert_m4_m4(lamp->imat, mat);
|
||||
|
||||
/* update spotlamp scale on X and Y axis */
|
||||
lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2];
|
||||
lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2];
|
||||
|
||||
/* makeshadowbuf */
|
||||
gpu_lamp_calc_winmat(lamp);
|
||||
}
|
||||
|
||||
void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
|
||||
@ -1895,8 +1916,6 @@ void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend)
|
||||
{
|
||||
lamp->spotsi = cosf(spotsize * 0.5f);
|
||||
lamp->spotbl = (1.0f - lamp->spotsi) * spotblend;
|
||||
|
||||
gpu_lamp_calc_winmat(lamp);
|
||||
}
|
||||
|
||||
static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp)
|
||||
@ -1941,9 +1960,6 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
|
||||
|
||||
/* arbitrary correction for the fact we do no soft transition */
|
||||
lamp->bias *= 0.25f;
|
||||
|
||||
/* makeshadowbuf */
|
||||
gpu_lamp_calc_winmat(lamp);
|
||||
}
|
||||
|
||||
static void gpu_lamp_shadow_free(GPULamp *lamp)
|
||||
|
@ -1584,11 +1584,13 @@ void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float
|
||||
outvisifac= visifac*max(t, 0.0)/lampdist;
|
||||
}
|
||||
|
||||
void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float inpr)
|
||||
void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
|
||||
{
|
||||
if(dot(lv, lampvec) > 0.0) {
|
||||
vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz;
|
||||
float x = max(abs(lvrot.x/lvrot.z), abs(lvrot.y/lvrot.z));
|
||||
/* without clever non-uniform scale, we could do: */
|
||||
// float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
|
||||
float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z));
|
||||
|
||||
inpr = 1.0/sqrt(1.0 + x*x);
|
||||
}
|
||||
@ -1596,9 +1598,21 @@ void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float
|
||||
inpr = 0.0;
|
||||
}
|
||||
|
||||
void lamp_visibility_spot_circle(vec3 lampvec, vec3 lv, out float inpr)
|
||||
void lamp_visibility_spot_circle(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
|
||||
{
|
||||
inpr = dot(lv, lampvec);
|
||||
/* without clever non-uniform scale, we could do: */
|
||||
// inpr = dot(lv, lampvec);
|
||||
if (dot(lv, lampvec) > 0.0) {
|
||||
vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
|
||||
float x = abs(lvrot.x / lvrot.z);
|
||||
float y = abs(lvrot.y / lvrot.z);
|
||||
|
||||
float ellipse = abs((x * x) / (scale.x * scale.x) + (y * y) / (scale.y * scale.y));
|
||||
|
||||
inpr = 1.0 / sqrt(1.0 + ellipse);
|
||||
}
|
||||
else
|
||||
inpr = 0.0;
|
||||
}
|
||||
|
||||
void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, out float outvisifac)
|
||||
|
@ -116,6 +116,7 @@ static PyObject *PyInit_gpu(void)
|
||||
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE);
|
||||
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE);
|
||||
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND);
|
||||
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE);
|
||||
/* GPU_DYNAMIC_GROUP_SAMPLER */
|
||||
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER);
|
||||
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE);
|
||||
|
Loading…
x
Reference in New Issue
Block a user