/* * Copyright 2011, Blender Foundation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "camera.h" #include "scene.h" #include "blender_sync.h" #include "blender_util.h" CCL_NAMESPACE_BEGIN /* Blender Camera Intermediate: we first convert both the offline and 3d view * render camera to this, and from there convert to our native camera format. */ struct BlenderCamera { float nearclip; float farclip; bool ortho; float ortho_scale; float lens; float lensradius; float focaldistance; float2 shift; float2 offset; float zoom; float2 pixelaspect; Transform matrix; }; static void blender_camera_init(BlenderCamera *bcam) { memset(bcam, 0, sizeof(BlenderCamera)); bcam->zoom = 1.0f; bcam->pixelaspect = make_float2(1.0f, 1.0f); } static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera) { BL::Object b_dof_object = b_camera.dof_object(); if(!b_dof_object) return b_camera.dof_distance(); /* for dof object, return distance along camera direction. this is * compatible with blender, but does it fit our dof model? */ Transform obmat = get_transform(b_ob.matrix_world()); Transform dofmat = get_transform(b_dof_object.matrix_world()); float3 cam_p = transform_get_column(&obmat, 3); float3 cam_dir = normalize(transform_get_column(&obmat, 2)); float3 dof_p = transform_get_column(&dofmat, 3); float3 proj_p = dot(dof_p, cam_dir) * cam_dir; return len(proj_p - cam_p); } static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob) { BL::ID b_ob_data = b_ob.data(); if(b_ob_data.is_a(&RNA_Camera)) { BL::Camera b_camera(b_ob_data); PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles"); bcam->nearclip = b_camera.clip_start(); bcam->farclip = b_camera.clip_end(); bcam->ortho = (b_camera.type() == BL::Camera::type_ORTHO); bcam->ortho_scale = b_camera.ortho_scale(); bcam->lens = b_camera.lens(); bcam->lensradius = RNA_float_get(&ccamera, "lens_radius"); bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera); bcam->shift.x = b_camera.shift_x(); bcam->shift.y = b_camera.shift_y(); } else { /* from lamp not implemented yet */ } } static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height) { /* copy camera to compare later */ Camera prevcam = *cam; /* dimensions */ float xratio = width*bcam->pixelaspect.x; float yratio = height*bcam->pixelaspect.y; /* compute x/y aspect and ratio */ float aspectratio, xaspect, yaspect; if(xratio > yratio) { aspectratio= xratio/yratio; xaspect= aspectratio; yaspect= 1.0f; } else { aspectratio= yratio/xratio; xaspect= 1.0f; yaspect= aspectratio; } /* modify aspect for orthographic scale */ if(bcam->ortho) { xaspect = xaspect*bcam->ortho_scale/(aspectratio*2.0f); yaspect = yaspect*bcam->ortho_scale/(aspectratio*2.0f); aspectratio = bcam->ortho_scale/2.0f; } /* set viewplane */ cam->left = -xaspect; cam->right = xaspect; cam->bottom = -yaspect; cam->top = yaspect; /* zoom for 3d camera view */ cam->left *= bcam->zoom; cam->right *= bcam->zoom; cam->bottom *= bcam->zoom; cam->top *= bcam->zoom; /* modify viewplane with camera shift and 3d camera view offset */ float dx = 2.0f*(aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f); float dy = 2.0f*(aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f); cam->left += dx; cam->right += dx; cam->bottom += dy; cam->top += dy; /* clipping distances */ cam->nearclip = bcam->nearclip; cam->farclip = bcam->farclip; /* orthographic */ cam->ortho = bcam->ortho; /* perspective */ cam->fov = 2.0f*atan(16.0f/bcam->lens/aspectratio); cam->focaldistance = bcam->focaldistance; cam->lensradius = bcam->lensradius; /* transform, note the blender camera points along the negative z-axis */ cam->matrix = bcam->matrix * transform_scale(1.0f, 1.0f, -1.0f); /* set update flag */ if(cam->modified(prevcam)) cam->tag_update(); } /* Sync Render Camera */ void BlenderSync::sync_camera(int width, int height) { BlenderCamera bcam; blender_camera_init(&bcam); /* pixel aspect */ BL::RenderSettings r = b_scene.render(); bcam.pixelaspect.x = r.pixel_aspect_x(); bcam.pixelaspect.y = r.pixel_aspect_y(); /* camera object */ BL::Object b_ob = b_scene.camera(); if(b_ob) { blender_camera_from_object(&bcam, b_ob); bcam.matrix = get_transform(b_ob.matrix_world()); } /* sync */ Camera *cam = scene->camera; blender_camera_sync(cam, &bcam, width, height); } /* Sync 3D View Camera */ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height) { BlenderCamera bcam; blender_camera_init(&bcam); /* 3d view parameters */ bcam.nearclip = b_v3d.clip_start(); bcam.farclip = b_v3d.clip_end(); bcam.lens = b_v3d.lens(); if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) { /* camera view */ BL::Object b_ob = b_scene.camera(); if(b_ob) { blender_camera_from_object(&bcam, b_ob); /* magic zoom formula */ bcam.zoom = (float)b_rv3d.view_camera_zoom(); bcam.zoom = (1.41421f + bcam.zoom/50.0f); bcam.zoom *= bcam.zoom; bcam.zoom = 2.0f/bcam.zoom; /* offset */ bcam.offset = get_float2(b_rv3d.view_camera_offset()); } } else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) { /* orthographic view */ bcam.farclip *= 0.5; bcam.nearclip = -bcam.farclip; bcam.ortho = true; bcam.ortho_scale = b_rv3d.view_distance(); } bcam.zoom *= 2.0f; /* 3d view transform */ bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix())); /* sync */ blender_camera_sync(scene->camera, &bcam, width, height); } CCL_NAMESPACE_END