diff options
Diffstat (limited to 'intern/cycles/render/mesh_displace.cpp')
-rw-r--r-- | intern/cycles/render/mesh_displace.cpp | 160 |
1 files changed, 146 insertions, 14 deletions
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index 95f46ff02a2..ef9cfedd412 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -26,19 +26,27 @@ CCL_NAMESPACE_BEGIN +static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts) +{ + float3 v0 = verts[t.v[0]]; + float3 v1 = verts[t.v[1]]; + float3 v2 = verts[t.v[2]]; + + float3 norm = cross(v1 - v0, v2 - v0); + float normlen = len(norm); + + if(normlen == 0.0f) + return make_float3(1.0f, 0.0f, 0.0f); + + return norm / normlen; +} + bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress) { /* verify if we have a displacement shader */ - bool has_displacement = false; - - if(mesh->displacement_method != Mesh::DISPLACE_BUMP) { - foreach(Shader *shader, mesh->used_shaders) - if(shader->has_displacement) - has_displacement = true; - } - - if(!has_displacement) + if(!mesh->has_true_displacement()) { return false; + } string msg = string_printf("Computing Displacement %s", mesh->name.c_str()); progress.set_status("Updating Mesh", msg); @@ -67,8 +75,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; - if(!shader->has_displacement) + if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { continue; + } for(int j = 0; j < 3; j++) { if(done[t.v[j]]) @@ -153,8 +162,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; - if(!shader->has_displacement) + if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { continue; + } for(int j = 0; j < 3; j++) { if(!done[t.v[j]]) { @@ -178,9 +188,131 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); - if(mesh->displacement_method == Mesh::DISPLACE_TRUE) { - mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); - mesh->add_vertex_normals(); + bool need_recompute_vertex_normals = false; + + foreach(Shader *shader, mesh->used_shaders) { + if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) { + need_recompute_vertex_normals = true; + break; + } + } + + if(need_recompute_vertex_normals) { + bool flip = mesh->transform_negative_scaled; + vector<bool> tri_has_true_disp(num_triangles, false); + + for(size_t i = 0; i < num_triangles; i++) { + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) ? + mesh->used_shaders[shader_index] : scene->default_surface; + + tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE; + } + + /* static vertex normals */ + + /* get attributes */ + Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL); + Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + + float3 *fN = attr_fN->data_float3(); + float3 *vN = attr_vN->data_float3(); + + /* compute vertex normals */ + + /* zero vertex normals on triangles with true displacement */ + for(size_t i = 0; i < num_triangles; i++) { + if(tri_has_true_disp[i]) { + for(size_t j = 0; j < 3; j++) { + vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f); + } + } + } + + /* add face normals to vertex normals */ + for(size_t i = 0; i < num_triangles; i++) { + if(tri_has_true_disp[i]) { + for(size_t j = 0; j < 3; j++) { + vN[mesh->get_triangle(i).v[j]] += fN[i]; + } + } + } + + /* normalize vertex normals */ + done.clear(); + done.resize(num_verts, false); + + for(size_t i = 0; i < num_triangles; i++) { + if(tri_has_true_disp[i]) { + for(size_t j = 0; j < 3; j++) { + int vert = mesh->get_triangle(i).v[j]; + + if(done[vert]) { + continue; + } + + vN[vert] = normalize(vN[vert]); + if(flip) + vN[vert] = -vN[vert]; + + done[vert] = true; + } + } + } + + /* motion vertex normals */ + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + + if(mesh->has_motion_blur() && attr_mP && attr_mN) { + for(int step = 0; step < mesh->motion_steps - 1; step++) { + float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); + float3 *mN = attr_mN->data_float3() + step*mesh->verts.size(); + + /* compute */ + + /* zero vertex normals on triangles with true displacement */ + for(size_t i = 0; i < num_triangles; i++) { + if(tri_has_true_disp[i]) { + for(size_t j = 0; j < 3; j++) { + mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f); + } + } + } + + /* add face normals to vertex normals */ + for(size_t i = 0; i < num_triangles; i++) { + if(tri_has_true_disp[i]) { + for(size_t j = 0; j < 3; j++) { + float3 fN = compute_face_normal(mesh->get_triangle(i), mP); + mN[mesh->get_triangle(i).v[j]] += fN; + } + } + } + + /* normalize vertex normals */ + done.clear(); + done.resize(num_verts, false); + + for(size_t i = 0; i < num_triangles; i++) { + if(tri_has_true_disp[i]) { + for(size_t j = 0; j < 3; j++) { + int vert = mesh->get_triangle(i).v[j]; + + if(done[vert]) { + continue; + } + + mN[vert] = normalize(mN[vert]); + if(flip) + mN[vert] = -mN[vert]; + + done[vert] = true; + } + } + } + } + } } return true; |