diff options
-rw-r--r-- | intern/cycles/blender/addon/properties.py | 17 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 33 | ||||
-rw-r--r-- | intern/cycles/blender/blender_camera.cpp | 45 | ||||
-rw-r--r-- | intern/cycles/blender/blender_mesh.cpp | 4 | ||||
-rw-r--r-- | intern/cycles/render/camera.cpp | 94 | ||||
-rw-r--r-- | intern/cycles/render/camera.h | 5 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 3 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 1 |
8 files changed, 178 insertions, 24 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 7d1cbadce1b..263d90d6712 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -388,6 +388,23 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=12, ) + cls.dicing_camera = PointerProperty( + name="Dicing Camera", + description="Camera to use as reference point when subdividing geometry, useful to avoid crawling " + "artifacts in animations when the scene camera is moving", + type=bpy.types.Object, + poll=lambda self, obj: obj.type == 'CAMERA', + ) + cls.offscreen_dicing_scale = FloatProperty( + name="Offscreen Dicing Scale", + description="Multiplier for dicing rate of geometry outside of the camera view. The dicing rate " + "of objects is gradually increased the further they are outside the camera view. " + "Lower values provide higher quality reflections and shadows for off screen objects, " + "while higher values use less memory", + min=1.0, soft_max=25.0, + default=4.0, + ) + cls.film_exposure = FloatProperty( name="Exposure", description="Image brightness scale", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 6badfed76d5..5bb0ea1c2dd 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -225,31 +225,32 @@ class CYCLES_RENDER_PT_geometry(CyclesButtonsPanel, Panel): cscene = scene.cycles ccscene = scene.cycles_curves + row = layout.row() + row.label("Volume Sampling:") + row = layout.row() + row.prop(cscene, "volume_step_size") + row.prop(cscene, "volume_max_steps") + + layout.separator() + if cscene.feature_set == 'EXPERIMENTAL': + layout.label("Subdivision Rate:") split = layout.split() col = split.column() - sub = col.column(align=True) - sub.label("Volume Sampling:") - sub.prop(cscene, "volume_step_size") - sub.prop(cscene, "volume_max_steps") + sub.prop(cscene, "dicing_rate", text="Render") + sub.prop(cscene, "preview_dicing_rate", text="Preview") col = split.column() + col.prop(cscene, "offscreen_dicing_scale", text="Offscreen Scale") + col.prop(cscene, "max_subdivisions") - sub = col.column(align=True) - 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:") - row = layout.row() - row.prop(cscene, "volume_step_size") - row.prop(cscene, "volume_max_steps") + layout.prop(cscene, "dicing_camera") + + layout.separator() + layout.label("Hair:") layout.prop(ccscene, "use_curves", text="Use Hair") col = layout.column() col.active = ccscene.use_curves diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index b29711d30d3..62e950e3bef 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -81,6 +81,8 @@ struct BlenderCamera { BoundBox2D viewport_camera_border; Transform matrix; + + float offscreen_dicing_scale; }; static void blender_camera_init(BlenderCamera *bcam, @@ -104,6 +106,7 @@ static void blender_camera_init(BlenderCamera *bcam, bcam->pano_viewplane.top = 1.0f; bcam->viewport_camera_border.right = 1.0f; bcam->viewport_camera_border.top = 1.0f; + bcam->offscreen_dicing_scale = 1.0f; /* render resolution */ bcam->full_width = render_resolution_x(b_render); @@ -353,7 +356,11 @@ static void blender_camera_viewplane(BlenderCamera *bcam, } } -static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height, const char *viewname) +static void blender_camera_sync(Camera *cam, + BlenderCamera *bcam, + int width, int height, + const char *viewname, + PointerRNA *cscene) { /* copy camera to compare later */ Camera prevcam = *cam; @@ -466,6 +473,9 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->border = bcam->border; cam->viewport_camera_border = bcam->viewport_camera_border; + bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale"); + cam->offscreen_dicing_scale = bcam->offscreen_dicing_scale; + /* set update flag */ if(cam->modified(prevcam)) cam->tag_update(); @@ -525,7 +535,21 @@ void BlenderSync::sync_camera(BL::RenderSettings& b_render, /* sync */ Camera *cam = scene->camera; - blender_camera_sync(cam, &bcam, width, height, viewname); + blender_camera_sync(cam, &bcam, width, height, viewname, &cscene); + + /* dicing camera */ + b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera")); + if(b_ob) { + BL::Array<float, 16> b_ob_matrix; + blender_camera_from_object(&bcam, b_engine, b_ob); + b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); + bcam.matrix = get_transform(b_ob_matrix); + + blender_camera_sync(scene->dicing_camera, &bcam, width, height, viewname, &cscene); + } + else { + *scene->dicing_camera = *cam; + } } void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, @@ -818,7 +842,22 @@ void BlenderSync::sync_view(BL::SpaceView3D& b_v3d, b_v3d, b_rv3d, width, height); - blender_camera_sync(scene->camera, &bcam, width, height, ""); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + blender_camera_sync(scene->camera, &bcam, width, height, "", &cscene); + + /* dicing camera */ + BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera")); + if(b_ob) { + BL::Array<float, 16> b_ob_matrix; + blender_camera_from_object(&bcam, b_engine, b_ob); + b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); + bcam.matrix = get_transform(b_ob_matrix); + + blender_camera_sync(scene->dicing_camera, &bcam, width, height, "", &cscene); + } + else { + *scene->dicing_camera = *scene->camera; + } } BufferParams BlenderSync::get_buffer_params(BL::RenderSettings& b_render, diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 5ec3bd7a781..6b003cfa539 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -920,8 +920,8 @@ static void create_subd_mesh(Scene *scene, sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate); sdparams.max_level = max_subdivisions; - scene->camera->update(); - sdparams.camera = scene->camera; + scene->dicing_camera->update(); + sdparams.camera = scene->dicing_camera; sdparams.objecttoworld = get_transform(b_ob.matrix_world()); } diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 9b226140f08..b6757d80afd 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -128,6 +128,8 @@ NODE_DEFINE(Camera) SOCKET_FLOAT(border.bottom, "Border Bottom", 0); SOCKET_FLOAT(border.top, "Border Top", 0); + SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f); + return type; } @@ -273,6 +275,13 @@ void Camera::update() full_dx = transform_direction(&cameratoworld, full_dx); full_dy = transform_direction(&cameratoworld, full_dy); + if(type == CAMERA_PERSPECTIVE) { + float3 v = transform_perspective(&full_rastertocamera, make_float3(full_width, full_height, 1.0f)); + + frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x)); + frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y)); + } + /* TODO(sergey): Support other types of camera. */ if(type == CAMERA_PERSPECTIVE) { /* TODO(sergey): Move to an utility function and de-duplicate with @@ -581,8 +590,27 @@ BoundBox Camera::viewplane_bounds_get() float Camera::world_to_raster_size(float3 P) { + float res = 1.0f; + if(type == CAMERA_ORTHOGRAPHIC) { - return min(len(full_dx), len(full_dy)); + res = min(len(full_dx), len(full_dy)); + + if(offscreen_dicing_scale > 1.0f) { + float3 p = transform_perspective(&worldtocamera, P); + float3 v = transform_perspective(&rastertocamera, make_float3(width, height, 0.0f)); + + /* Create point clamped to frustum */ + float3 c; + c.x = max(-v.x, min(v.x, p.x)); + c.y = max(-v.y, min(v.y, p.y)); + c.z = max(0.0f, p.z); + + float f_dist = len(p - c) / sqrtf((v.x*v.x+v.y*v.y)*0.5f); + + if(f_dist > 0.0f) { + res += res * f_dist * (offscreen_dicing_scale - 1.0f); + } + } } else if(type == CAMERA_PERSPECTIVE) { /* Calculate as if point is directly ahead of the camera. */ @@ -597,14 +625,74 @@ float Camera::world_to_raster_size(float3 P) /* dPdx */ float dist = len(transform_point(&worldtocamera, P)); float3 D = normalize(Ddiff); - return len(dist*dDdx - dot(dist*dDdx, D)*D); + res = len(dist*dDdx - dot(dist*dDdx, D)*D); + + /* Decent approx distance to frustum (doesn't handle corners correctly, but not that big of a deal) */ + float f_dist = 0.0f; + + if(offscreen_dicing_scale > 1.0f) { + float3 p = transform_point(&worldtocamera, P); + + /* Distance from the four planes */ + float r = dot(p, frustum_right_normal); + float t = dot(p, frustum_top_normal); + p = make_float3(-p.x, -p.y, p.z); + float l = dot(p, frustum_right_normal); + float b = dot(p, frustum_top_normal); + p = make_float3(-p.x, -p.y, p.z); + + if(r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) { + /* Point is inside frustum */ + f_dist = 0.0f; + } + else if(r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) { + /* Point is behind frustum */ + f_dist = len(p); + } + else { + /* Point may be behind or off to the side, need to check */ + float3 along_right = make_float3(-frustum_right_normal.z, 0.0f, frustum_right_normal.x); + float3 along_left = make_float3(frustum_right_normal.z, 0.0f, frustum_right_normal.x); + float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y); + float3 along_bottom = make_float3(0.0f, frustum_top_normal.z, frustum_top_normal.y); + + float dist[] = {r, l, t, b}; + float3 along[] = {along_right, along_left, along_top, along_bottom}; + + bool test_o = false; + + float *d = dist; + float3 *a = along; + for(int i = 0; i < 4; i++, d++, a++) { + /* Test if we should check this side at all */ + if(*d > 0.0f) { + if(dot(p, *a) >= 0.0f) { + /* We are in front of the back edge of this side of the frustum */ + f_dist = max(f_dist, *d); + } + else { + /* Possibly far enough behind the frustum to use distance to origin instead of edge */ + test_o = true; + } + } + } + + if(test_o) { + f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p); + } + } + + if(f_dist > 0.0f) { + res += len(dDdx - dot(dDdx, D)*D) * f_dist * (offscreen_dicing_scale - 1.0f); + } + } } else { // TODO(mai): implement for CAMERA_PANORAMA assert(!"pixel width calculation for panoramic projection not implemented yet"); } - return 1.0f; + return res; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index dd6b831b347..12d67044d4f 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -129,6 +129,8 @@ public: BoundBox2D viewplane; /* width and height change during preview, so we need these for calculating dice rates. */ int full_width, full_height; + /* controls how fast the dicing rate falls off for geometry out side of view */ + float offscreen_dicing_scale; /* border */ BoundBox2D border; @@ -163,6 +165,9 @@ public: float3 full_dx; float3 full_dy; + float3 frustum_right_normal; + float3 frustum_top_normal; + /* update */ bool need_update; bool need_device_update; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 260a325206c..8ab4dd48552 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -85,6 +85,7 @@ Scene::Scene(const SceneParams& params_, Device *device) memset(&dscene.data, 0, sizeof(dscene.data)); camera = new Camera(); + dicing_camera = new Camera(); lookup_tables = new LookupTables(); film = new Film(); background = new Background(); @@ -155,6 +156,7 @@ void Scene::free_memory(bool final) if(final) { delete lookup_tables; delete camera; + delete dicing_camera; delete film; delete background; delete integrator; @@ -359,6 +361,7 @@ void Scene::reset() /* ensure all objects are updated */ camera->tag_update(); + dicing_camera->tag_update(); film->tag_update(this); background->tag_update(this); integrator->tag_update(this); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 204c38e5963..81b00b922e5 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -165,6 +165,7 @@ class Scene { public: /* data */ Camera *camera; + Camera *dicing_camera; LookupTables *lookup_tables; Film *film; Background *background; |