Cycles: Add support for cameras inside volume
Basically the title says it all, volume stack initialization now is aware that camera might be inside of the volume. This gives quite noticeable render time regressions in cases camera is in the volume (didn't measure them yet) because this requires quite a few of ray-casting per camera ray in order to check which objects we're inside. Not quite sure if this might be optimized. But the good thing is that we can do quite a good job on detecting whether camera is outside of any of the volumes and in this case there should be no time penalty at all (apart from some extra checks during the sync state). For now we're only doing rather simple AABB checks between the viewplane and volume objects. This could give some false-positives, but this should be good starting point. Need to mention panoramic cameras here, for them it's only check for whether there are volumes in the scene, which would lead to speed regressions even if the camera is outside of the volumes. Would need to figure out proper check for such cameras. There are still quite a few of TODOs in the code, but the patch is good enough to start playing around with it checking whether there are some obvious mistakes somewhere. Currently the feature is only available in the Experimental feature sey, need to solve some of the TODOs and look into making things faster before considering the feature is ready for the official feature set. This would still likely happen in current release cycle. Reviewers: brecht, juicyfruit, dingto Differential Revision: https://developer.blender.org/D794
This commit is contained in:
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user