BGE: Allow access to light shadow settings with python
authorUlysse Martin <you.le@live.fr>
Sun, 17 Jan 2016 17:41:37 +0000 (18:41 +0100)
committerThomas Szepe <HG1_public@gmx.net>
Sun, 17 Jan 2016 17:47:14 +0000 (18:47 +0100)
This patch adds a new API which allow us to access light shadow settings from python. The new API can be used to write custom GLSL materials with shadows.

Reviewers: brecht, kupoman, agoose77, panzergame, campbellbarton, moguri, hg1

Reviewed By: agoose77, panzergame, campbellbarton, moguri, hg1

Projects: #game_engine

Differential Revision: https://developer.blender.org/D1690

doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
source/blender/gpu/GPU_material.h
source/blender/gpu/intern/gpu_material.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Ketsji/KX_Light.cpp
source/gameengine/Ketsji/KX_Light.h
source/gameengine/Rasterizer/RAS_ILightObject.h
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h

index 2b2bdf76b4fdf420b4d35ab63c20141d20e9b852..f4d5b1143728e5245504223772bbb06f18806826 100644 (file)
@@ -48,6 +48,78 @@ base class --- :class:`KX_GameObject`
 
       :type: float
 
+   .. attribute:: shadowClipStart
+
+      The shadowmap clip start, below which objects will not generate shadows.
+
+      :type: float (read only)
+
+   .. attribute:: shadowClipEnd
+
+      The shadowmap clip end, beyond which objects will not generate shadows.
+
+      :type: float (read only)
+
+   ..attribute:: shadowFrustumSize
+
+      Size of the frustum used for creating the shadowmap.
+
+      :type: float (read only)
+
+   ..attribute:: shadowBindId
+
+      The OpenGL shadow texture bind number/id.
+
+      :type: int (read only)
+
+   ..attribute:: shadowMapType
+
+      The shadow shadow map type (0 -> Simple; 1 -> Variance)
+
+      :type: int (read only)
+
+   ..attribute:: shadowBias
+
+      The shadow buffer sampling bias.
+
+      :type: float (read only)
+
+   ..attribute:: shadowBleedBias
+
+      The bias for reducing light-bleed on variance shadow maps.
+
+      :type: float (read only)
+
+   ..attribute:: useShadow
+
+      Returns True if the light has Shadow option activated, else returns False.
+
+      :type: boolean (read only)
+
+   .. attribute:: shadowColor
+
+      The color of this light shadows. Black = (0.0, 0.0, 0.0), White = (1.0, 1.0, 1.0).
+
+      :type: :class:`mathutils.Color` (read only)
+
+   .. attribute:: shadowMatrix
+
+      Matrix that converts a vector in camera space to shadow buffer depth space.
+
+      Computed as:
+          mat4_perspective_to_depth * mat4_lamp_to_perspective * mat4_world_to_lamp * mat4_cam_to_world.
+
+      mat4_perspective_to_depth is a fixed matrix defined as follow:
+
+          0.5 0.0 0.0 0.5
+          0.0 0.5 0.0 0.5
+          0.0 0.0 0.5 0.5
+          0.0 0.0 0.0 1.0
+      Note:
+          There is one matrix of that type per lamp casting shadow in the scene.
+
+      :type: Matrix4x4 (read only)
+
    .. attribute:: distance
 
       The maximum distance this light can illuminate. (SPOT and NORMAL lights only).
index 40b32862e9f92a45bc1e6b7052834885efbf9c6a..25788c26fea9ba3b42b51efbfa984118f4724752 100644 (file)
@@ -306,6 +306,8 @@ void GPU_lamp_update_buffer_mats(GPULamp *lamp);
 void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]);
 void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp);
 int GPU_lamp_shadow_buffer_type(GPULamp *lamp);
+int GPU_lamp_shadow_bind_code(GPULamp *lamp);
+float *GPU_lamp_dynpersmat(GPULamp *lamp);
 
 void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]);
 void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy);
index 2c5054c0d622ca3f7c34f3b99c7fa2f48881566a..29e49ca89d33a2f4e16647aa1cd70fb2a2a2311c 100644 (file)
@@ -2275,6 +2275,16 @@ int GPU_lamp_shadow_buffer_type(GPULamp *lamp)
        return lamp->la->shadowmap_type;
 }
 
+int GPU_lamp_shadow_bind_code(GPULamp *lamp)
+{
+       return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1;
+}
+
+float *GPU_lamp_dynpersmat(GPULamp *lamp)
+{
+       return lamp->dynpersmat ? (float *)lamp->dynpersmat : NULL;
+}
+
 int GPU_lamp_shadow_layer(GPULamp *lamp)
 {
        if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW)))
index f542525dd1ed3286892dcbf32383f5b0686fd79b..0f55438ecf6bb188c0fb3003406f4929e6ed9b43 100644 (file)
@@ -1432,6 +1432,15 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l
        lightobj->m_color[2] = la->b;
        lightobj->m_distance = la->dist;
        lightobj->m_energy = la->energy;
+       lightobj->m_shadowclipstart = la->clipsta;
+       lightobj->m_shadowclipend = la->clipend;
+       lightobj->m_shadowbias = la->bias;
+       lightobj->m_shadowbleedbias = la->bleedbias;
+       lightobj->m_shadowmaptype = la->shadowmap_type;
+       lightobj->m_shadowfrustumsize = la->shadow_frustum_size;
+       lightobj->m_shadowcolor[0] = la->shdwr;
+       lightobj->m_shadowcolor[1] = la->shdwg;
+       lightobj->m_shadowcolor[2] = la->shdwb;
        lightobj->m_layer = layerflag;
        lightobj->m_spotblend = la->spotblend;
        lightobj->m_spotsize = la->spotsize;
index b681f10804ad375e109d0e6bd3e1626acf61eb96..9ccf60b15ce0bd1ea21589abdc77825c2c96988d 100644 (file)
@@ -158,6 +158,16 @@ PyAttributeDef KX_LightObject::Attributes[] = {
        KX_PYATTRIBUTE_RW_FUNCTION("quad_attenuation", KX_LightObject, pyattr_get_quad_attenuation, pyattr_set_quad_attenuation),
        KX_PYATTRIBUTE_RW_FUNCTION("spotsize", KX_LightObject, pyattr_get_spotsize, pyattr_set_spotsize),
        KX_PYATTRIBUTE_RW_FUNCTION("spotblend", KX_LightObject, pyattr_get_spotblend, pyattr_set_spotblend),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowClipStart", KX_LightObject, pyattr_get_shadow_clip_start),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowClipEnd", KX_LightObject, pyattr_get_shadow_clip_end),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowFrustumSize", KX_LightObject, pyattr_get_shadow_frustum_size),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowBias", KX_LightObject, pyattr_get_shadow_bias),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowBleedBias", KX_LightObject, pyattr_get_shadow_bleed_bias),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowBindId", KX_LightObject, pyattr_get_shadow_bind_code),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowMapType", KX_LightObject, pyattr_get_shadow_map_type),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowColor", KX_LightObject, pyattr_get_shadow_color),
+       KX_PYATTRIBUTE_RO_FUNCTION("useShadow", KX_LightObject, pyattr_get_shadow_active),
+       KX_PYATTRIBUTE_RO_FUNCTION("shadowMatrix", KX_LightObject, pyattr_get_shadow_matrix),
        KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst),
        KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst),
        KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst),
@@ -219,6 +229,66 @@ int KX_LightObject::pyattr_set_energy(void *self_v, const KX_PYATTRIBUTE_DEF *at
        return PY_SET_ATTR_FAIL;
 }
 
+PyObject *KX_LightObject::pyattr_get_shadow_clip_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyFloat_FromDouble(self->m_lightobj->m_shadowclipstart);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_clip_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyFloat_FromDouble(self->m_lightobj->m_shadowclipend);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_frustum_size(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyFloat_FromDouble(self->m_lightobj->m_shadowfrustumsize);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_bind_code(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyLong_FromLong(self->m_lightobj->GetShadowBindCode());
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyFloat_FromDouble(self->m_lightobj->m_shadowbias);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_bleed_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyFloat_FromDouble(self->m_lightobj->m_shadowbleedbias);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_map_type(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyLong_FromLong(self->m_lightobj->m_shadowmaptype);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyObjectFrom(self->m_lightobj->GetShadowMatrix());
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyColorFromVector(MT_Vector3(self->m_lightobj->m_shadowcolor));
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_active(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+       return PyBool_FromLong(self->m_lightobj->HasShadowBuffer());
+}
+
 PyObject *KX_LightObject::pyattr_get_distance(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
        KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
index 3a58584223dbd998ec753a4765292a001664a7cf..b446acd6e63ebb0159379b56e0eaf60bd60ba375 100644 (file)
@@ -70,6 +70,16 @@ public:
        static int                      pyattr_set_layer(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
        static PyObject*        pyattr_get_energy(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static int                      pyattr_set_energy(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject         *pyattr_get_shadow_clip_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_clip_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_frustum_size(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_bind_code(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_bleed_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_map_type(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_active(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static PyObject         *pyattr_get_shadow_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static PyObject*        pyattr_get_distance(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static int                      pyattr_set_distance(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
        static PyObject*        pyattr_get_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
index f087f3bbb70a2af5b9cac5074642fa98cb3d4091..59475200a73d67054ef879944c9c69afdc9d3909 100644 (file)
@@ -38,6 +38,7 @@ class KX_Camera;
 class KX_Scene;
 
 class MT_Transform;
+class MT_Matrix4x4;
 
 struct Image;
 
@@ -56,6 +57,13 @@ public:
        
        float   m_energy;
        float   m_distance;
+       float   m_shadowclipstart;
+       float   m_shadowfrustumsize;
+       float   m_shadowclipend;
+       float   m_shadowbias;
+       float   m_shadowbleedbias;
+       short   m_shadowmaptype;
+       float   m_shadowcolor[3];
 
        float   m_color[3];
 
@@ -74,6 +82,8 @@ public:
        virtual RAS_ILightObject* Clone() = 0;
 
        virtual bool HasShadowBuffer() = 0;
+       virtual int GetShadowBindCode() = 0;
+       virtual MT_Matrix4x4 GetShadowMatrix() = 0;
        virtual int GetShadowLayer() = 0;
        virtual void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans) = 0;
        virtual void UnbindShadowBuffer() = 0;
index 8319b75331f1341a53c9bacdd064c398732ac3dc..beb2d67f9f53fc73aefedd0af8f496b1467f8638 100644 (file)
@@ -177,6 +177,26 @@ bool RAS_OpenGLLight::HasShadowBuffer()
                return false;
 }
 
+int RAS_OpenGLLight::GetShadowBindCode()
+{
+       GPULamp *lamp;
+       
+       if ((lamp = GetGPULamp()))
+               return GPU_lamp_shadow_bind_code(lamp);
+       return -1;
+}
+
+MT_Matrix4x4 RAS_OpenGLLight::GetShadowMatrix()
+{
+       GPULamp *lamp;
+
+       if ((lamp = GetGPULamp()))
+               return MT_Matrix4x4(GPU_lamp_dynpersmat(lamp));
+       MT_Matrix4x4 mat;
+       mat.setIdentity();
+       return mat;
+}
+
 int RAS_OpenGLLight::GetShadowLayer()
 {
        GPULamp *lamp;
index 0c4e5bf41c4b5a855cf7480f1a564c04654b1ad2..a520b18c434abaafab772affc09a5c3300d244e5 100644 (file)
@@ -46,6 +46,8 @@ public:
        RAS_OpenGLLight* Clone() { return new RAS_OpenGLLight(*this); }
 
        bool HasShadowBuffer();
+       int GetShadowBindCode();
+       MT_Matrix4x4 GetShadowMatrix();
        int GetShadowLayer();
        void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans);
        void UnbindShadowBuffer();