Object Info node support for GLSL mode and the internal render
authorAlexander Romanov <a.romanov@blend4web.com>
Fri, 14 Apr 2017 15:13:44 +0000 (18:13 +0300)
committerAlexander Romanov <a.romanov@blend4web.com>
Fri, 14 Apr 2017 15:15:57 +0000 (18:15 +0300)
Object Info node can be useful to give some variation to a single material assigned to multiple instances. This patch adds support for Viewport and BI.

{F499530}

Example: {F499528}

Reviewers: merwin, brecht, dfelinto

Reviewed By: brecht

Subscribers: duarteframos, fclem, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov

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

20 files changed:
intern/cycles/blender/blender_object.cpp
release/scripts/startup/nodeitems_builtins.py
source/blender/blenkernel/intern/object_dupli.c
source/blender/blenlib/BLI_hash.h [new file with mode: 0644]
source/blender/gpu/GPU_material.h
source/blender/gpu/intern/gpu_codegen.c
source/blender/gpu/intern/gpu_draw.c
source/blender/gpu/intern/gpu_material.c
source/blender/gpu/intern/gpu_shader.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/intern/rna_object.c
source/blender/nodes/shader/nodes/node_shader_object_info.c
source/blender/render/extern/include/RE_pipeline.h
source/blender/render/extern/include/RE_shader_ext.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/source/renderdatabase.c
source/blender/render/intern/source/shadeoutput.c
source/blenderplayer/bad_level_call_stubs/stubs.c
source/gameengine/Ketsji/BL_BlenderShader.cpp

index d05699236cc404b8c03463f1ac3816853bc36d60..2810ad15b9a0dbb39609a4928219784d6c5c2bd7 100644 (file)
@@ -379,27 +379,16 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
                        }
                }
 
-               /* random number */
-               object->random_id = hash_string(object->name.c_str());
-
-               if(persistent_id) {
-                       for(int i = 0; i < OBJECT_PERSISTENT_ID_SIZE; i++)
-                               object->random_id = hash_int_2d(object->random_id, persistent_id[i]);
-               }
-               else
-                       object->random_id = hash_int_2d(object->random_id, 0);
-
-               if(b_parent.ptr.data != b_ob.ptr.data)
-                       object->random_id ^= hash_int(hash_string(b_parent.name().c_str()));
-
-               /* dupli texture coordinates */
+               /* dupli texture coordinates and random_id */
                if(b_dupli_ob) {
                        object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f);
                        object->dupli_uv = get_float2(b_dupli_ob.uv());
+                       object->random_id = b_dupli_ob.random_id();
                }
                else {
                        object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
                        object->dupli_uv = make_float2(0.0f, 0.0f);
+                       object->random_id =  hash_int_2d(hash_string(object->name.c_str()), 0);
                }
 
                object->tag_update(scene);
index afc6e5455c49567c1d7ef334443f493f8a3faf0b..517a0738b445ab1524f4080cdf32f2d89a2df52d 100644 (file)
@@ -157,6 +157,7 @@ shader_node_categories = [
         NodeItem("ShaderNodeGeometry"),
         NodeItem("ShaderNodeExtendedMaterial"),
         NodeItem("ShaderNodeParticleInfo"),
+        NodeItem("ShaderNodeObjectInfo"),
         NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
         ]),
     ShaderOldNodeCategory("SH_OUTPUT", "Output", items=[
index e3b801b319336a749ce4c53f05ab1211331c5a1d..eb7abc2f0046bcb35413ecbce96613c7bf571efc 100644 (file)
@@ -64,6 +64,7 @@
 
 
 #include "BLI_strict_flags.h"
+#include "BLI_hash.h"
 
 /* Dupli-Geometry */
 
@@ -180,6 +181,22 @@ static DupliObject *make_dupli(const DupliContext *ctx,
        if (ob->type == OB_MBALL)
                dob->no_draw = true;
 
+       /* random number */
+       /* the logic here is designed to match Cycles */
+       dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
+
+       if (dob->persistent_id[0] != INT_MAX) {
+               for(i = 0; i < MAX_DUPLI_RECUR*2; i++)
+                       dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
+       }
+       else {
+               dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
+       }
+
+       if (ctx->object != ob) {
+               dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
+       }
+
        return dob;
 }
 
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
new file mode 100644 (file)
index 0000000..551143f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_HASH_H__
+#define __BLI_HASH_H__
+
+/** \file BLI_hash.h
+ *  \ingroup bli
+ */
+
+static inline unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
+{
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+       unsigned int a, b, c;
+
+       a = b = c = 0xdeadbeef + (2 << 2) + 13;
+       a += kx;
+       b += ky;
+
+       c ^= b; c -= rot(b,14);
+       a ^= c; a -= rot(c,11);
+       b ^= a; b -= rot(a,25);
+       c ^= b; c -= rot(b,16);
+       a ^= c; a -= rot(c,4);
+       b ^= a; b -= rot(a,14);
+       c ^= b; c -= rot(b,24);
+
+       return c;
+
+#undef rot
+}
+
+static inline unsigned int BLI_hash_string(const char *str)
+{
+       unsigned int i = 0, c;
+
+       while((c = *str++))
+               i = i * 37 + c;
+
+       return i;
+}
+
+static inline  unsigned int BLI_hash_int(unsigned int k)
+{
+       return BLI_hash_int_2d(k, 0);
+}
+
+#endif // __BLI_HASH_H__
index 0d92d22a173a9baeee794ef756879bdc19b398b1..6db236868321d4ddc00758bcfef13085d8c6ae28 100644 (file)
@@ -98,6 +98,7 @@ typedef enum GPUBuiltin {
        GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
        GPU_LOC_TO_VIEW_MATRIX =    (1 << 13),
        GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
+       GPU_OBJECT_INFO =           (1 << 15)
 } GPUBuiltin;
 
 typedef enum GPUOpenGLBuiltin {
@@ -213,6 +214,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
 
 void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
 void GPU_material_enable_alpha(GPUMaterial *material);
+GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
 GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
 
 /* High level functions to create and use GPU materials */
@@ -230,7 +232,7 @@ void GPU_material_bind(
         float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
 void GPU_material_bind_uniforms(
         GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
-        float autobumpscale, GPUParticleInfo *pi);
+        float autobumpscale, GPUParticleInfo *pi, float object_info[3]);
 void GPU_material_unbind(GPUMaterial *material);
 bool GPU_material_bound(GPUMaterial *material);
 struct Scene *GPU_material_scene(GPUMaterial *material);
@@ -345,6 +347,7 @@ struct GPUParticleInfo
        float location[3];
        float velocity[3];
        float angular_velocity[3];
+       int random_id;
 };
 
 #ifdef WITH_OPENSUBDIV
index c3896fbd65946e5fabd79b7bcc6e7ee73d89e806..b5512aa108d7e4531f789df3e5b468f9980d9dea 100644 (file)
@@ -410,6 +410,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
                return "unfparticlevel";
        else if (builtin == GPU_PARTICLE_ANG_VELOCITY)
                return "unfparticleangvel";
+       else if (builtin == GPU_OBJECT_INFO)
+               return "unfobjectinfo";
        else
                return "";
 }
index 074fadf600354472d5da3c736850fa8aa0a86ed0..79934190cbcbcc0ccc345c395a61686dad387c49 100644 (file)
@@ -45,6 +45,7 @@
 #include "BLI_math.h"
 #include "BLI_threads.h"
 #include "BLI_utildefines.h"
+#include "BLI_hash.h"
 
 #include "DNA_lamp_types.h"
 #include "DNA_material_types.h"
@@ -1899,6 +1900,21 @@ static int gpu_get_particle_info(GPUParticleInfo *pi)
                return 0;
 }
 
+static void GPU_get_object_info(float oi[3], Material *mat)
+{
+       Object *ob = GMS.gob;
+       oi[0] = ob->index;
+       oi[1] = mat->index;
+       unsigned int random;
+       if (GMS.dob) {
+               random = GMS.dob->random_id;
+       }
+       else {
+               random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0);
+       }
+       oi[2] = random * (1.0f/(float)0xFFFFFFFF);
+}
+
 int GPU_object_material_bind(int nr, void *attribs)
 {
        GPUVertexAttribs *gattribs = attribs;
@@ -1958,6 +1974,7 @@ int GPU_object_material_bind(int nr, void *attribs)
                        /* bind glsl material and get attributes */
                        Material *mat = GMS.gmatbuf[nr];
                        GPUParticleInfo partile_info;
+                       float object_info[3] = {0};
 
                        float auto_bump_scale;
 
@@ -1967,13 +1984,17 @@ int GPU_object_material_bind(int nr, void *attribs)
                        if (GMS.dob) {
                                gpu_get_particle_info(&partile_info);
                        }
+                       
+                       if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) {
+                               GPU_get_object_info(object_info, mat);
+                       }
 
                        GPU_material_bind(
                                gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
                                GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
 
                        auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
-                       GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info);
+                       GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
                        GMS.gboundmat = mat;
 
                        /* for glsl use alpha blend mode, unless it's set to solid and
index d3ea8e13691529d7ce893b7705f455b101eab742..1f3ae7f708a1f8ae15686c9564798b6fac0fd296 100644 (file)
@@ -122,6 +122,8 @@ struct GPUMaterial {
        int partvel;
        int partangvel;
 
+       int objectinfoloc;
+
        ListBase lamps;
        bool bound;
 
@@ -268,6 +270,8 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam
                        material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY));
                if (material->builtins & GPU_PARTICLE_ANG_VELOCITY)
                        material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
+               if (material->builtins & GPU_OBJECT_INFO)
+                       material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO));
                return 1;
        }
        else {
@@ -398,9 +402,14 @@ void GPU_material_bind(
        }
 }
 
+GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
+{
+       return material->builtins;
+}
+
 void GPU_material_bind_uniforms(
         GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
-        float autobumpscale, GPUParticleInfo *pi)
+        float autobumpscale, GPUParticleInfo *pi, float object_info[3])
 {
        if (material->pass) {
                GPUShader *shader = GPU_pass_shader(material->pass);
@@ -449,6 +458,9 @@ void GPU_material_bind_uniforms(
                if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) {
                        GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity);
                }
+               if (material->builtins & GPU_OBJECT_INFO) {
+                       GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info);
+               }
 
        }
 }
index 14f2764b0095c9ac2d42587c37a59f455e72eec2..b579f87698c98d747921f529d587c510bdb2cb2a 100644 (file)
@@ -39,6 +39,7 @@
 #include "GPU_glew.h"
 #include "GPU_shader.h"
 #include "GPU_texture.h"
+#include "GPU_material.h"
 
 /* TODO(sergey): Find better default values for this constants. */
 #define MAX_DEFINE_LENGTH 1024
index 0f3ffa8244b0dcf5f6ccc6d29ce614516a3d488e..c354b274f00beda3c163f658cdcc77cfa39a2cd2 100644 (file)
@@ -3563,12 +3563,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out
        constant = strength;
 }
 
-void node_object_info(out vec3 location, out float object_index, out float material_index, out float random)
+void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random)
 {
-       location = vec3(0.0);
-       object_index = 0.0;
-       material_index = 0.0;
-       random = 0.0;
+       location = obmat[3].xyz;
+       object_index = info.x;
+       material_index = info.y;
+       random = info.z;
 }
 
 void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
index d24c7faa9f55a0221381382f78d5c2a51e637072..6d79e6d49f8bb534fb08ae832371cf0ef19cd94b 100644 (file)
@@ -335,6 +335,8 @@ typedef struct DupliObject {
 
        /* particle this dupli was generated from */
        struct ParticleSystem *particle_system;
+       unsigned int random_id;
+       unsigned int pad;
 } DupliObject;
 
 /* **************** OBJECT ********************* */
index b3c166a68109e57426505d8acfa6536180e15af3..ec6a03e713dc3844eb72d073a5d33ff0c69962d9 100644 (file)
@@ -2897,6 +2897,10 @@ static void rna_def_dupli_object(BlenderRNA *brna)
        RNA_def_property_enum_items(prop, dupli_items);
        RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
        RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
+
+       prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object");
 }
 
 static void rna_def_object_base(BlenderRNA *brna)
index d1905246fd492422d40219e5b8f0413651a2e0c0..165d565a5b40388fba75ab2b92e1a8689e4f5ab9 100644 (file)
@@ -39,7 +39,16 @@ static bNodeSocketTemplate sh_node_object_info_out[] = {
 
 static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
 {
-       return GPU_stack_link(mat, "node_object_info", in, out);
+       return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO));
+}
+
+static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
+{
+       ShaderCallData *scd = (ShaderCallData *)data;
+       copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]);
+       out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi);
+       out[2]->vec[0] = scd->shi->mat->index;
+       out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f/(float)0xFFFFFFFF);;
 }
 
 /* node type definition */
@@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void)
        node_type_init(&ntype, NULL);
        node_type_storage(&ntype, "", NULL, NULL);
        node_type_gpu(&ntype, node_shader_gpu_object_info);
+       node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info);
 
        nodeRegisterType(&ntype);
 }
index f535aa5aa71a34e546b4f347fe6f8c88b3b324cd..eaa4cf2c69c1f9a6d424a4cdeeec22f538a96df8 100644 (file)
@@ -381,7 +381,7 @@ bool RE_allow_render_generic_object(struct Object *ob);
 /* RE_updateRenderInstances flag */
 enum {
        RE_OBJECT_INSTANCES_UPDATE_VIEW  = (1 << 0),
-       RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1),
+       RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1)
 };
 void RE_updateRenderInstances(Render *re, int flag);
 
index ae389fdfd2e9f41e16cfe0dd6c61706dfb57b2ae..b64c0c8fc5253c8aa079a72ff9ce25ed2e931450 100644 (file)
@@ -178,6 +178,7 @@ typedef struct ShadeInput {
        
        unsigned int lay;
        int layflag, passflag, combinedflag;
+       short object_pass_index;
        struct Group *light_override;
        struct Material *mat_override;
 
@@ -241,6 +242,9 @@ enum {
 
 const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4];
 
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi);
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi);
+
 enum {
        RE_VIEW_MATRIX,
        RE_VIEWINV_MATRIX,
index b3a5ccdae170af19ea30384daa710e6b166cac62..f032334089935a65c10be20506f5f0dae9720143 100644 (file)
@@ -382,6 +382,8 @@ typedef struct ObjectInstanceRen {
        float part_co[3];
        float part_vel[3];
        float part_avel[3];
+
+       unsigned int random_id;
 } ObjectInstanceRen;
 
 /* ------------------------------------------------------------------------- */
index 76e6ca8d467edd84f28b4c3209112dee0bddc3fd..199322795f322ffd00a5d049f5cb2657e1f87741 100644 (file)
@@ -66,6 +66,7 @@
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
+#include "BLI_hash.h"
 
 #include "DNA_material_types.h" 
 #include "DNA_meshdata_types.h" 
@@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance(
                }
        }
 
+       /* Fill object info */
+       if (dob) {
+               obi->random_id = dob->random_id;
+       }
+       else {
+               obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
+       }
+
        RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
 
        if (mat) {
index a8fb72fb7f866786182797b432bc5edfb7456f36..8dea0930b9e63e123847fc41fe7d9854e818a4ef 100644 (file)
@@ -2141,6 +2141,16 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m
        return NULL;
 }
 
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
+{
+       return obi->ob->index;
+}
+
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
+{
+       return obi->random_id;
+}
+
 const float (*RE_render_current_get_matrix(int matrix_id))[4]
 {
        switch (matrix_id) {
index 8c652565c0bb5f907f02d9d878e2a68220cf34e5..5400abc47915b1b1d47167cb62599ee4ee2bd5a3 100644 (file)
@@ -274,6 +274,7 @@ struct Object *RE_GetCamera(struct Render *re) RET_NULL
 float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
 const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL
 const float (*RE_render_current_get_matrix(int matrix_id))[4] RET_NULL
+const float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) RET_ZERO
 
 /* blenkernel */
 bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO
index 95679b5d3a613ad442d93eff7d82dc0c0a5ce008..9cbd61590b6dea9bcecaffb256ba3f84a96add09 100644 (file)
@@ -169,7 +169,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
 
        rasty->GetViewMatrix().getValue(&viewmat[0][0]);
        float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f;
-       GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL);
+       GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL, NULL);
 
        mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol);
 }