Cycles microdisplacement: Move displacement options from mesh to material settings

Displacement is now a per material setting, which means old files will have to
be updated if they had used displacement. Cool side effect of this change is
material previews now show displacement.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2140
This commit is contained in:
Mai Lavelle 2016-08-02 05:13:58 -04:00
parent dd1929754f
commit a58fe05c05
10 changed files with 201 additions and 89 deletions

@ -775,6 +775,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
default='LINEAR',
)
cls.displacement_method = EnumProperty(
name="Displacement Method",
description="Method to use for the displacement",
items=enum_displacement_methods,
default='BUMP',
)
@classmethod
def unregister(cls):
del bpy.types.Material.cycles
@ -952,13 +959,6 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
type=cls,
)
cls.displacement_method = EnumProperty(
name="Displacement Method",
description="Method to use for the displacement",
items=enum_displacement_methods,
default='BUMP',
)
@classmethod
def unregister(cls):
del bpy.types.Mesh.cycles

@ -674,40 +674,6 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
split.separator()
class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
bl_label = "Displacement"
bl_context = "data"
@classmethod
def poll(cls, context):
if CyclesButtonsPanel.poll(context):
if context.mesh or context.curve or context.meta_ball:
if context.scene.cycles.feature_set == 'EXPERIMENTAL':
return True
return False
def draw(self, context):
layout = self.layout
mesh = context.mesh
curve = context.curve
mball = context.meta_ball
if mesh:
cdata = mesh.cycles
elif curve:
cdata = curve.cycles
elif mball:
cdata = mball.cycles
split = layout.split()
col = split.column()
sub = col.column(align=True)
sub.label(text="Displacement:")
sub.prop(cdata, "displacement_method", text="")
class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
bl_label = "Motion Blur"
bl_context = "object"
@ -1219,6 +1185,11 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
col.prop(cmat, "sample_as_light", text="Multiple Importance")
col.prop(cmat, "use_transparent_shadow")
if context.scene.cycles.feature_set == 'EXPERIMENTAL':
col.separator()
col.label(text="Displacement:")
col.prop(cmat, "displacement_method", text="")
col = split.column()
col.label(text="Volume:")
sub = col.column()

@ -1008,21 +1008,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
}
mesh->geometry_flags = requested_geometry_flags;
/* displacement method */
if(cmesh.data) {
const int method = get_enum(cmesh,
"displacement_method",
Mesh::DISPLACE_NUM_METHODS,
Mesh::DISPLACE_BUMP);
if(method == 0 || !experimental)
mesh->displacement_method = Mesh::DISPLACE_BUMP;
else if(method == 1)
mesh->displacement_method = Mesh::DISPLACE_TRUE;
else
mesh->displacement_method = Mesh::DISPLACE_BOTH;
}
/* fluid motion */
sync_mesh_fluid_motion(b_ob, scene, mesh);

@ -64,6 +64,14 @@ static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
VOLUME_INTERPOLATION_LINEAR);
}
static DisplacementMethod get_displacement_method(PointerRNA& ptr)
{
return (DisplacementMethod)get_enum(ptr,
"displacement_method",
DISPLACE_NUM_METHODS,
DISPLACE_BUMP);
}
static int validate_enum_value(int value, int num_values, int default_value)
{
if(value >= num_values) {
@ -1182,6 +1190,7 @@ void BlenderSync::sync_materials(bool update_all)
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
shader->volume_sampling_method = get_volume_sampling(cmat);
shader->volume_interpolation_method = get_volume_interpolation(cmat);
shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
shader->set_graph(graph);
shader->tag_update(scene);

@ -120,12 +120,6 @@ NODE_DEFINE(Mesh)
{
NodeType* type = NodeType::add("mesh", create);
static NodeEnum displacement_method_enum;
displacement_method_enum.insert("bump", DISPLACE_BUMP);
displacement_method_enum.insert("true", DISPLACE_TRUE);
displacement_method_enum.insert("both", DISPLACE_BOTH);
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
SOCKET_UINT(motion_steps, "Motion Steps", 3);
SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
@ -787,6 +781,17 @@ bool Mesh::has_motion_blur() const
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
}
bool Mesh::has_true_displacement() const
{
foreach(Shader *shader, used_shaders) {
if(shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) {
return true;
}
}
return false;
}
bool Mesh::need_build_bvh() const
{
return !transform_applied || has_surface_bssrdf;
@ -1659,7 +1664,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
bool old_need_object_flags_update = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->displacement_method != Mesh::DISPLACE_BUMP)
mesh->has_true_displacement())
{
true_displacement_used = true;
break;

@ -116,15 +116,6 @@ public:
float crease;
};
/* Displacement */
enum DisplacementMethod {
DISPLACE_BUMP = 0,
DISPLACE_TRUE = 1,
DISPLACE_BOTH = 2,
DISPLACE_NUM_METHODS,
};
enum SubdivisionType {
SUBDIVISION_NONE,
SUBDIVISION_LINEAR,
@ -174,7 +165,6 @@ public:
bool transform_applied;
bool transform_negative_scaled;
Transform transform_normal;
DisplacementMethod displacement_method;
PackedPatchTable *patch_table;
@ -245,6 +235,7 @@ public:
void tag_update(Scene *scene, bool rebuild);
bool has_motion_blur() const;
bool has_true_displacement() const;
/* Check whether the mesh should have own BVH built separately. Briefly,
* own BVH is needed for mesh, if:

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

@ -689,7 +689,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
* Could be solved by moving reference counter to Mesh.
*/
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
!object->mesh->has_true_displacement())
{
if(!(motion_blur && object->use_motion)) {
if(!object->mesh->transform_applied) {

@ -150,6 +150,12 @@ NODE_DEFINE(Shader)
volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
SOCKET_ENUM(volume_interpolation_method, "Volume Interpolation Method", volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR);
static NodeEnum displacement_method_enum;
displacement_method_enum.insert("bump", DISPLACE_BUMP);
displacement_method_enum.insert("true", DISPLACE_TRUE);
displacement_method_enum.insert("both", DISPLACE_BOTH);
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
return type;
}
@ -173,6 +179,8 @@ Shader::Shader()
has_object_dependency = false;
has_integrator_dependency = false;
displacement_method = DISPLACE_BUMP;
id = -1;
used = false;
@ -310,7 +318,7 @@ int ShaderManager::get_shader_id(Shader *shader, Mesh *mesh, bool smooth)
int id = shader->id*2;
/* index depends bump since this setting is not in the shader */
if(mesh && mesh->displacement_method != Mesh::DISPLACE_TRUE)
if(mesh && shader->displacement_method != DISPLACE_TRUE)
id += 1;
/* smooth flag */
if(smooth)

@ -66,6 +66,14 @@ enum VolumeInterpolation {
VOLUME_NUM_INTERPOLATION,
};
enum DisplacementMethod {
DISPLACE_BUMP = 0,
DISPLACE_TRUE = 1,
DISPLACE_BOTH = 2,
DISPLACE_NUM_METHODS,
};
/* Shader describing the appearance of a Mesh, Light or Background.
*
* While there is only a single shader graph, it has three outputs: surface,
@ -110,6 +118,9 @@ public:
bool has_object_dependency;
bool has_integrator_dependency;
/* displacement */
DisplacementMethod displacement_method;
/* requested mesh attributes */
AttributeRequestSet attributes;