diff options
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/camera.cpp | 114 | ||||
-rw-r--r-- | intern/cycles/render/camera.h | 10 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 13 |
3 files changed, 131 insertions, 6 deletions
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index bb0fec759a9..4c73726ba33 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -15,14 +15,43 @@ */ #include "camera.h" +#include "mesh.h" +#include "object.h" #include "scene.h" #include "device.h" +#include "util_foreach.h" #include "util_vector.h" CCL_NAMESPACE_BEGIN +namespace { + +bool object_has_volume(Scene *scene, Object *object) +{ + Mesh *mesh = object->mesh; + foreach(uint shader, mesh->used_shaders) { + if(scene->shaders[shader]->has_volume) { + return true; + } + } + return false; +} + +bool scene_has_volume(Scene *scene) +{ + for(size_t i = 0; i < scene->objects.size(); ++i) { + Object *object = scene->objects[i]; + if(object_has_volume(scene, object)) { + return true; + } + } + return false; +} + +} // namespace + Camera::Camera() { shuttertime = 1.0f; @@ -270,6 +299,40 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) need_device_update = false; previous_need_motion = need_motion; + + /* Camera in volume. */ + kcam->is_inside_volume = 0; + if(use_camera_in_volume) { + if(type == CAMERA_PANORAMA) { + /* It's not clear how to do viewplace->object intersection for + * panoramic cameras, for now let's just check for whether there + * are any volumes in the scene. + */ + kcam->is_inside_volume = scene_has_volume(scene); + } + else { + /* TODO(sergey): Whole bunch of stuff here actually: + * - We do rather stupid check with object AABB to camera viewplane + * AABB intersection, which is quite fast to perform, but which + * could give some false-positives checks here, More grained check + * would help avoiding time wasted n the kernel to initialize the + * volume stack. + * - We could cache has_volume in the cache, would save quite a few + * CPU ticks when having loads of instanced meshes. + */ + BoundBox viewplane_boundbox = viewplane_bounds_get(); + for(size_t i = 0; i < scene->objects.size(); ++i) { + Object *object = scene->objects[i]; + if(object_has_volume(scene, object)) { + if(viewplane_boundbox.intersects(object->bounds)) { + /* TODO(sergey): Consider adding more grained check. */ + kcam->is_inside_volume = 1; + break; + } + } + } + } + } } void Camera::device_free(Device *device, DeviceScene *dscene) @@ -313,5 +376,56 @@ void Camera::tag_update() need_update = true; } +float3 Camera::transform_raster_to_world(float raster_x, float raster_y) +{ + float3 D, P; + if(type == CAMERA_PERSPECTIVE) { + D = transform_perspective(&rastertocamera, + make_float3(raster_x, raster_y, 0.0f)); + P = make_float3(0.0f, 0.0f, 0.0f); + /* TODO(sergey): Aperture support? */ + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); + /* TODO(sergey): Clipping is conditional in kernel, and hence it could + * be mistakes in here, currently leading to wrong camera-in-volume + * detection. + */ + P += nearclip * D; + } + else if (type == CAMERA_ORTHOGRAPHIC) { + D = make_float3(0.0f, 0.0f, 1.0f); + /* TODO(sergey): Aperture support? */ + P = transform_perspective(&rastertocamera, + make_float3(raster_x, raster_y, 0.0f)); + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); + } + else { + assert(!"unsupported camera type"); + } + return P; +} + +BoundBox Camera::viewplane_bounds_get() +{ + assert(type != CAMERA_PANORAMA); + + /* TODO(sergey): This is all rather stupid, but is there a way to perform + * checks we need in a more clear and smart fasion? + */ + BoundBox bounds = BoundBox::empty; + bounds.grow(transform_raster_to_world(0.0f, 0.0f)); + bounds.grow(transform_raster_to_world(0.0f, (float)height)); + bounds.grow(transform_raster_to_world((float)width, (float)height)); + bounds.grow(transform_raster_to_world((float)width, 0.0f)); + if(type == CAMERA_PERSPECTIVE) { + /* Center point has the most distancei in local Z axis, + * use it to construct bounding box/ + */ + bounds.grow(transform_raster_to_world(0.5f*width, 0.5f*height)); + } + return bounds; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 50889968a90..3054137309d 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -102,6 +102,13 @@ public: bool need_device_update; int previous_need_motion; + /* Camera in volume. */ + /* TODO(sergey): Get rid of this argument once + * cameras in volume considered fast enough for + * the regular kernel. + */ + bool use_camera_in_volume; + /* functions */ Camera(); ~Camera(); @@ -116,6 +123,9 @@ public: bool modified(const Camera& cam); bool motion_modified(const Camera& cam); void tag_update(); + + BoundBox viewplane_bounds_get(); + float3 transform_raster_to_world(float raster_x, float raster_y); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 796007b64a8..d0de8c51300 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -165,13 +165,13 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel()) return; - progress.set_status("Updating Camera"); - camera->device_update(device, &dscene, this); + progress.set_status("Updating Objects"); + object_manager->device_update(device, &dscene, this, progress); if(progress.get_cancel()) return; - progress.set_status("Updating Objects"); - object_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Meshes"); + mesh_manager->device_update(device, &dscene, this, progress); if(progress.get_cancel()) return; @@ -185,8 +185,9 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel()) return; - progress.set_status("Updating Meshes"); - mesh_manager->device_update(device, &dscene, this, progress); + /* TODO(sergey): Make sure camera is not needed above. */ + progress.set_status("Updating Camera"); + camera->device_update(device, &dscene, this); if(progress.get_cancel()) return; |