Cycles: Calculate face normal on the fly.

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.
This commit is contained in:
Thomas Dinges 2014-06-13 21:27:21 +02:00
parent cd5e1ff74e
commit 49df707496
8 changed files with 37 additions and 37 deletions

@ -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 {

@ -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;

@ -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 */

@ -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 {

@ -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)

@ -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();

@ -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);

@ -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;