[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [46287] trunk/blender: Fisheye Camera for Cycles

Dalai Felinto dfelinto at gmail.com
Fri May 4 18:20:53 CEST 2012


Revision: 46287
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=46287
Author:   dfelinto
Date:     2012-05-04 16:20:51 +0000 (Fri, 04 May 2012)
Log Message:
-----------
Fisheye Camera for Cycles

For sample images see:
http://www.dalaifelinto.com/?p=399 (equisolid)
http://www.dalaifelinto.com/?p=389 (equidistant)

The 'use_panorama' option is now part of a new Camera type: 'Panorama'.
Created two other panorama cameras:

- Equisolid: most of lens in the market simulate this lens - e.g. Nikon, Canon, ...)
             this works as a real lens up to an extent. The final result takes the
             sensor dimensions into account also.
             .:. to simulate a Nikon DX2S with a 10.5mm lens do:
                 sensor: 23.7 x 15.7
                 fisheye lens: 10.5
                 fisheye fov: 180
                 render dimensions: 4288 x 2848

- Equidistant: this is not a real lens model. Although the old equidistant lens simulate
               this lens. The result is always as a circular fisheye that takes the whole sensor
               (in other words, it doesn't take the sensor into consideration).
               This is perfect for fulldomes ;)

               For the UI we have 10 to 360 as soft values and 10 to 3600 as hard values (because we can).


Reference material:
http://www.hdrlabs.com/tutorials/downloads_files/HDRI%20for%20CGI.pdf
http://www.bobatkins.com/photography/technical/field_of_view.html

Note, this is not a real simulation of the light path through the lens.
The ideal solution would be this:
https://graphics.stanford.edu/wikis/cs348b-11/Assignment3
http://www.graphics.stanford.edu/papers/camera/


Thanks Brecht for the fix, suggestions and code review.
Kudos for the dome community for keeping me stimulated on the topic since 2009 ;)

Patch partly implemented during lab time at VisGraf, IMPA - Rio de Janeiro.

Modified Paths:
--------------
    trunk/blender/intern/cycles/app/cycles_xml.cpp
    trunk/blender/intern/cycles/blender/addon/enums.py
    trunk/blender/intern/cycles/blender/addon/properties.py
    trunk/blender/intern/cycles/blender/blender_camera.cpp
    trunk/blender/intern/cycles/kernel/kernel_camera.h
    trunk/blender/intern/cycles/kernel/kernel_montecarlo.h
    trunk/blender/intern/cycles/kernel/kernel_path.h
    trunk/blender/intern/cycles/kernel/kernel_types.h
    trunk/blender/intern/cycles/render/camera.cpp
    trunk/blender/intern/cycles/render/camera.h
    trunk/blender/release/scripts/startup/bl_ui/properties_data_camera.py
    trunk/blender/source/blender/blenkernel/intern/camera.c
    trunk/blender/source/blender/blenlib/intern/uvproject.c
    trunk/blender/source/blender/blenloader/intern/readfile.c
    trunk/blender/source/blender/collada/CameraExporter.cpp
    trunk/blender/source/blender/makesdna/DNA_camera_types.h
    trunk/blender/source/blender/makesrna/intern/rna_camera.c
    trunk/blender/source/blender/modifiers/intern/MOD_uvproject.c

Modified: trunk/blender/intern/cycles/app/cycles_xml.cpp
===================================================================
--- trunk/blender/intern/cycles/app/cycles_xml.cpp	2012-05-04 16:17:09 UTC (rev 46286)
+++ trunk/blender/intern/cycles/app/cycles_xml.cpp	2012-05-04 16:20:51 UTC (rev 46287)
@@ -290,9 +290,23 @@
 		cam->type = CAMERA_ORTHOGRAPHIC;
 	else if(xml_equal_string(node, "type", "perspective"))
 		cam->type = CAMERA_PERSPECTIVE;
-	else if(xml_equal_string(node, "type", "environment"))
-		cam->type = CAMERA_ENVIRONMENT;
+	else if(xml_equal_string(node, "type", "panorama"))
+		cam->type = CAMERA_PANORAMA;
 
+	if(xml_equal_string(node, "panorama_type", "equirectangular"))
+		cam->panorama_type = PANORAMA_EQUIRECTANGULAR;
+	else if(xml_equal_string(node, "panorama_type", "fisheye_equidistant"))
+		cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
+	else if(xml_equal_string(node, "panorama_type", "fisheye_equisolid"))
+		cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
+
+	xml_read_float(&cam->fisheye_fov, node, "fisheye_fov");
+	xml_read_float(&cam->fisheye_lens, node, "fisheye_lens");
+
+	xml_read_float(&cam->sensorwidth, node, "sensorwidth");
+	xml_read_float(&cam->sensorheight, node, "sensorheight");
+
+
 	cam->matrix = state.tfm;
 
 	cam->need_update = true;

Modified: trunk/blender/intern/cycles/blender/addon/enums.py
===================================================================
--- trunk/blender/intern/cycles/blender/addon/enums.py	2012-05-04 16:17:09 UTC (rev 46286)
+++ trunk/blender/intern/cycles/blender/addon/enums.py	2012-05-04 16:20:51 UTC (rev 46287)
@@ -54,3 +54,9 @@
     ('RADIUS', "Radius", "Directly change the size of the aperture"),
     ('FSTOP', "F/stop", "Change the size of the aperture by f/stops"),
     )
+
+panorama_types = (
+    ('EQUIRECTANGULAR', "Equirectangular", "Render the scene with a spherical camera, also known as Lat Long panorama"),
+    ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"),
+    ('FISHEYE_EQUISOLID', "Fisheye Equisolid", "Similar to most fisheye modern lens, take sensor dimensions into consideration"),
+    )

Modified: trunk/blender/intern/cycles/blender/addon/properties.py
===================================================================
--- trunk/blender/intern/cycles/blender/addon/properties.py	2012-05-04 16:17:09 UTC (rev 46286)
+++ trunk/blender/intern/cycles/blender/addon/properties.py	2012-05-04 16:20:51 UTC (rev 46287)
@@ -278,6 +278,25 @@
                 subtype='ANGLE',
                 default=0,
                 )
+        cls.panorama_type = EnumProperty(
+                name="Panorama Type",
+                description="Distortion to use for the calculation",
+                items=enums.panorama_types,
+                default='FISHEYE_EQUISOLID',
+                )
+        cls.fisheye_fov = FloatProperty(
+                name="Field of View",
+                description="Field of view for the fisheye lens",
+                min=0.1745, soft_max=2*math.pi, max=10.0*math.pi,
+                subtype='ANGLE',
+                default=math.pi,
+                )
+        cls.fisheye_lens = FloatProperty(
+                name="Fisheye Lens",
+                description="Lens focal length (mm))",
+                min=0.01, soft_max=15.0, max=100.0,
+                default=10.5,
+                )
 
     @classmethod
     def unregister(cls):

Modified: trunk/blender/intern/cycles/blender/blender_camera.cpp
===================================================================
--- trunk/blender/intern/cycles/blender/blender_camera.cpp	2012-05-04 16:17:09 UTC (rev 46286)
+++ trunk/blender/intern/cycles/blender/blender_camera.cpp	2012-05-04 16:20:51 UTC (rev 46287)
@@ -48,6 +48,10 @@
 
 	float2 pixelaspect;
 
+	PanoramaType panorama_type;
+	float fisheye_fov;
+	float fisheye_lens;
+
 	enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
 	float sensor_width;
 	float sensor_height;
@@ -94,9 +98,37 @@
 		bcam->nearclip = b_camera.clip_start();
 		bcam->farclip = b_camera.clip_end();
 
-		bcam->type = (b_camera.type() == BL::Camera::type_ORTHO)? CAMERA_ORTHOGRAPHIC: CAMERA_PERSPECTIVE;
-		if(bcam->type == CAMERA_PERSPECTIVE && b_camera.use_panorama())
-			bcam->type = CAMERA_ENVIRONMENT;
+		switch(b_camera.type())
+		{
+			case BL::Camera::type_ORTHO:
+				bcam->type = CAMERA_ORTHOGRAPHIC;
+				break;
+			case BL::Camera::type_PANO:
+				bcam->type = CAMERA_PANORAMA;
+				break;
+			case BL::Camera::type_PERSP:
+			default:
+				bcam->type = CAMERA_PERSPECTIVE;
+				break;
+		}	
+
+		switch(RNA_enum_get(&ccamera, "panorama_type"))
+		{
+			case 1:
+				bcam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
+				break;
+			case 2:
+				bcam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
+				break;
+			case 0:
+			default:
+				bcam->panorama_type = PANORAMA_EQUIRECTANGULAR;
+				break;
+		}	
+
+		bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
+		bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
+
 		bcam->ortho_scale = b_camera.ortho_scale();
 
 		bcam->lens = b_camera.lens();
@@ -138,7 +170,7 @@
 {
 	Transform result;
 
-	if(type == CAMERA_ENVIRONMENT) {
+	if(type == CAMERA_PANORAMA) {
 		/* make it so environment camera needs to be pointed in the direction
 		   of the positive x-axis to match an environment texture, this way
 		   it is looking at the center of the texture */
@@ -172,6 +204,9 @@
 	bool horizontal_fit;
 	float sensor_size;
 
+	cam->sensorwidth = bcam->sensor_width;
+	cam->sensorheight = bcam->sensor_height;
+
 	if(bcam->sensor_fit == BlenderCamera::AUTO) {
 		horizontal_fit = (xratio > yratio);
 		sensor_size = bcam->sensor_width;
@@ -203,7 +238,7 @@
 		aspectratio = bcam->ortho_scale/2.0f;
 	}
 
-	if(bcam->type == CAMERA_ENVIRONMENT) {
+	if(bcam->type == CAMERA_PANORAMA) {
 		/* set viewplane */
 		cam->left = 0.0f;
 		cam->right = 1.0f;
@@ -240,6 +275,11 @@
 	/* type */
 	cam->type = bcam->type;
 
+	/* panorama */
+	cam->panorama_type = bcam->panorama_type;
+	cam->fisheye_fov = bcam->fisheye_fov;
+	cam->fisheye_lens = bcam->fisheye_lens;
+
 	/* perspective */
 	cam->fov = 2.0f*atan((0.5f*sensor_size)/bcam->lens/aspectratio);
 	cam->focaldistance = bcam->focaldistance;

Modified: trunk/blender/intern/cycles/kernel/kernel_camera.h
===================================================================
--- trunk/blender/intern/cycles/kernel/kernel_camera.h	2012-05-04 16:17:09 UTC (rev 46286)
+++ trunk/blender/intern/cycles/kernel/kernel_camera.h	2012-05-04 16:20:51 UTC (rev 46287)
@@ -132,17 +132,41 @@
 #endif
 }
 
-/* Environment Camera */
+/* Panorama Camera */
 
-__device void camera_sample_environment(KernelGlobals *kg, float raster_x, float raster_y, Ray *ray)
+__device float3 panorama_to_direction(KernelGlobals *kg, float u, float v, Ray *ray)
 {
+	switch (kernel_data.cam.panorama_type) {
+	case PANORAMA_EQUIRECTANGULAR:
+		return equirectangular_to_direction(u, v);
+		break;
+	case PANORAMA_FISHEYE_EQUIDISTANT:
+		return fisheye_to_direction(u, v, kernel_data.cam.fisheye_fov, ray);
+		break;
+	case PANORAMA_FISHEYE_EQUISOLID:
+	default:
+		return fisheye_equisolid_to_direction(u, v, kernel_data.cam.fisheye_lens, kernel_data.cam.fisheye_fov, kernel_data.cam.sensorwidth, kernel_data.cam.sensorheight, ray);
+		break;
+	}
+}
+
+__device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float raster_y, Ray *ray)
+{
 	Transform rastertocamera = kernel_data.cam.rastertocamera;
 	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);
-	ray->D = equirectangular_to_direction(Pcamera.x, Pcamera.y);
 
+#ifdef __CAMERA_CLIPPING__
+	/* clipping */
+	ray->t = kernel_data.cam.cliplength;
+#else
+	ray->t = FLT_MAX;
+#endif
+
+	ray->D = panorama_to_direction(kg, Pcamera.x, Pcamera.y, ray);
+
 	/* transform ray from camera to world */
 	Transform cameratoworld = kernel_data.cam.cameratoworld;
 
@@ -161,17 +185,11 @@
 	ray->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
 
 	Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
-	ray->dD.dx = normalize(transform_direction(&cameratoworld, equirectangular_to_direction(Pcamera.x, Pcamera.y))) - ray->D;
+	ray->dD.dx = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y, ray))) - ray->D;
 
 	Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
-	ray->dD.dy = normalize(transform_direction(&cameratoworld, equirectangular_to_direction(Pcamera.x, Pcamera.y))) - ray->D;
-#endif
+	ray->dD.dy = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y, ray))) - ray->D;
 
-#ifdef __CAMERA_CLIPPING__
-	/* clipping */
-	ray->t = kernel_data.cam.cliplength;
-#else
-	ray->t = FLT_MAX;
 #endif
 }
 
@@ -198,7 +216,7 @@
 	else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
 		camera_sample_orthographic(kg, raster_x, raster_y, ray);
 	else
-		camera_sample_environment(kg, raster_x, raster_y, ray);
+		camera_sample_panorama(kg, raster_x, raster_y, ray);
 }
 
 CCL_NAMESPACE_END

Modified: trunk/blender/intern/cycles/kernel/kernel_montecarlo.h
===================================================================
--- trunk/blender/intern/cycles/kernel/kernel_montecarlo.h	2012-05-04 16:17:09 UTC (rev 46286)
+++ trunk/blender/intern/cycles/kernel/kernel_montecarlo.h	2012-05-04 16:20:51 UTC (rev 46287)
@@ -224,6 +224,57 @@
 		cos(theta));
 }
 
+/* Fisheye <- Cartesian direction */
+
+__device float3 fisheye_to_direction(float u, float v, float fov, Ray *ray)
+{
+	u = (u - 0.5f) * 2.f;
+	v = (v - 0.5f) * 2.f;
+
+	float r = sqrt(u*u + v*v);
+
+	if (r > 1.0) {
+		ray->t = 0.f;
+		return make_float3(0.f,0.f,0.f);
+	}
+
+	float phi = acosf((r!=0.f)?u/r:0.f);
+	float theta = asinf(r) * (fov / M_PI_F);
+
+	if (v < 0.f) phi = -phi;
+
+	return make_float3(
+		 cosf(theta),
+		 -cosf(phi)*sinf(theta),
+		 sinf(phi)*sinf(theta)
+	);
+}
+
+__device float3 fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height, Ray *ray)
+{
+	u = (u - 0.5f) * width;
+	v = (v - 0.5f) * height;
+
+	float rmax = 2.f * lens * sinf(fov * 0.5f);
+	float r = sqrt(u*u + v*v);
+
+	if (r > rmax) {
+		ray->t = 0.f;
+		return make_float3(0.f,0.f,0.f);
+	}
+
+	float phi = acosf((r!=0.f)?u/r:0.f);
+	float theta = 2.f * asinf(r/(2.f * lens));
+
+	if (v < 0.f) phi = -phi;
+
+	return make_float3(

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list