Cycles: Calculate face normal on the fly.
authorThomas Dinges <blender@dingto.org>
Fri, 13 Jun 2014 19:27:21 +0000 (21:27 +0200)
committerThomas Dinges <blender@dingto.org>
Fri, 13 Jun 2014 19:59:13 +0000 (21:59 +0200)
Instead of pre-calculation and storage, we now calculate the face normal during render.
This gives a small slowdown (~1%) but decreases memory usage, which is especially important for GPUs,
where you have limited VRAM.

Part of my GSoC 2014.

intern/cycles/kernel/geom/geom_bvh_shadow.h
intern/cycles/kernel/geom/geom_motion_triangle.h
intern/cycles/kernel/geom/geom_triangle.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_textures.h
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h
intern/cycles/render/scene.h

index 48876da049e8289a347f96f5d11e1ce8794704db..1f6e4942fab0fde76ee4ac4f118ae76c2ab938ba 100644 (file)
@@ -252,8 +252,7 @@ ccl_device bool BVH_FUNCTION_NAME
                                                        if(kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
 #endif
                                                        {
-                                                               float4 Ns = kernel_tex_fetch(__tri_normal, prim);
-                                                               shader = __float_as_int(Ns.w);
+                                                               shader =  __float_as_int(kernel_tex_fetch(__tri_shader, prim));
                                                        }
 #ifdef __HAIR__
                                                        else {
index 73fcf1adda6b6d2122d9352884c2cd4e5f996bd7..5ab0b731bddf158c9b44c0fe2fbb9bd4caf637df 100644 (file)
@@ -233,8 +233,7 @@ ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, Sh
 ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, bool subsurface)
 {
        /* get shader */
-       float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
-       sd->shader = __float_as_int(Ns.w);
+       sd->shader =  __float_as_int(kernel_tex_fetch(__tri_shader, sd->prim));
 
        /* get motion info */
        int numsteps, numverts;
index 355e36fef0c3b8091f500aef4bf9104849f6dee3..4ee5d5aa6d5c59eeeec5c2844ed2eea4a144e274 100644 (file)
@@ -116,6 +116,20 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, ShaderDat
 #endif
 }
 
+/* normal on triangle  */
+ccl_device_inline float3 triangle_normal(KernelGlobals *kg, int prim)
+{
+       /* load triangle vertices */
+       float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, prim));
+
+       float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
+       float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
+       float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+       
+       /* return normal */
+       return normalize(cross(v1 - v0, v2 - v0));
+}
+
 /* point and normal on triangle  */
 ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int prim, float u, float v, float3 *P, float3 *Ng, int *shader)
 {
@@ -130,9 +144,11 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int prim, float
        float t = 1.0f - u - v;
        *P = (u*v0 + v*v1 + t*v2);
 
-       float4 Nm = kernel_tex_fetch(__tri_normal, prim);
-       *Ng = make_float3(Nm.x, Nm.y, Nm.z);
-       *shader = __float_as_int(Nm.w);
+       /* compute normal */
+       *Ng = normalize(cross(v1 - v0, v2 - v0));
+
+       /* shader`*/
+       *shader = __float_as_int(kernel_tex_fetch(__tri_shader, prim));
 }
 
 /* Triangle vertex locations */
index c6a7f9f1570a0da920d447106c6a33f8d921046d..0ea21a85fcb51ef50512def792e3f22984193c8a 100644 (file)
@@ -86,9 +86,8 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 #endif
        if(sd->type & PRIMITIVE_TRIANGLE) {
                /* static triangle */
-               float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
-               float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
-               sd->shader = __float_as_int(Ns.w);
+               float3 Ng = triangle_normal(kg, sd->prim);
+               sd->shader =  __float_as_int(kernel_tex_fetch(__tri_shader, sd->prim));
 
                /* vectors */
                sd->P = triangle_refine(kg, sd, isect, ray);
@@ -166,9 +165,8 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
 
        /* fetch triangle data */
        if(sd->type == PRIMITIVE_TRIANGLE) {
-               float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
-               float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
-               sd->shader = __float_as_int(Ns.w);
+               float3 Ng = triangle_normal(kg, sd->prim);
+               sd->shader =  __float_as_int(kernel_tex_fetch(__tri_shader, sd->prim));
 
                /* static triangle */
                sd->P = triangle_refine_subsurface(kg, sd, isect, ray);
@@ -1028,8 +1026,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
 #ifdef __HAIR__
        if(kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
 #endif
-               float4 Ns = kernel_tex_fetch(__tri_normal, prim);
-               shader = __float_as_int(Ns.w);
+               shader = __float_as_int(kernel_tex_fetch(__tri_shader, prim));
 #ifdef __HAIR__
        }
        else {
index b07075c6c958f5de5983e6dd17c18e9317554798..dfef8ed9c663d98c4807be9e610031221fe34e00 100644 (file)
@@ -36,7 +36,7 @@ KERNEL_TEX(float4, texture_float4, __objects)
 KERNEL_TEX(float4, texture_float4, __objects_vector)
 
 /* triangles */
-KERNEL_TEX(float4, texture_float4, __tri_normal)
+KERNEL_TEX(float, texture_float, __tri_shader)
 KERNEL_TEX(float4, texture_float4, __tri_vnormal)
 KERNEL_TEX(float4, texture_float4, __tri_vindex)
 KERNEL_TEX(float4, texture_float4, __tri_verts)
index 9c5ddd5501007c6a79d986eed49d0d9c1298b49f..b6826f0066bf83b3e25628530df50939c053babd 100644 (file)
@@ -377,12 +377,10 @@ void Mesh::add_vertex_normals()
        }
 }
 
-void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
+void Mesh::pack_normals(Scene *scene, float *tri_shader, float4 *vnormal)
 {
-       Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
        Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
 
-       float3 *fN = attr_fN->data_float3();
        float3 *vN = attr_vN->data_float3();
        int shader_id = 0;
        uint last_shader = -1;
@@ -394,24 +392,15 @@ void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
        bool do_transform = transform_applied;
        Transform ntfm = transform_normal;
 
+       /* save shader */
        for(size_t i = 0; i < triangles_size; i++) {
-               float3 fNi = fN[i];
-
-               if(do_transform)
-                       fNi = normalize(transform_direction(&ntfm, fNi));
-
-               normal[i].x = fNi.x;
-               normal[i].y = fNi.y;
-               normal[i].z = fNi.z;
-
-               /* stuff shader id in here too */
                if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
                        last_shader = shader_ptr[i];
                        last_smooth = smooth[i];
                        shader_id = scene->shader_manager->get_shader_id(last_shader, this, last_smooth);
                }
 
-               normal[i].w = __int_as_float(shader_id);
+               tri_shader[i] = __int_as_float(shader_id);
        }
 
        size_t verts_size = verts.size();
@@ -932,13 +921,13 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
                /* normals */
                progress.set_status("Updating Mesh", "Computing normals");
 
-               float4 *normal = dscene->tri_normal.resize(tri_size);
+               float *tri_shader = dscene->tri_shader.resize(tri_size);
                float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
                float4 *tri_verts = dscene->tri_verts.resize(vert_size);
                float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
 
                foreach(Mesh *mesh, scene->meshes) {
-                       mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]);
+                       mesh->pack_normals(scene, &tri_shader[mesh->tri_offset], &vnormal[mesh->vert_offset]);
                        mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
 
                        if(progress.get_cancel()) return;
@@ -947,7 +936,7 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
                /* vertex coordinates */
                progress.set_status("Updating Mesh", "Copying Mesh to device");
 
-               device->tex_alloc("__tri_normal", dscene->tri_normal);
+               device->tex_alloc("__tri_shader", dscene->tri_shader);
                device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
                device->tex_alloc("__tri_verts", dscene->tri_verts);
                device->tex_alloc("__tri_vindex", dscene->tri_vindex);
@@ -1119,7 +1108,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
        device->tex_free(dscene->prim_visibility);
        device->tex_free(dscene->prim_index);
        device->tex_free(dscene->prim_object);
-       device->tex_free(dscene->tri_normal);
+       device->tex_free(dscene->tri_shader);
        device->tex_free(dscene->tri_vnormal);
        device->tex_free(dscene->tri_vindex);
        device->tex_free(dscene->tri_verts);
@@ -1136,7 +1125,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
        dscene->prim_visibility.clear();
        dscene->prim_index.clear();
        dscene->prim_object.clear();
-       dscene->tri_normal.clear();
+       dscene->tri_shader.clear();
        dscene->tri_vnormal.clear();
        dscene->tri_vindex.clear();
        dscene->tri_verts.clear();
index 247e3dd555e0ad60dc84d04c7930d0a6586a3860..5ee774bacc19512ad0b9939f98ddeaf480ad2a1e 100644 (file)
@@ -120,7 +120,7 @@ public:
        void add_face_normals();
        void add_vertex_normals();
 
-       void pack_normals(Scene *scene, float4 *normal, float4 *vnormal);
+       void pack_normals(Scene *scene, float *shader, float4 *vnormal);
        void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
        void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
        void compute_bvh(SceneParams *params, Progress *progress, int n, int total);
index d657e48e4781f0d776101bae5e3c31185e4b1ddb..777d26ac79ea29f7e82c1014872d42bc94e733dc 100644 (file)
@@ -69,7 +69,7 @@ public:
        device_vector<uint> prim_object;
 
        /* mesh */
-       device_vector<float4> tri_normal;
+       device_vector<float> tri_shader;
        device_vector<float4> tri_vnormal;
        device_vector<float4> tri_vindex;
        device_vector<float4> tri_verts;