Cycles microdisplacement: add max subdivision setting
This is to prevent situations such as when the camera gets very close to a mesh and causes it to be tessellated into an excessive amount of micropolygons. In REYES this is known as the eye-splits problem. Reviewed By: brecht Differential Revision: https://developer.blender.org/D1922
This commit is contained in:
parent
71588300d2
commit
3068ea34e4
|
@ -383,6 +383,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default=8.0,
|
||||
)
|
||||
|
||||
cls.max_subdivisions = IntProperty(
|
||||
name="Max Subdivisions",
|
||||
description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation",
|
||||
min=0, max=16,
|
||||
default=12,
|
||||
)
|
||||
|
||||
cls.film_exposure = FloatProperty(
|
||||
name="Exposure",
|
||||
description="Image brightness scale",
|
||||
|
|
|
@ -235,6 +235,8 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
|
|||
sub.label("Subdivision Rate:")
|
||||
sub.prop(cscene, "dicing_rate", text="Render")
|
||||
sub.prop(cscene, "preview_dicing_rate", text="Preview")
|
||||
sub.separator()
|
||||
sub.prop(cscene, "max_subdivisions")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.label("Volume Sampling:")
|
||||
|
|
|
@ -661,13 +661,15 @@ static void create_subd_mesh(Scene *scene,
|
|||
BL::Mesh& b_mesh,
|
||||
PointerRNA *cmesh,
|
||||
const vector<uint>& used_shaders,
|
||||
float dicing_rate)
|
||||
float dicing_rate,
|
||||
int max_subdivisions)
|
||||
{
|
||||
Mesh basemesh;
|
||||
create_mesh(scene, &basemesh, b_mesh, used_shaders);
|
||||
|
||||
SubdParams sdparams(mesh, used_shaders[0], true, false);
|
||||
sdparams.dicing_rate = max(0.1f, RNA_float_get(cmesh, "dicing_rate") * dicing_rate);
|
||||
sdparams.max_level = max_subdivisions;
|
||||
|
||||
scene->camera->update();
|
||||
sdparams.camera = scene->camera;
|
||||
|
@ -784,7 +786,8 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
|
|||
if(b_mesh) {
|
||||
if(render_layer.use_surfaces && !hide_tris) {
|
||||
if(cmesh.data && experimental && RNA_enum_get(&cmesh, "subdivision_type"))
|
||||
create_subd_mesh(scene, mesh, b_ob, b_mesh, &cmesh, used_shaders, dicing_rate);
|
||||
create_subd_mesh(scene, mesh, b_ob, b_mesh, &cmesh, used_shaders,
|
||||
dicing_rate, max_subdivisions);
|
||||
else
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders);
|
||||
|
||||
|
|
|
@ -64,10 +64,12 @@ BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
|
|||
experimental(false),
|
||||
is_cpu(is_cpu),
|
||||
dicing_rate(1.0f),
|
||||
max_subdivisions(12),
|
||||
progress(progress)
|
||||
{
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") : RNA_float_get(&cscene, "dicing_rate");
|
||||
max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
|
||||
}
|
||||
|
||||
BlenderSync::~BlenderSync()
|
||||
|
@ -127,16 +129,24 @@ bool BlenderSync::sync_recalc()
|
|||
}
|
||||
}
|
||||
|
||||
bool dicing_rate_changed = false;
|
||||
bool dicing_prop_changed = false;
|
||||
|
||||
if(experimental) {
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate")
|
||||
: RNA_float_get(&cscene, "dicing_rate");
|
||||
|
||||
if(dicing_rate != updated_dicing_rate) {
|
||||
dicing_rate = updated_dicing_rate;
|
||||
dicing_rate_changed = true;
|
||||
dicing_prop_changed = true;
|
||||
}
|
||||
|
||||
int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
|
||||
|
||||
if(max_subdivisions != updated_max_subdivisions) {
|
||||
max_subdivisions = updated_max_subdivisions;
|
||||
dicing_prop_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +156,7 @@ bool BlenderSync::sync_recalc()
|
|||
if(b_mesh->is_updated()) {
|
||||
mesh_map.set_recalc(*b_mesh);
|
||||
}
|
||||
else if(dicing_rate_changed) {
|
||||
else if(dicing_prop_changed) {
|
||||
PointerRNA cmesh = RNA_pointer_get(&b_mesh->ptr, "cycles");
|
||||
|
||||
if(RNA_enum_get(&cmesh, "subdivision_type"))
|
||||
|
|
|
@ -173,6 +173,7 @@ private:
|
|||
bool is_cpu;
|
||||
|
||||
float dicing_rate;
|
||||
int max_subdivisions;
|
||||
|
||||
struct RenderLayerInfo {
|
||||
RenderLayerInfo()
|
||||
|
|
|
@ -40,6 +40,7 @@ struct SubdParams {
|
|||
int test_steps;
|
||||
int split_threshold;
|
||||
float dicing_rate;
|
||||
int max_level;
|
||||
Camera *camera;
|
||||
Transform objecttoworld;
|
||||
|
||||
|
@ -53,6 +54,7 @@ struct SubdParams {
|
|||
test_steps = 3;
|
||||
split_threshold = 1;
|
||||
dicing_rate = 0.1f;
|
||||
max_level = 12;
|
||||
camera = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,59 @@ void DiagSplit::partition_edge(Patch *patch, float2 *P, int *t0, int *t1, float2
|
|||
}
|
||||
}
|
||||
|
||||
static float2 right_to_equilateral(float2 P)
|
||||
{
|
||||
static const float2 A = make_float2(1.0f, 0.5f);
|
||||
static const float2 B = make_float2(0.0f, sinf(M_PI_F/3.0f));
|
||||
return make_float2(dot(P, A), dot(P, B));
|
||||
}
|
||||
|
||||
static void limit_edge_factors(const TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int max_t)
|
||||
{
|
||||
float2 Pu = sub.Pu;
|
||||
float2 Pv = sub.Pv;
|
||||
float2 Pw = sub.Pw;
|
||||
|
||||
if(sub.patch->is_triangle()) {
|
||||
Pu = right_to_equilateral(Pu);
|
||||
Pv = right_to_equilateral(Pv);
|
||||
Pw = right_to_equilateral(Pw);
|
||||
}
|
||||
|
||||
int tu = int(max_t * len(Pw - Pv));
|
||||
int tv = int(max_t * len(Pw - Pu));
|
||||
int tw = int(max_t * len(Pv - Pu));
|
||||
|
||||
ef.tu = tu <= 1 ? 1 : min(ef.tu, tu);
|
||||
ef.tv = tv <= 1 ? 1 : min(ef.tv, tv);
|
||||
ef.tw = tw <= 1 ? 1 : min(ef.tw, tw);
|
||||
}
|
||||
|
||||
static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int max_t)
|
||||
{
|
||||
float2 P00 = sub.P00;
|
||||
float2 P01 = sub.P01;
|
||||
float2 P10 = sub.P10;
|
||||
float2 P11 = sub.P11;
|
||||
|
||||
if(sub.patch->is_triangle()) {
|
||||
P00 = right_to_equilateral(P00);
|
||||
P01 = right_to_equilateral(P01);
|
||||
P10 = right_to_equilateral(P10);
|
||||
P11 = right_to_equilateral(P11);
|
||||
}
|
||||
|
||||
int tu0 = int(max_t * len(P10 - P00));
|
||||
int tu1 = int(max_t * len(P11 - P01));
|
||||
int tv0 = int(max_t * len(P01 - P00));
|
||||
int tv1 = int(max_t * len(P11 - P10));
|
||||
|
||||
ef.tu0 = tu0 <= 1 ? 1 : min(ef.tu0, tu0);
|
||||
ef.tu1 = tu1 <= 1 ? 1 : min(ef.tu1, tu1);
|
||||
ef.tv0 = tv0 <= 1 ? 1 : min(ef.tv0, tv0);
|
||||
ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1);
|
||||
}
|
||||
|
||||
void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth)
|
||||
{
|
||||
if(depth > 32) {
|
||||
|
@ -172,6 +225,10 @@ void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef
|
|||
QuadDice::SubPatch sub1 = {sub.patch, sub.Pw, Pv, Pu, Pcenter};
|
||||
QuadDice::SubPatch sub2 = {sub.patch, sub.Pv, Pu, Pw, Pcenter};
|
||||
|
||||
limit_edge_factors(sub0, ef0, 1 << params.max_level);
|
||||
limit_edge_factors(sub1, ef1, 1 << params.max_level);
|
||||
limit_edge_factors(sub2, ef2, 1 << params.max_level);
|
||||
|
||||
split(sub0, ef0, depth+1);
|
||||
split(sub1, ef1, depth+1);
|
||||
split(sub2, ef2, depth+1);
|
||||
|
@ -228,6 +285,9 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
|
|||
QuadDice::SubPatch sub0 = {sub.patch, sub.P00, Pu0, sub.P01, Pu1};
|
||||
QuadDice::SubPatch sub1 = {sub.patch, Pu0, sub.P10, Pu1, sub.P11};
|
||||
|
||||
limit_edge_factors(sub0, ef0, 1 << params.max_level);
|
||||
limit_edge_factors(sub1, ef1, 1 << params.max_level);
|
||||
|
||||
split(sub0, ef0, depth+1);
|
||||
split(sub1, ef1, depth+1);
|
||||
}
|
||||
|
@ -253,6 +313,9 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
|
|||
QuadDice::SubPatch sub0 = {sub.patch, sub.P00, sub.P10, Pv0, Pv1};
|
||||
QuadDice::SubPatch sub1 = {sub.patch, Pv0, Pv1, sub.P01, sub.P11};
|
||||
|
||||
limit_edge_factors(sub0, ef0, 1 << params.max_level);
|
||||
limit_edge_factors(sub1, ef1, 1 << params.max_level);
|
||||
|
||||
split(sub0, ef0, depth+1);
|
||||
split(sub1, ef1, depth+1);
|
||||
}
|
||||
|
@ -275,6 +338,8 @@ void DiagSplit::split_triangle(Patch *patch)
|
|||
ef_split.tv = T(patch, sub_split.Pw, sub_split.Pu);
|
||||
ef_split.tw = T(patch, sub_split.Pu, sub_split.Pv);
|
||||
|
||||
limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
|
||||
|
||||
split(sub_split, ef_split);
|
||||
|
||||
TriangleDice dice(params);
|
||||
|
@ -328,6 +393,8 @@ void DiagSplit::split_quad(Patch *patch)
|
|||
ef_split.tv0 = T(patch, sub_split.P00, sub_split.P01);
|
||||
ef_split.tv1 = T(patch, sub_split.P10, sub_split.P11);
|
||||
|
||||
limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
|
||||
|
||||
split(sub_split, ef_split);
|
||||
|
||||
QuadDice dice(params);
|
||||
|
|
Loading…
Reference in New Issue