[Bf-blender-cvs] [6b54ac5] cycles_panorama_experiments: Cycles: Experiment with native cubemap support in Cycles
Sergey Sharybin
noreply at git.blender.org
Mon Mar 28 18:14:01 CEST 2016
Commit: 6b54ac5081642b3ef30e14f58ccc4430007c1e62
Author: Sergey Sharybin
Date: Sat Mar 26 17:49:46 2016 +0100
Branches: cycles_panorama_experiments
https://developer.blender.org/rB6b54ac5081642b3ef30e14f58ccc4430007c1e62
Cycles: Experiment with native cubemap support in Cycles
This commit implements a native cubemap rendering in Cycles,
which is currently a research project with the following goals:
- Make it easier to render cubemaps for engines which supports
or expects them to be used.
- Intermediate projection to optimize rendering of equirectangular
camera.
Cube map layout is not currently standart but it's most efficient
from the resolution and storage point of views and it's currently:
+-------+-------+--------+
| Back | Right | Bottom |
+-------+-------+--------+
| Front | Left | Top |
+-------+-------+--------+
It's easy to re-map views in the future.
There are still issues to be solved, but it'll be nice to get
VR and panorama artists involved into feedback already. So the
limitations are:
- There's no auto-remapping to equirectangular map happening yet,
so the only way to see result is to put result to an environment
map with cubemap projection and either re-render or investigate
it in viewport.
- Projection formulas are not optimized by any mean. This is to
keep them totally obvious to make it easier to make further
tweaks.
===================================================================
M intern/cycles/app/cycles_xml.cpp
M intern/cycles/blender/addon/properties.py
M intern/cycles/kernel/kernel_camera.h
M intern/cycles/kernel/kernel_projection.h
M intern/cycles/kernel/kernel_types.h
M intern/cycles/kernel/svm/svm.h
M intern/cycles/kernel/svm/svm_image.h
M intern/cycles/render/image.cpp
M intern/cycles/render/image.h
M intern/cycles/render/nodes.cpp
M source/blender/makesdna/DNA_node_types.h
M source/blender/makesrna/intern/rna_nodetree.c
===================================================================
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 176f83f..7fcc669 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -355,6 +355,8 @@ static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
else if(xml_equal_string(node, "panorama_type", "fisheye_equisolid"))
cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
+ else if(xml_equal_string(node, "panorama_type", "cubemap"))
+ cam->panorama_type = PANORAMA_CUBEMAP;
xml_read_float(&cam->fisheye_fov, node, "fisheye_fov");
xml_read_float(&cam->fisheye_lens, node, "fisheye_lens");
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 01aa619..d8d4157 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -68,6 +68,7 @@ enum_panorama_types = (
('FISHEYE_EQUISOLID', "Fisheye Equisolid",
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"),
+ ('CUBEMAP', "Cubemap", "Render the scene using cube map projection"),
)
enum_curve_primitives = (
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index f6c103d..55c6431 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -211,10 +211,17 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
/* Panorama Camera */
-ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
+ccl_device void camera_sample_panorama(KernelGlobals *kg,
+ float x, float y,
+ float raster_x, float raster_y,
+ float lens_u, float lens_v,
+ ccl_addr_space Ray *ray)
{
Transform rastertocamera = kernel_data.cam.rastertocamera;
- float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+ const float3 P = transform_perspective(&rastertocamera,
+ make_float3(x, y, 0.0f));
+ float3 Pcamera = transform_perspective(&rastertocamera,
+ make_float3(raster_x, raster_y, 0.0f));
/* create ray form raster position */
ray->P = make_float3(0.0f, 0.0f, 0.0f);
@@ -226,7 +233,10 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
ray->t = FLT_MAX;
#endif
- ray->D = panorama_to_direction(kg, Pcamera.x, Pcamera.y);
+ ray->D = panorama_to_direction(kg,
+ P.x, P.y,
+ kernel_data.cam.width, kernel_data.cam.height,
+ Pcamera.x, Pcamera.y);
/* indicates ray should not receive any light, outside of the lens */
if(is_zero(ray->D)) {
@@ -283,18 +293,33 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
ray->dP = differential3_zero();
tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
- tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
+ tD = transform_direction(&cameratoworld,
+ panorama_to_direction(kg,
+ P.x, P.y,
+ kernel_data.cam.width,
+ kernel_data.cam.height,
+ tP.x, tP.y));
float3 Pdiff = spherical_stereo_position(kg, tD, tP);
float3 Ddiff = 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));
+ tD = transform_direction(&cameratoworld,
+ panorama_to_direction(kg,
+ P.x, P.y,
+ kernel_data.cam.width,
+ kernel_data.cam.height,
+ tP.x, tP.y));
Pcamera = spherical_stereo_position(kg, tD, tP);
ray->dD.dx = 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));
+ tD = transform_direction(&cameratoworld,
+ panorama_to_direction(kg,
+ P.x, P.y,
+ kernel_data.cam.width,
+ kernel_data.cam.height,
+ tP.x, tP.y));
Pcamera = spherical_stereo_position(kg, tD, tP);
ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
/* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */
@@ -357,7 +382,7 @@ ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, f
else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
else
- camera_sample_panorama(kg, raster_x, raster_y, lens_u, lens_v, ray);
+ camera_sample_panorama(kg, x, y, raster_x, raster_y, lens_u, lens_v, ray);
}
/* Utilities */
diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h
index c1a359e..88cd507 100644
--- a/intern/cycles/kernel/kernel_projection.h
+++ b/intern/cycles/kernel/kernel_projection.h
@@ -189,7 +189,183 @@ ccl_device float2 direction_to_mirrorball(float3 dir)
return make_float2(u, v);
}
-ccl_device float3 panorama_to_direction(KernelGlobals *kg, float u, float v)
+/* Cubemap coordinates <-> Cartesian direction */
+
+/* Get horizontal scaling factor to make it so cubemap side has an overscan
+ * of two pixels.
+ */
+ccl_device_inline float cubemap_scaling_x(float raster_width)
+{
+ const float side_wideh = raster_width / 3.0f;
+ return side_wideh / (side_wideh - 4.0f);
+}
+
+/* Get vertical scaling factor to make it so cubemap side has an overscan
+ * of two pixels.
+ */
+ccl_device_inline float cubemap_scaling_y(float raster_height)
+{
+ const float side_height = raster_height / 2.0f;
+ return side_height / (side_height - 4.0f);
+}
+
+/* Adjust normalized coordinates to include an overscan. */
+ccl_device_inline float cubemap_forward_x(float x, float raster_width)
+{
+ return x * cubemap_scaling_x(raster_width);
+}
+
+ccl_device_inline float cubemap_forward_y(float y, float raster_height)
+{
+ return y * cubemap_scaling_y(raster_height);
+}
+
+/* Adjust normalized coordinates to remove an overscan.
+ *
+ * NOTE: Only does scaling, still need to include translation to the result.
+ */
+ccl_device_inline float cubemap_backward_x(float x, float raster_width)
+{
+ return x / cubemap_scaling_x(raster_width);
+}
+
+ccl_device_inline float cubemap_backward_y(float y, float raster_height)
+{
+ return y / cubemap_scaling_y(raster_height);
+}
+
+/* Adjust normalized cube map projection coordinate (which is in [-1..1] range)
+ * to remove an overscan and get normalized texture coordinate.
+ *
+ * NOTE: Similar to cubemap_backward functions only does scaling, trnalsation
+ * should be applied separately.
+ */
+ccl_device_inline float cubemap_projection_backward_x(float x,
+ float raster_width)
+{
+ return cubemap_backward_x((x * 0.5f) + 0.5f, raster_width);
+}
+
+ccl_device_inline float cubemap_projection_backward_y(float x,
+ float raster_height)
+{
+ return cubemap_backward_y((x * 0.5f) + 0.5f, raster_height);
+}
+
+ccl_device float2 direction_to_cubemap(float3 dir,
+ float raster_width, float raster_height)
+{
+ /* We require direction to be normalized. */
+ float3 normalized_dir = normalize(dir);
+ /* Calculate barycentric coordinates in an equilateral triangle
+ * to see which side of a cube direction point to.
+ *
+ * See comments svm_node_tex_image_box() about how it works.
+ */
+ float3 abs_N = make_float3(fabsf(normalized_dir.x),
+ fabsf(normalized_dir.y),
+ fabsf(normalized_dir.z));
+ float den = max(max(abs_N.x, abs_N.y), abs_N.z);
+ /* Project point to a closest side of a cube.
+ * After such projeciton one coordinate is either -1.0 or 1.0 and others
+ * are in a -1.0 .. 1.0 range.
+ */
+ float3 P = normalized_dir / den;
+ float u, v;
+ if(abs_N.x == den) {
+ if(P.x < 0.0f) {
+ /* Left view. */
+ u = cubemap_projection_backward_x(P.y, raster_width) / 3.0f + 1.0f / 3.0f;
+ v = cubemap_projection_backward_y(P.z, raster_height) * 0.5f;
+ }
+ else {
+ /* Right view. */
+ u = cubemap_projection_backward_x(-P.y, raster_width) / 3.0f + 1.0f / 3.0f;
+ v = cubemap_projection_backward_y(P.z, raster_height) * 0.5f + 0.5f;
+ }
+ }
+ else if(abs_N.y == den) {
+ if(P.y > 0.0f) {
+ /* Front view. */
+ u = cubemap_projection_backward_x(P.x, raster_width) / 3.0f;
+ v = cubemap_projection_backward_y(P.z, raster_height) * 0.5f;
+ }
+ else {
+ /* Back view. */
+ u = cubemap_projection_backward_x(P.x, raster_width) / 3.0f;
+ v = cubemap_projection_backward_y(P.z, raster_height) * 0.5f + 0.5f;
+ }
+ }
+ else {
+ if(P.z < 0.0f) {
+ /* Bottom view. */
+ u = cubemap_projection_backward_x(P.x, raster_width) / 3.0f + 2.0f / 3.0f;
+ v = cubemap_projection_backward_y(P.y, raster_height) * 0.5f;
+ }
+ else {
+ /* Top view. */
+ u = cubemap_projection_backward_x(P.x, raster_width) / 3.0f + 2.0f / 3.0f;
+ v = cubemap_projection_backward_y(-P.y, raster_height) * 0.5f + 0.5f;
+ }
+ }
+ u += 2.0f / raster_width;
+ v += 2.0f / raster_height;
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list