Bugfix & Feature fix: Only Shadow Material options
authorTon Roosendaal <ton@blender.org>
Tue, 8 Mar 2011 16:08:43 +0000 (16:08 +0000)
committerTon Roosendaal <ton@blender.org>
Tue, 8 Mar 2011 16:08:43 +0000 (16:08 +0000)
Patch from Miika Hämäläinen.

The old Material "Only Shadow" used an ancient 'best guess'
formula using Lamp Distance and some averaging for converting
shadow values to alpha.
A couple of bug reporters already complained about the not
very predictable renders. Miika fixed this by adding two
new options, to only give the true shadow factor exclusively,
or to give a result including light intensity values.

More info:
http://projects.blender.org/tracker/index.php?func=detail&aid=26413&group_id=9&atid=127

release/scripts/ui/properties_material.py
source/blender/makesdna/DNA_material_types.h
source/blender/makesrna/intern/rna_material.c
source/blender/render/intern/source/shadeoutput.c

index d169629b6f614d294aee178d49af4c2bbd6cdaf8..5554390e3a8044120f3bf2e7ff89dd6b171e0035 100644 (file)
@@ -752,10 +752,13 @@ class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel):
         col = split.column()
         col.prop(mat, "use_shadows", text="Receive")
         col.prop(mat, "use_transparent_shadows", text="Receive Transparent")
-        col.prop(mat, "use_only_shadow", text="Shadows Only")
         if simple_material(base_mat):
             col.prop(mat, "use_cast_shadows_only", text="Cast Only")
             col.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
+        col.prop(mat, "use_only_shadow", text="ShadowsOnly")
+        sub = col.column()
+        sub.active = mat.use_only_shadow
+        sub.prop(mat, "shadow_only_type", text="")
 
         col = split.column()
         if simple_material(base_mat):
@@ -771,6 +774,7 @@ class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel):
             col.prop(mat, "use_cast_approximate")
 
 
+
 class MATERIAL_PT_transp_game(MaterialButtonsPanel, bpy.types.Panel):
     bl_label = "Transparency"
     bl_options = {'DEFAULT_CLOSED'}
index 860da1d80a443812371343944a361b03718953d9..1489593f7f624cfbe53d69c9ddcf1b9a8c7117b8 100644 (file)
@@ -160,7 +160,8 @@ typedef struct Material {
        short sss_flag, sss_preset;
 
        int mapto_textured;     /* render-time cache to optimise texture lookups */
-       int pad4;
+       short shadowonly_flag;          /* "shadowsonly" type */
+       short pad;
 
        ListBase gpumaterial;           /* runtime */
 } Material;
@@ -238,6 +239,11 @@ typedef struct Material {
 #define MA_RAYMIR_FADETOSKY    0
 #define MA_RAYMIR_FADETOMAT    1
 
+/* shadowonly_flag */
+#define MA_SO_OLD                      0
+#define MA_SO_SHADOW           1
+#define MA_SO_SHADED           2
+
 /* shade_flag */
 #define MA_CUBIC                       1
 #define MA_OBCOLOR                     2
index ce568c2af631b25caca5961a370e7dd1893c5fe1..179b077032216f7c24c8a84365aabe21ccc77544 100644 (file)
@@ -1583,6 +1583,12 @@ void RNA_def_material(BlenderRNA *brna)
                {MA_SPHERE_A, "SPHERE_A", ICON_MAT_SPHERE_SKY, "Flat", "Preview type: Large sphere with sky"},
                {0, NULL, 0, NULL, NULL}};
 
+       static EnumPropertyItem prop_shadows_only_items[] = {
+               {MA_SO_OLD, "SO_OLD", 0, "Shadow and Distance", ""},
+               {MA_SO_SHADOW, "SO_SHADOW", 0, "Shadow Only", ""},
+               {MA_SO_SHADED, "SO_SHADED", 0, "Shadow and Shading", ""},
+               {0, NULL, 0, NULL, NULL}};
+
        srna= RNA_def_struct(brna, "Material", "ID");
        RNA_def_struct_ui_text(srna, "Material", "Material datablock to defined the appearance of geometric objects for rendering");
        RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA);
@@ -1713,6 +1719,12 @@ void RNA_def_material(BlenderRNA *brna)
        RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_ONLYSHADOW);
        RNA_def_property_ui_text(prop, "Only Shadow", "Renders shadows as the material's alpha value, making materials transparent except for shadowed areas");
        RNA_def_property_update(prop, 0, "rna_Material_update");
+
+       prop= RNA_def_property(srna, "shadow_only_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_bitflag_sdna(prop, NULL, "shadowonly_flag");
+       RNA_def_property_enum_items(prop, prop_shadows_only_items);
+       RNA_def_property_ui_text(prop, "Shadow Type", "How to draw shadows");
+       RNA_def_property_update(prop, 0, "rna_Material_update");
        
        prop= RNA_def_property(srna, "use_face_texture", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_FACETEXTURE);
index 58284534ce900a0ee1485f4e5e1803bae7bf233e..0081f809a0921857e9d8cb414a22ce522edbaab3 100644 (file)
@@ -1502,10 +1502,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                float inpr, lv[3];
                float *view, shadfac[4];
                float ir, accum, visifac, lampdist;
+               float shaded = 0.0f, lightness = 0.0f;
                
 
                view= shi->view;
-
                accum= ir= 0.0f;
                
                lights= get_lights(shi);
@@ -1522,27 +1522,69 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                        if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
                                visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
                                if(visifac <= 0.0f) {
-                                       ir+= 1.0f;
-                                       accum+= 1.0f;
+                                       if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                                               ir+= 1.0f;
+                                               accum+= 1.0f;
+                                       }
                                        continue;
                                }
                                inpr= INPR(shi->vn, lv);
                                if(inpr <= 0.0f) {
-                                       ir+= 1.0f;
-                                       accum+= 1.0f;
+                                       if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                                               ir+= 1.0f;
+                                               accum+= 1.0f;
+                                       }
                                        continue;
-                               }                               
+                               }
+
                                lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
 
-                               ir+= 1.0f;
-                               accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3];
+                               if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                                       /* Old "Shadows Only" */
+                                       ir+= 1.0f;
+                                       accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3];
+                               }
+                               else {
+                                       ir+= lar->energy;
+                                       shaded += rgb_to_grayscale(shadfac)*shadfac[3] * visifac * lar->energy;
+
+                                       if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
+                                               lightness += visifac * lar->energy;
+                                       }
+                               }
                        }
                }
+
+               /* Apply shadows as alpha */
                if(ir>0.0f) {
-                       accum/= ir;
-                       shr->alpha= (shi->mat->alpha)*(1.0f-accum);
+                       if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                               accum = 1.0f - accum/ir;
+                       }
+                       else {
+                               shaded/= ir;
+                               lightness/= ir;
+
+                               if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
+                                       if (lightness > 0.0f) {
+                                               /* Get shadow value from between 0.0f and non-shadowed lightness */
+                                               accum = (lightness - shaded) / (lightness);
+                                       }
+                                       else {
+                                               accum = 0.0f;
+                                       }
+                               }
+                               else { /* shadowonly_flag == MA_SO_SHADED */
+                                       /* Use shaded value */
+                                       accum = 1.0f - shaded;
+                       }}
+
+                       shr->alpha= (shi->mat->alpha)*(accum);
+               }
+               else {
+                       /* If "fully shaded", use full alpha even on areas that have no lights */
+                       if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=1.0f;
+                       else shr->alpha= 0.f;
                }
-               else shr->alpha= 0.f;
        }
        
        /* quite disputable this...  also note it doesn't mirror-raytrace */    
@@ -1551,18 +1593,31 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                
                if(R.wrld.mode & WO_AMB_OCC) {
                        f= R.wrld.aoenergy*shi->amb;
-
+                       
                        if(R.wrld.aomix==WO_AOADD) {
-                               f= f*(1.0f - rgb_to_grayscale(shi->ao));
-                               shr->alpha= (shr->alpha + f)*f;
+                               if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                                       f= f*(1.0f - rgb_to_grayscale(shi->ao));
+                                       shr->alpha= (shr->alpha + f)*f;
+                               }
+                               else {
+                                       shr->alpha -= f*rgb_to_grayscale(shi->ao);
+                                       if (shr->alpha<0.0f) shr->alpha=0.0f;
+                               }
                        }
-                       else
+                       else /* AO Multiply */
                                shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*rgb_to_grayscale(shi->ao));
                }
 
                if(R.wrld.mode & WO_ENV_LIGHT) {
-                       f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env));
-                       shr->alpha= (shr->alpha + f)*f;
+                       if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                               f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env));
+                               shr->alpha= (shr->alpha + f)*f;
+                       }
+                       else {
+                               f= R.wrld.ao_env_energy*shi->amb;
+                               shr->alpha -= f*rgb_to_grayscale(shi->env);
+                               if (shr->alpha<0.0f) shr->alpha=0.0f;
+                       }
                }
        }
 }