Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/blender_camera.cpp2
-rw-r--r--intern/cycles/kernel/kernel_bake.h2
-rw-r--r--intern/cycles/kernel/kernel_path.h4
-rw-r--r--intern/cycles/kernel/kernel_path_state.h4
-rw-r--r--intern/cycles/kernel/kernel_types.h2
-rw-r--r--intern/cycles/kernel/kernel_volume.h93
-rw-r--r--intern/cycles/render/camera.cpp114
-rw-r--r--intern/cycles/render/camera.h10
-rw-r--r--intern/cycles/render/scene.cpp13
-rw-r--r--intern/cycles/util/util_boundbox.h9
10 files changed, 235 insertions, 18 deletions
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index ce8c64c4819..016f6637b3c 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -390,6 +390,7 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
/* sync */
Camera *cam = scene->camera;
blender_camera_sync(cam, &bcam, width, height);
+ scene->camera->use_camera_in_volume = experimental;
}
void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
@@ -554,6 +555,7 @@ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int
blender_camera_border(&bcam, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
blender_camera_sync(scene->camera, &bcam, width, height);
+ scene->camera->use_camera_in_volume = experimental;
}
BufferParams BlenderSync::get_buffer_params(BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height)
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 822ad14039b..a1ec080e3d3 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -33,7 +33,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
path_radiance_init(&L_sample, kernel_data.film.use_light_pass);
/* init path state */
- path_state_init(kg, &state, &rng, sample);
+ path_state_init(kg, &state, &rng, sample, NULL);
/* evaluate surface shader */
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 0515489f77f..94440fc31a7 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -469,7 +469,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
path_radiance_init(&L, kernel_data.film.use_light_pass);
PathState state;
- path_state_init(kg, &state, rng, sample);
+ path_state_init(kg, &state, rng, sample, &ray);
/* path iteration */
for(;;) {
@@ -858,7 +858,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
path_radiance_init(&L, kernel_data.film.use_light_pass);
PathState state;
- path_state_init(kg, &state, rng, sample);
+ path_state_init(kg, &state, rng, sample, &ray);
for(;;) {
/* intersect scene */
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index 43e75885849..f29168642a4 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -16,7 +16,7 @@
CCL_NAMESPACE_BEGIN
-ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state, RNG *rng, int sample)
+ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state, RNG *rng, int sample, Ray *ray)
{
state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP;
@@ -41,7 +41,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state, RNG
if(kernel_data.integrator.use_volumes) {
/* initialize volume stack with volume we are inside of */
- kernel_volume_stack_init(kg, state->volume_stack);
+ kernel_volume_stack_init(kg, ray, state->volume_stack);
/* seed RNG for cases where we can't use stratified samples */
state->rng_congruential = lcg_init(*rng + sample*0x51633e2d);
}
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 1f61d80b947..3e9e260794d 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -784,7 +784,7 @@ typedef struct KernelCamera {
/* anamorphic lens bokeh */
float inv_aperture_ratio;
- int pad1;
+ int is_inside_volume;
int pad2;
/* more matrices */
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index ea02ede10cd..1273869ca28 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -954,17 +954,99 @@ ccl_device bool kernel_volume_use_decoupled(KernelGlobals *kg, bool heterogeneou
* This is an array of object/shared ID's that the current segment of the path
* is inside of. */
-ccl_device void kernel_volume_stack_init(KernelGlobals *kg, VolumeStack *stack)
+ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
+ Ray *ray,
+ VolumeStack *stack)
{
- /* todo: this assumes camera is always in air, need to detect when it isn't */
- if(kernel_data.background.volume_shader == SHADER_NONE) {
- stack[0].shader = SHADER_NONE;
+ /* NULL ray happens in the baker, does it need proper initializetion of
+ * camera in volume?
+ */
+ if(!kernel_data.cam.is_inside_volume || ray == NULL) {
+ /* Camera is guaranteed to be in the air, only take background volume
+ * into account in this case.
+ */
+ if(kernel_data.background.volume_shader != SHADER_NONE) {
+ stack[0].shader = kernel_data.background.volume_shader;
+ stack[0].object = PRIM_NONE;
+ stack[1].shader = SHADER_NONE;
+ }
+ else {
+ stack[0].shader = SHADER_NONE;
+ }
+ return;
}
- else {
+
+ const float3 Pend = ray->P + ray->D*ray->t;
+ Ray volume_ray = *ray;
+ int stack_index = 0, enclosed_index = 0;
+ int enclosed_volumes[VOLUME_STACK_SIZE];
+
+ while(stack_index < VOLUME_STACK_SIZE - 1 &&
+ enclosed_index < VOLUME_STACK_SIZE - 1)
+ {
+ Intersection isect;
+ bool hit = scene_intersect(kg, &volume_ray, PATH_RAY_ALL_VISIBILITY,
+ &isect,
+ NULL, 0.0f, 0.0f);
+ if(!hit) {
+ break;
+ }
+
+ ShaderData sd;
+ shader_setup_from_ray(kg, &sd, &isect, &volume_ray, 0, 0);
+ if(sd.flag & SD_HAS_VOLUME) {
+ if(sd.flag & SD_BACKFACING) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
+ bool is_enclosed = false;
+ for(int i = 0; i < enclosed_index; ++i) {
+ if(enclosed_volumes[i] == sd.object) {
+ is_enclosed = true;
+ break;
+ }
+ }
+ if(is_enclosed == false) {
+ stack[stack_index].object = sd.object;
+ stack[stack_index].shader = sd.shader;
+ ++stack_index;
+ }
+ }
+ else {
+ /* If ray from camera enters the volume, this volume shouldn't
+ * be added to the stak on exit.
+ */
+ enclosed_volumes[enclosed_index++] = sd.object;
+ }
+ }
+
+ /* Move ray forward. */
+ volume_ray.P = ray_offset(sd.P, -sd.Ng);
+ if(volume_ray.t != FLT_MAX) {
+ volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t);
+ /* TODO(sergey): Find a faster way detecting that ray_offset moved
+ * us pass through the end point.
+ */
+ if(dot(ray->D, volume_ray.D) < 0.0f) {
+ break;
+ }
+ }
+ }
+ /* stack_index of 0 means quick checks outside of the kernel gave false
+ * positive, nothing to worry about, just we've wasted quite a few of
+ * ticks just to come into conclusion that camera is in the air.
+ *
+ * In this case we're doing the same above -- check whether background has
+ * volume.
+ */
+ if(stack_index == 0 && kernel_data.background.volume_shader == SHADER_NONE) {
stack[0].shader = kernel_data.background.volume_shader;
stack[0].object = PRIM_NONE;
stack[1].shader = SHADER_NONE;
}
+ else {
+ stack[stack_index].shader = SHADER_NONE;
+ }
}
ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack)
@@ -1013,4 +1095,3 @@ ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd
}
CCL_NAMESPACE_END
-
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;
diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h
index 369082af60a..a71e0399619 100644
--- a/intern/cycles/util/util_boundbox.h
+++ b/intern/cycles/util/util_boundbox.h
@@ -167,6 +167,15 @@ public:
return result;
}
+
+ __forceinline bool intersects(const BoundBox& other)
+ {
+ float3 center_diff = center() - other.center(),
+ total_size = (size() + other.size()) * 0.5f;
+ return fabsf(center_diff.x) <= total_size.x &&
+ fabsf(center_diff.y) <= total_size.y &&
+ fabsf(center_diff.z) <= total_size.z;
+ }
};
__forceinline BoundBox merge(const BoundBox& bbox, const float3& pt)