diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-10-15 14:36:31 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-10-15 14:36:31 +0300 |
commit | e60d535443824f44cd6e18280570cd066c1b3dc2 (patch) | |
tree | bc7c323d0103e58fdc978806b5690df3f8124db3 /source/blender | |
parent | 3de81314fa61f9b123e5d10cbe4176718479be10 (diff) |
3D View: support non-uniform scaled lamps
D1378 by @youle
Non-uniform scaled lamps now cast oval/rectangular shadows, viewport & BGE.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 101 | ||||
-rw-r--r-- | source/blender/gpu/GPU_material.h | 1 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_material.c | 40 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_material.glsl | 22 | ||||
-rw-r--r-- | source/blender/python/intern/gpu.c | 1 |
5 files changed, 113 insertions, 52 deletions
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 8e664d74451..7f3a50ae6e5 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -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); - - tvec[0] = tvec[1] = z_abs; - tvec[2] = 0.0; - - 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(); + /* 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, + }; + + /* 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); + + /* 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) diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 9a850757496..25a4f33b526 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -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, diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 5b647232934..82902f8d69c 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -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) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 311fcb8ead2..5b62739b0eb 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -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) diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index a7ece10f06c..bc15e109901 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -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); |