diff options
22 files changed, 289 insertions, 47 deletions
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index dd1dae121b1..a8f90c7e6d4 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -359,6 +359,10 @@ static void xml_read_camera(const XMLReadState& state, pugi::xml_node node) xml_read_float(&cam->fisheye_fov, node, "fisheye_fov"); xml_read_float(&cam->fisheye_lens, node, "fisheye_lens"); + xml_read_float(&cam->use_spherical_stereo, node, "use_spherical_stereo"); + xml_read_float(&cam->interocular_distance, node, "interocular_distance"); + xml_read_float(&cam->convergence_distance, node, "convergence_distance"); + xml_read_float(&cam->sensorwidth, node, "sensorwidth"); xml_read_float(&cam->sensorheight, node, "sensorheight"); diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 150b4e75581..29388317873 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -43,6 +43,7 @@ class CyclesRender(bpy.types.RenderEngine): bl_use_preview = True bl_use_exclude_layers = True bl_use_save_buffers = True + bl_use_spherical_stereo = True def __init__(self): self.session = None diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index cdbee52bfa9..2a7c1d3d943 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -62,6 +62,9 @@ struct BlenderCamera { float latitude_max; float longitude_min; float longitude_max; + bool use_spherical_stereo; + float interocular_distance; + float convergence_distance; enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit; float sensor_width; @@ -110,7 +113,8 @@ static void blender_camera_init(BlenderCamera *bcam, static float blender_camera_focal_distance(BL::RenderEngine& b_engine, BL::Object& b_ob, - BL::Camera& b_camera) + BL::Camera& b_camera, + BlenderCamera *bcam) { BL::Object b_dof_object = b_camera.dof_object(); @@ -119,8 +123,8 @@ static float blender_camera_focal_distance(BL::RenderEngine& b_engine, /* for dof object, return distance along camera Z direction */ BL::Array<float, 16> b_ob_matrix; - b_engine.camera_model_matrix(b_ob, b_ob_matrix); - Transform obmat = get_transform(b_ob_matrix); + b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix); + Transform obmat = transform_clear_scale(get_transform(b_ob_matrix)); Transform dofmat = get_transform(b_dof_object.matrix_world()); float3 view_dir = normalize(transform_get_column(&obmat, 2)); float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3); @@ -170,6 +174,10 @@ static void blender_camera_from_object(BlenderCamera *bcam, bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min"); bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max"); + bcam->interocular_distance = b_camera.stereo().interocular_distance(); + bcam->convergence_distance = b_camera.stereo().convergence_distance(); + bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob); + bcam->ortho_scale = b_camera.ortho_scale(); bcam->lens = b_camera.lens(); @@ -192,10 +200,10 @@ static void blender_camera_from_object(BlenderCamera *bcam, bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades"); bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation"); - bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera); + bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam); bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio"); - bcam->shift.x = b_engine.camera_shift_x(b_ob); + bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo); bcam->shift.y = b_camera.shift_y(); bcam->sensor_width = b_camera.sensor_width(); @@ -337,7 +345,7 @@ static void blender_camera_viewplane(BlenderCamera *bcam, } } -static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height) +static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height, const char *viewname) { /* copy camera to compare later */ Camera prevcam = *cam; @@ -394,6 +402,20 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->longitude_min = bcam->longitude_min; cam->longitude_max = bcam->longitude_max; + /* panorama stereo */ + cam->interocular_distance = bcam->interocular_distance; + cam->convergence_distance = bcam->convergence_distance; + cam->use_spherical_stereo = bcam->use_spherical_stereo; + + if(cam->use_spherical_stereo) { + if(strcmp(viewname, "left") == 0) + cam->stereo_eye = Camera::STEREO_LEFT; + else if(strcmp(viewname, "right") == 0) + cam->stereo_eye = Camera::STEREO_RIGHT; + else + cam->stereo_eye = Camera::STEREO_NONE; + } + /* anamorphic lens bokeh */ cam->aperture_ratio = bcam->aperture_ratio; @@ -435,7 +457,8 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int void BlenderSync::sync_camera(BL::RenderSettings& b_render, BL::Object& b_override, - int width, int height) + int width, int height, + const char *viewname) { BlenderCamera bcam; blender_camera_init(&bcam, b_render); @@ -478,13 +501,13 @@ void BlenderSync::sync_camera(BL::RenderSettings& b_render, 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, b_ob_matrix); + b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); bcam.matrix = get_transform(b_ob_matrix); } /* sync */ Camera *cam = scene->camera; - blender_camera_sync(cam, &bcam, width, height); + blender_camera_sync(cam, &bcam, width, height, viewname); } void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, @@ -497,7 +520,7 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, Camera *cam = scene->camera; BL::Array<float, 16> b_ob_matrix; - b_engine.camera_model_matrix(b_ob, b_ob_matrix); + b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix); Transform tfm = get_transform(b_ob_matrix); tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type); @@ -766,7 +789,7 @@ void BlenderSync::sync_view(BL::SpaceView3D& b_v3d, b_v3d, b_rv3d, width, height); - blender_camera_sync(scene->camera, &bcam, width, height); + blender_camera_sync(scene->camera, &bcam, width, height, ""); } BufferParams BlenderSync::get_buffer_params(BL::RenderSettings& b_render, diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index f1b524f7b44..1f85feb0b7d 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -153,7 +153,6 @@ void BlenderSession::create_session() * do some basic syncing here, no objects or materials for speed */ sync->sync_render_layers(b_v3d, NULL); sync->sync_integrator(); - sync->sync_camera(b_render, b_camera_override, width, height); } /* set buffer parameters */ @@ -206,10 +205,8 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_) /* for final render we will do full data sync per render layer, only * do some basic syncing here, no objects or materials for speed */ - BL::Object b_camera_override(b_engine.camera_override()); sync->sync_render_layers(b_v3d, NULL); sync->sync_integrator(); - sync->sync_camera(b_render, b_camera_override, width, height); BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); @@ -502,7 +499,7 @@ void BlenderSession::render() /* update scene */ BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_camera(b_render, b_camera_override, width, height); + sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str()); sync->sync_data(b_render, b_v3d, b_camera_override, @@ -642,7 +639,7 @@ void BlenderSession::bake(BL::Object& b_object, /* update scene */ BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_camera(b_render, b_camera_override, width, height); + sync->sync_camera(b_render, b_camera_override, width, height, ""); sync->sync_data(b_render, b_v3d, b_camera_override, @@ -808,7 +805,7 @@ void BlenderSession::synchronize() if(b_rv3d) sync->sync_view(b_v3d, b_rv3d, width, height); else - sync->sync_camera(b_render, b_camera_override, width, height); + sync->sync_camera(b_render, b_camera_override, width, height, ""); /* unlock */ session->scene->mutex.unlock(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index d3edfcb657f..92250ffeefc 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -69,7 +69,8 @@ public: void sync_integrator(); void sync_camera(BL::RenderSettings& b_render, BL::Object& b_override, - int width, int height); + int width, int height, + const char *viewname); void sync_view(BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, int width, int height); diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index fd1d854a0ff..0947946e63d 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -105,18 +105,32 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo } #endif - ray->P = transform_point(&cameratoworld, ray->P); - ray->D = transform_direction(&cameratoworld, ray->D); + float3 tP = transform_point(&cameratoworld, ray->P); + float3 tD = transform_direction(&cameratoworld, ray->D); + ray->P = spherical_stereo_position(kg, tD, tP); + ray->D = spherical_stereo_direction(kg, tD, tP, ray->P); ray->D = normalize(ray->D); #ifdef __RAY_DIFFERENTIALS__ /* ray differential */ - float3 Ddiff = transform_direction(&cameratoworld, Pcamera); - ray->dP = differential3_zero(); - ray->dD.dx = normalize(Ddiff + float4_to_float3(kernel_data.cam.dx)) - normalize(Ddiff); - ray->dD.dy = normalize(Ddiff + float4_to_float3(kernel_data.cam.dy)) - normalize(Ddiff); + tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + tD = transform_direction(&cameratoworld, tP); + float3 Pdiff = spherical_stereo_position(kg, tD, tP); + float3 Ddiff = normalize(spherical_stereo_direction(kg, tD, tP, Pdiff)); + + tP = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + tD = transform_direction(&cameratoworld, tP); + Pcamera = spherical_stereo_position(kg, tD, tP); + ray->dD.dx = normalize(spherical_stereo_direction(kg, tD, tP, Pcamera)) - Ddiff; + ray->dP.dx = Pcamera - Pdiff; + + tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + tD = transform_direction(&cameratoworld, tP); + Pcamera = spherical_stereo_position(kg, tD, tP); + ray->dD.dy = normalize(spherical_stereo_direction(kg, tD, tP, Pcamera)) - Ddiff; + /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */ #endif #ifdef __CAMERA_CLIPPING__ @@ -259,22 +273,32 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float } #endif - ray->P = transform_point(&cameratoworld, ray->P); - ray->D = transform_direction(&cameratoworld, ray->D); + float3 tP = transform_point(&cameratoworld, ray->P); + float3 tD = transform_direction(&cameratoworld, ray->D); + ray->P = spherical_stereo_position(kg, tD, tP); + ray->D = spherical_stereo_direction(kg, tD, tP, ray->P); ray->D = normalize(ray->D); #ifdef __RAY_DIFFERENTIALS__ /* ray differential */ ray->dP = differential3_zero(); - Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); - float3 Ddiff = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y))); - - Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); - ray->dD.dx = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y))) - Ddiff; - - Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); - ray->dD.dy = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y))) - Ddiff; + tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); + float3 Pdiff = spherical_stereo_position(kg, tD, tP); + float3 Ddiff = normalize(spherical_stereo_direction(kg, tD, tP, Pdiff)); + + tP = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); + Pcamera = spherical_stereo_position(kg, tD, tP); + ray->dD.dx = normalize(spherical_stereo_direction(kg, tD, tP, Pcamera)) - Ddiff; + ray->dP.dx = Pcamera - Pdiff; + + tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); + Pcamera = spherical_stereo_position(kg, tD, tP); + ray->dD.dy = normalize(spherical_stereo_direction(kg, tD, tP, Pcamera)) - Ddiff; + /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */ #endif } diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h index 62922df3286..fa06b937e61 100644 --- a/intern/cycles/kernel/kernel_projection.h +++ b/intern/cycles/kernel/kernel_projection.h @@ -222,6 +222,32 @@ ccl_device float2 direction_to_panorama(KernelGlobals *kg, float3 dir) } } +ccl_device float3 spherical_stereo_position(KernelGlobals *kg, float3 dir, float3 pos) +{ + float3 up, side; + + /* Interocular_offset of zero means either non stereo, or stereo without spherical stereo. */ + + up = make_float3(0.0f, 0.0f, 1.0f); + side = normalize(cross(dir, up)); + + return pos + (side * kernel_data.cam.interocular_offset); +} + +ccl_device float3 spherical_stereo_direction(KernelGlobals *kg, float3 dir, float3 pos, float3 newpos) +{ + float3 screenpos, dirnew; + + /* Interocular_distance of zero means either no stereo, or stereo without spherical stereo. */ + if(kernel_data.cam.interocular_offset == 0.0f) + return dir; + + screenpos = pos + (normalize(dir) * kernel_data.cam.convergence_distance); + dirnew = screenpos - newpos; + + return dirnew; +} + CCL_NAMESPACE_END #endif /* __KERNEL_PROJECTION_CL__ */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index bdd17c66c0f..c5edc16f196 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -901,6 +901,11 @@ typedef struct KernelCamera { float fisheye_lens; float4 equirectangular_range; + /* stereo */ + int pad1, pad2; + float interocular_offset; + float convergence_distance; + /* matrices */ Transform cameratoworld; Transform rastertocamera; diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 9c17a11e0f1..0e343822223 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -73,6 +73,9 @@ Camera::Camera() longitude_max = M_PI_F; fov = M_PI_4_F; fov_pre = fov_post = fov; + stereo_eye = STEREO_NONE; + interocular_distance = 0.065f; + convergence_distance = 30.0f * 0.065f; sensorwidth = 0.036f; sensorheight = 0.024f; @@ -341,6 +344,21 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) kcam->equirectangular_range = make_float4(longitude_min - longitude_max, -longitude_min, latitude_min - latitude_max, -latitude_min + M_PI_2_F); + switch(stereo_eye) { + case STEREO_LEFT: + kcam->interocular_offset = -interocular_distance * 0.5f; + break; + case STEREO_RIGHT: + kcam->interocular_offset = interocular_distance * 0.5f; + break; + case STEREO_NONE: + default: + kcam->interocular_offset = 0.0f; + break; + } + + kcam->convergence_distance = convergence_distance; + /* sensor size */ kcam->sensorwidth = sensorwidth; kcam->sensorheight = sensorheight; @@ -427,7 +445,8 @@ bool Camera::modified(const Camera& cam) (latitude_min == cam.latitude_min) && (latitude_max == cam.latitude_max) && (longitude_min == cam.longitude_min) && - (longitude_max == cam.longitude_max)); + (longitude_max == cam.longitude_max) && + (stereo_eye == cam.stereo_eye)); } bool Camera::motion_modified(const Camera& cam) @@ -480,9 +499,30 @@ BoundBox Camera::viewplane_bounds_get() BoundBox bounds = BoundBox::empty; if(type == CAMERA_PANORAMA) { - bounds.grow(make_float3(cameratoworld.x.w, - cameratoworld.y.w, - cameratoworld.z.w)); + if(use_spherical_stereo == false) { + bounds.grow(make_float3(cameratoworld.x.w, + cameratoworld.y.w, + cameratoworld.z.w)); + } + else { + float half_eye_distance = interocular_distance * 0.5f; + + bounds.grow(make_float3(cameratoworld.x.w + half_eye_distance, + cameratoworld.y.w, + cameratoworld.z.w)); + + bounds.grow(make_float3(cameratoworld.z.w, + cameratoworld.y.w + half_eye_distance, + cameratoworld.z.w)); + + bounds.grow(make_float3(cameratoworld.x.w - half_eye_distance, + cameratoworld.y.w, + cameratoworld.z.w)); + + bounds.grow(make_float3(cameratoworld.x.w, + cameratoworld.y.w - half_eye_distance, + cameratoworld.z.w)); + } } else { bounds.grow(transform_raster_to_world(0.0f, 0.0f)); diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 6771ecc8f23..6fbb1dc3bc8 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -59,6 +59,13 @@ public: ROLLING_SHUTTER_NUM_TYPES, }; + /* Stereo Type */ + enum StereoEye { + STEREO_NONE, + STEREO_LEFT, + STEREO_RIGHT, + }; + /* motion blur */ float shuttertime; MotionPosition motion_position; @@ -92,6 +99,12 @@ public: float longitude_min; float longitude_max; + /* panorama stereo */ + StereoEye stereo_eye; + bool use_spherical_stereo; + float interocular_distance; + float convergence_distance; + /* anamorphic lens bokeh */ float aperture_ratio; diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index 108e8bdfc74..58a4820e27a 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -147,8 +147,12 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): def draw(self, context): layout = self.layout - # render = context.scene.render + render = context.scene.render st = context.camera.stereo + cam = context.camera + + is_spherical_stereo = cam.type != 'ORTHO' and render.use_spherical_stereo + use_spherical_stereo = is_spherical_stereo and st.use_spherical_stereo col = layout.column() col.row().prop(st, "convergence_mode", expand=True) @@ -159,8 +163,14 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): col.prop(st, "interocular_distance") + if is_spherical_stereo: + col.separator() + col.prop(st, "use_spherical_stereo") + col.label(text="Pivot:") - col.row().prop(st, "pivot", expand=True) + row = col.row() + row.active = not use_spherical_stereo + row.prop(st, "pivot", expand=True) class DATA_PT_camera(CameraButtonsPanel, Panel): diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index 118153a9163..d13a711c589 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -144,6 +144,7 @@ void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Ob void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]); float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname); void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname); +bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, struct Object *camera); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 2eac5b6ce5e..a4c44b9934e 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -135,6 +135,7 @@ float get_render_aosss_error(const struct RenderData *r, float error); bool BKE_scene_use_new_shading_nodes(const struct Scene *scene); bool BKE_scene_use_shading_nodes_custom(struct Scene *scene); +bool BKE_scene_use_spherical_stereo(struct Scene *scene); bool BKE_scene_uses_blender_internal(const struct Scene *scene); bool BKE_scene_uses_blender_game(const struct Scene *scene); diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 73b1f0e53f6..6fd756e2788 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -845,6 +845,29 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha normalize_m4(r_modelmat); } +bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera) +{ + Camera *cam; + const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; + + if (!is_multiview) + return false; + + if (camera->type != OB_CAMERA) + return false; + else + cam = camera->data; + + if ((rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) && + ELEM(cam->type, CAM_PANO, CAM_PERSP) && + ((cam->stereo.flag & CAM_S3D_SPHERICAL) != 0)) + { + return true; + } + + return false; +} + static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix) { SceneRenderView *srv; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 3ce000abcfb..6b297a143d6 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -2192,6 +2192,12 @@ bool BKE_scene_use_shading_nodes_custom(Scene *scene) return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); } +bool BKE_scene_use_spherical_stereo(Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + return (type && type->flag & RE_USE_SPHERICAL_STEREO); +} + bool BKE_scene_uses_blender_internal(const Scene *scene) { return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER); diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index c45322b818f..7f2e1aaadf9 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -51,7 +51,8 @@ typedef struct CameraStereoSettings { float convergence_distance; short convergence_mode; short pivot; - short pad, pad2; + short flag; + short pad; } CameraStereoSettings; typedef struct Camera { @@ -148,6 +149,11 @@ enum { CAM_S3D_PIVOT_CENTER = 2, }; +/* stereo->flag */ +enum { + CAM_S3D_SPHERICAL = (1 << 0), +}; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 341cbb70d64..e3f27625356 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -144,6 +144,13 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) "The converge point for the stereo cameras " "(often the distance between a projector and the projection screen)"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "use_spherical_stereo", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_S3D_SPHERICAL); + RNA_def_property_ui_text(prop, "Spherical Stereo", + "Render every pixel rotating the camera around the " + "middle of the interocular distance"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); } void RNA_def_camera(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 6fce93dd9f6..84382704b2b 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -522,6 +522,10 @@ static void rna_def_render_engine(BlenderRNA *brna) prop = RNA_def_boolean(func, "do_break", 0, "Break", ""); RNA_def_function_return(func, prop); + func = RNA_def_function(srna, "active_view_get", "RE_engine_active_view_get"); + prop = RNA_def_string(func, "view", NULL, 0, "View", "Single view active"); + RNA_def_function_return(func, prop); + func = RNA_def_function(srna, "active_view_set", "RE_engine_active_view_set"); RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */ RNA_def_property_flag(prop, PROP_REQUIRED); @@ -529,15 +533,23 @@ static void rna_def_render_engine(BlenderRNA *brna) func = RNA_def_function(srna, "camera_shift_x", "RE_engine_get_camera_shift_x"); prop = RNA_def_pointer(func, "camera", "Object", "", ""); RNA_def_property_flag(prop, PROP_REQUIRED); + prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); prop = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX); RNA_def_function_return(func, prop); func = RNA_def_function(srna, "camera_model_matrix", "RE_engine_get_camera_model_matrix"); prop = RNA_def_pointer(func, "camera", "Object", "", ""); RNA_def_property_flag(prop, PROP_REQUIRED); + prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f); RNA_def_property_flag(prop, PROP_REQUIRED); + func = RNA_def_function(srna, "use_spherical_stereo", "RE_engine_get_spherical_stereo"); + prop = RNA_def_pointer(func, "camera", "Object", "", ""); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); + RNA_def_function_return(func, prop); + func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats"); RNA_def_function_ui_description(func, "Update and signal to redraw render status text"); prop = RNA_def_string(func, "stats", NULL, 0, "Stats", ""); @@ -667,6 +679,10 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SAVE_BUFFERS); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + prop = RNA_def_property(srna, "bl_use_spherical_stereo", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SPHERICAL_STEREO); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_define_verify_sdna(1); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 7505dc28210..412c0bc0f96 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1470,6 +1470,12 @@ static int rna_RenderSettings_use_shading_nodes_get(PointerRNA *ptr) return BKE_scene_use_new_shading_nodes(scene); } +static int rna_RenderSettings_use_spherical_stereo_get(PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->id.data; + return BKE_scene_use_spherical_stereo(scene); +} + static int rna_RenderSettings_use_game_engine_get(PointerRNA *ptr) { RenderData *rd = (RenderData *)ptr->data; @@ -5945,6 +5951,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Use Shading Nodes", "Active render engine uses new shading nodes system"); + prop = RNA_def_property(srna, "use_spherical_stereo", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_spherical_stereo_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Use Spherical Stereo", "Active render engine supports spherical stereo rendering"); + prop = RNA_def_property(srna, "use_game_engine", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_game_engine_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index d08b637454b..f83a210275f 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -62,6 +62,7 @@ struct BakePixel; #define RE_USE_SAVE_BUFFERS 64 #define RE_USE_TEXTURE_PREVIEW 128 #define RE_USE_SHADING_NODES_CUSTOM 256 +#define RE_USE_SPHERICAL_STEREO 512 /* RenderEngine.flag */ #define RE_ENGINE_ANIMATION 1 @@ -140,9 +141,11 @@ struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result); void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results); +const char *RE_engine_active_view_get(RenderEngine *engine); void RE_engine_active_view_set(RenderEngine *engine, const char *viewname); -float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera); -void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, float *r_modelmat); +float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera, int use_spherical_stereo); +void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat); +int RE_engine_get_spherical_stereo(RenderEngine *engine, struct Object *camera); int RE_engine_test_break(RenderEngine *engine); void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index b31760c34dd..fd9d95c63b6 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -372,24 +372,46 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg) } } +const char *RE_engine_active_view_get(RenderEngine *engine) +{ + Render *re = engine->re; + return RE_GetActiveRenderView(re); +} + void RE_engine_active_view_set(RenderEngine *engine, const char *viewname) { Render *re = engine->re; RE_SetActiveRenderView(re, viewname); } -float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera) +float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, int use_spherical_stereo) { Render *re = engine->re; + + /* when using spherical stereo, get camera shift without multiview, leaving stereo to be handled by the engine */ + if (use_spherical_stereo) + re = NULL; + return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname); } -void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, float *r_modelmat) +void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, int use_spherical_stereo, float *r_modelmat) { Render *re = engine->re; + + /* when using spherical stereo, get model matrix without multiview, leaving stereo to be handled by the engine */ + if (use_spherical_stereo) + re = NULL; + BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat); } +int RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera) +{ + Render *re = engine->re; + return BKE_camera_multiview_spherical_stereo(re ? &re->r : NULL, camera) ? 1 : 0; +} + rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free) { static rcti tiles_static[BLENDER_MAX_THREADS]; diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index e96e866245a..bbf0ffa4cd4 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -230,9 +230,11 @@ void RE_texture_rng_init() RET_NONE void RE_texture_rng_exit() RET_NONE bool RE_layers_have_name(struct RenderResult *result) {STUB_ASSERT(0); return 0;} +const char *RE_engine_active_view_get(struct RenderEngine *engine) RET_NULL void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) {STUB_ASSERT(0);} -void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, float *r_modelmat) {STUB_ASSERT(0);} -float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera) RET_ZERO +void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) {STUB_ASSERT(0);} +float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo) RET_ZERO +int RE_engine_get_spherical_stereo(struct RenderEngine *engine, struct Object *camera) RET_ZERO void RE_SetActiveRenderView(struct Render *re, const char *viewname) {STUB_ASSERT(0);} struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL |