Blender Internal: Add "Lamp Data" shader node that allows shaders to acquire information such as light vector from specified Lamp.

For now this provides the following outputs:

- Color
- Light Vector
- Distance
- Shadow
- Visibility Factor

Note: Color output is multiplied by the lamp energy.  Multiplication of
color*max(dot(light_vector,normal_vector),0)*shadow*visibility_factor
produces the exact same result as the Lambert shader.

Many thanks to Brecht for code review and discussion!
This commit is contained in:
Shinsuke Irie 2013-11-25 20:58:23 +09:00
parent 33bc6a3959
commit ab9822eff8
18 changed files with 296 additions and 1 deletions

View File

@ -111,6 +111,7 @@ shader_node_categories = [
ShaderOldNodeCategory("SH_INPUT", "Input", items=[
NodeItem("ShaderNodeMaterial"),
NodeItem("ShaderNodeCameraData"),
NodeItem("ShaderNodeLampData"),
NodeItem("ShaderNodeValue"),
NodeItem("ShaderNodeRGB"),
NodeItem("ShaderNodeTexture"),

View File

@ -740,6 +740,7 @@ struct ShadeResult;
#define SH_NODE_SEPHSV 183
#define SH_NODE_COMBHSV 184
#define SH_NODE_BSDF_HAIR 185
#define SH_NODE_LAMP 186
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1

View File

@ -3435,6 +3435,7 @@ static void registerShaderNodes(void)
register_node_type_sh_output();
register_node_type_sh_material();
register_node_type_sh_camera();
register_node_type_sh_lamp();
register_node_type_sh_gamma();
register_node_type_sh_brightcontrast();
register_node_type_sh_value();

View File

@ -753,6 +753,11 @@ static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA
}
}
static void node_shader_buts_lamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "lamp_object", 0, IFACE_("Lamp Object"), ICON_NONE);
}
static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE);
@ -1002,6 +1007,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_GEOMETRY:
ntype->draw_buttons = node_shader_buts_geometry;
break;
case SH_NODE_LAMP:
ntype->draw_buttons = node_shader_buts_lamp;
break;
case SH_NODE_ATTRIBUTE:
ntype->draw_buttons = node_shader_buts_attribute;
break;

View File

@ -133,6 +133,7 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale);
void GPU_material_unbind(GPUMaterial *material);
int GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
void GPU_material_vertex_attributes(GPUMaterial *material,
struct GPUVertexAttribs *attrib);
@ -244,6 +245,7 @@ void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float ener
void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2);
void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
int GPU_lamp_shadow_layer(GPULamp *lamp);
GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow);
#ifdef __cplusplus
}

View File

@ -355,6 +355,11 @@ int GPU_material_bound(GPUMaterial *material)
return material->bound;
}
Scene *GPU_material_scene(GPUMaterial *material)
{
return material->scene;
}
void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
{
*attribs = material->attribs;
@ -1953,6 +1958,48 @@ int GPU_lamp_shadow_layer(GPULamp *lamp)
return -1;
}
GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow)
{
GPUNodeLink *visifac;
*col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
visifac = lamp_get_visibility(mat, lamp, lv, dist);
shade_light_textures(mat, lamp, col);
if (GPU_lamp_has_shadow_buffer(lamp)) {
GPUNodeLink *vn, *inp;
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &vn);
GPU_link(mat, "shade_inp", vn, *lv, &inp);
mat->dynproperty |= DYN_LAMP_PERSMAT;
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
GPU_link(mat, "shadows_only_vsm",
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias),
GPU_uniform(lamp->shadow_color), inp, shadow);
}
else {
GPU_link(mat, "shadows_only",
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, shadow);
}
}
else {
GPU_link(mat, "set_rgb_one", shadow);
}
/* ensure shadow buffer and lamp textures will be updated */
add_user_list(&mat->lamps, lamp);
add_user_list(&lamp->materials, mat->ma);
return visifac;
}
/* export the GLSL shader */
GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)

View File

@ -166,6 +166,15 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
void lamp(vec4 col, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
{
outcol = col;
outlv = lv;
outdist = dist;
outshadow = vec4(shadow, 1.0);
outvisifac = visifac;
}
void math_add(float val1, float val2, out float outval)
{
outval = val1 + val2;
@ -1973,6 +1982,30 @@ void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float
}
}
void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, vec3 shadowcolor, float inp, out vec3 result)
{
result = vec3(1.0);
if(inp > 0.0) {
float shadfac;
test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac);
result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor);
}
}
void shadows_only_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, vec3 shadowcolor, float inp, out vec3 result)
{
result = vec3(1.0);
if(inp > 0.0) {
float shadfac;
test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac);
result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor);
}
}
void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result)
{

View File

@ -493,6 +493,7 @@ extern StructRNA RNA_ShaderNodeExtendedMaterial;
extern StructRNA RNA_ShaderNodeGeometry;
extern StructRNA RNA_ShaderNodeHueSaturation;
extern StructRNA RNA_ShaderNodeInvert;
extern StructRNA RNA_ShaderNodeLampData;
extern StructRNA RNA_ShaderNodeMapping;
extern StructRNA RNA_ShaderNodeMaterial;
extern StructRNA RNA_ShaderNodeMath;

View File

@ -239,6 +239,7 @@ void rna_TextureSlot_brush_update(struct Main *bmain, struct Scene *scene, struc
int rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Camera_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Curve_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Lamp_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Lattice_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);

View File

@ -3258,6 +3258,19 @@ static void def_sh_geometry(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_sh_lamp(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "lamp_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Lamp_object_poll");
RNA_def_property_ui_text(prop, "Lamp Object", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_sh_attribute(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -1446,6 +1446,11 @@ int rna_Camera_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
return ((Object *)value.id.data)->type == OB_CAMERA;
}
int rna_Lamp_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
return ((Object *)value.id.data)->type == OB_LAMP;
}
int rna_DupliObject_index_get(PointerRNA *ptr)
{
DupliObject *dob = (DupliObject *)ptr->data;

View File

@ -133,6 +133,7 @@ set(SRC
shader/nodes/node_shader_geom.c
shader/nodes/node_shader_hueSatVal.c
shader/nodes/node_shader_invert.c
shader/nodes/node_shader_lamp.c
shader/nodes/node_shader_mapping.c
shader/nodes/node_shader_material.c
shader/nodes/node_shader_math.c

View File

@ -47,6 +47,7 @@ void register_node_type_sh_group(void);
void register_node_type_sh_output(void);
void register_node_type_sh_material(void);
void register_node_type_sh_camera(void);
void register_node_type_sh_lamp(void);
void register_node_type_sh_value(void);
void register_node_type_sh_rgb(void);
void register_node_type_sh_mix_rgb(void);

View File

@ -56,6 +56,7 @@ DefNode( ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPI
DefNode( ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" )
DefNode( ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" )
DefNode( ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" )
DefNode( ShaderNode, SH_NODE_LAMP, def_sh_lamp, "LAMP", LampData, "Lamp Data", "" )
DefNode( ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode( ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode( ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )

View File

@ -0,0 +1,86 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2013 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/nodes/shader/nodes/node_shader_lamp.c
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** LAMP INFO ******************** */
static bNodeSocketTemplate sh_node_lamp_out[] = {
{ SOCK_RGBA, 0, N_("Color")},
{ SOCK_VECTOR, 0, N_("Light Vector")},
{ SOCK_FLOAT, 0, N_("Distance")},
{ SOCK_RGBA, 0, N_("Shadow")},
{ SOCK_FLOAT, 0, N_("Visibility Factor")},
{ -1, 0, "" }
};
static void node_shader_exec_lamp(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
{
if (data) {
Object *ob = (Object *)node->id;
if (ob) {
ShadeInput *shi = ((ShaderCallData *)data)->shi;
shi->nodes = 1; /* temp hack to prevent trashadow recursion */
out[4]->vec[0] = RE_lamp_get_data(shi, ob, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec);
shi->nodes = 0;
}
}
}
static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (node->id) {
GPULamp *lamp = GPU_lamp_from_blender(GPU_material_scene(mat), (Object *)node->id, NULL);
GPUNodeLink *col, *lv, *dist, *visifac, *shadow;
visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow);
return GPU_stack_link(mat, "lamp", in, out, col, lv, dist, shadow, visifac);
}
return 0;
}
void register_node_type_sh_lamp(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_LAMP, "Lamp Data", NODE_CLASS_INPUT, 0);
node_type_compatibility(&ntype, NODE_OLD_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_lamp_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_lamp);
node_type_gpu(&ntype, gpu_shader_lamp);
nodeRegisterType(&ntype);
}

View File

@ -194,6 +194,7 @@ struct Tex;
struct MTex;
struct ImBuf;
struct ImagePool;
struct Object;
/* this one uses nodes */
int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage);
@ -203,11 +204,11 @@ int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres
int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres,
const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex,
struct ImagePool *pool);
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]);
/* shaded view and bake */
struct Render;
struct Image;
struct Object;
int RE_bake_shade_all_selected(struct Render *re, int type, struct Object *actob, short *do_update, float *progress);
struct Image *RE_bake_shade_get_image(void);

View File

@ -1982,3 +1982,94 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
shr->combined[3]= shr->alpha;
}
/* used for "Lamp Data" shader node */
static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[4], float lv[3], float *dist, float shadow[4])
{
LampRen *lar = go->lampren;
float visifac, inp;
if (!lar || lar->type == LA_YF_PHOTON
|| ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0)
|| (lar->lay & shi->lay) == 0)
return 0.0f;
if (lar->mode & LA_TEXTURE)
do_lamp_tex(lar, lv, shi, col, LA_TEXTURE);
visifac = lamp_get_visibility(lar, shi->co, lv, dist);
if (visifac == 0.0f
|| lar->type == LA_HEMI
|| (lar->type != LA_SPOT && !(lar->mode & LA_SHAD_RAY))
|| (R.r.scemode & R_BUTS_PREVIEW))
return visifac;
inp = dot_v3v3(shi->vn, lv);
if (inp > 0.0f) {
float shadfac[4];
shadow[0] = lar->shdwr;
shadow[1] = lar->shdwg;
shadow[2] = lar->shdwb;
if (lar->mode & LA_SHAD_TEX)
do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
}
return visifac;
}
float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4])
{
col[0] = col[1] = col[2] = 0.0f;
col[3] = 1.0f;
copy_v3_v3(lv, shi->vn);
*dist = 1.0f;
shadow[0] = shadow[1] = shadow[2] = shadow[3] = 1.0f;
if (lamp_obj->type == OB_LAMP) {
GroupObject *go;
Lamp *lamp = (Lamp *)lamp_obj->data;
col[0] = lamp->r * lamp->energy;
col[1] = lamp->g * lamp->energy;
col[2] = lamp->b * lamp->energy;
if (R.r.scemode & R_BUTS_PREVIEW) {
for (go = R.lights.first; go; go = go->next) {
/* "Lamp.002" is main key light of material preview */
if (strcmp(go->ob->id.name + 2, "Lamp.002") == 0)
return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
}
return 0.0f;
}
if (shi->light_override) {
for (go = shi->light_override->gobject.first; go; go = go->next) {
if (go->ob == lamp_obj)
return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
}
}
if (shi->mat && shi->mat->group) {
for (go = shi->mat->group->gobject.first; go; go = go->next) {
if (go->ob == lamp_obj)
return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
}
}
for (go = R.lights.first; go; go = go->next) {
if (go->ob == lamp_obj)
return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
}
}
return 0.0f;
}

View File

@ -173,6 +173,7 @@ void modifier_skin_customdata_ensure(struct Object *ob) {STUB_ASSERT(0);}
/* nodes */
struct RenderResult *RE_GetResult(struct Render *re) {STUB_ASSERT(0); return (struct RenderResult *) NULL;}
struct Render *RE_GetRender(const char *name) {STUB_ASSERT(0); return (struct Render *) NULL;}
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[3], float lv[3], float *dist) {STUB_ASSERT(0); return 0.0f;}
/* blenkernel */
void RE_FreeRenderResult(struct RenderResult *res) {STUB_ASSERT(0);}