基于光线追踪的Mental Ray鱼眼镜头的编程实现

基于光线追踪的Mental Ray鱼眼镜头的编程实现

作者:华文广                                                                                   日期2010/12/3

一、什么是鱼眼镜头

从摄影识知来讲,鱼眼镜头是一种焦距约在6-16毫米之间的短焦距超广角摄影镜头,“鱼眼镜头”是它的俗称。为使镜头达到最大的摄影视角,这种摄影镜头的前镜片直径且呈抛物状向镜头前部凸出,与鱼的眼睛颇为相似,“鱼眼镜头”因此而得名。


    鱼眼镜头最大的作用是增大视角范围,视角一般可达到220·或230·,这为近距离拍摄大范围景物创造了条件;鱼眼镜头在接近被摄物拍摄时能造成非常强烈的透视效果,强调被摄物近大远小的对比,使所摄画面具有一种震撼。如下图所示:

    在现实应用中,也有很多地方会用到鱼眼镜头,最常见的就是球幕投影。图片经过鱼眼变形之后,再反投回到球幕上,就能得到正常的视觉效果。

二、在Mental Ray中模拟鱼眼镜头的实现

MAYA中,相机的镜头都是平面的。要想渲染出鱼眼效果,就得做一些特别处理。在网上,我们也能找到几种不同的解决方案。方案一,使用天空盒技术,就是分别渲染前后左右上下六个面组成一个天空盒,然后再在天空盒里面放一个球进行境面反射,这种方案有个优点就是渲染速度比较快,如果配置合理,完全可以达到实时的要求。关于这种实现方案,这个网址http://strlen.com/gfxengine/fisheyequake/上有比较长详细的介绍。然而,这个技术也有一些不缺点,比如,如果场景的灯光与摄像机的视线方向有光,那么六张图的明暗效果就没办法平滑过渡。方案二、使用多图拼接技术,就是从不同角度拍一系列图片,然后用拼接软件,把这些图片自动拼成一张360度全景图,Autodesk Stitcher Unlimited就是一个非常优秀的全景图制作工具,当然,这个方案对于制作人员来说,工作量也是相当巨大的。

 

 

在这里我们详细介绍一下第三种解决方案,就是基于光线追踪的鱼眼镜头的模拟实现。我们知道,Mental Ray是一款非常出色的基于光线追踪的渲染工具。正常情况下,摄像机发    

a

   

 


射出来的光线是沿直线方向投射到场景中去的,如果a所示:

如果我们能截获这个光线,然后改变它的前进方向,便能很容易实现鱼眼效果,如图b所示,在相机前加入一个半球形的镜头,然后再根据光的折射原理,计算新的光线方向。以下就是鱼眼镜头的实现代码:

 

#include "math.h"

#include <mi_version.h>

#include <shader.h>

#include <geoshader.h>       

 

#include <stdio.h>

#include <math.h>

#include "shader.h"

 

#define EPSILON 0.00001

 

// 定义一个输入参数结构体,用于从MAYA属性窗口来改变该变量

struct ben_fisheye_lens_FOV {

         miScalar FOV_Angle; // Fisheye FOV 视野角度

 

};

 

extern "C" DLLEXPORT int ben_fisheye_lens_version(void) {return(1);}

extern "C" DLLEXPORT miBoolean ben_fisheye_lens(

                                     miColor  *result,

                                     miState  *state,

                                     register  struct  ben_fisheye_lens_FOV *params)

{

         miScalar fov_angle_deg = *mi_eval_scalar(&params->FOV_Angle);

         miGeoScalar fov_angle_rad;

 

         miVector ray;

         miGeoScalar x, y, r, phi, theta;

 

         // 单位化 [-1,1]...

         x = (2.0 * state->raster_x) / state->camera->x_resolution - 1.0;

         y = (2.0 * state->raster_y) / state->camera->y_resolution - 1.0;

 

         // 根据像素坐标,来计算该像素离中心的半。

         r = MI_SQRT( ( x * x ) + ( y * y ) );

 

         if ( r < 1.0 ) {

                   // 根据球面坐标公式来计算 phi...

                   if ( (r > -EPSILON) && (r < EPSILON) ) {

                            phi = 0.0;

                   } else {

 

                            if ( x < EPSILON ) {

                                     phi = M_PI - asin( y / r );

                            } else {

                                     phi = asin( y / r );

                            }

                   }

 

                   // 把输入的角度值转换为弧度

                   fov_angle_rad = fov_angle_deg * M_PI / 180.0;

                  

                   // 计算 theta...

                   theta = r * ( fov_angle_rad / 2.0 );

 

                   // 计算新的光线的方向,沿球面法线方向

                   ray.x = (float)(sin(theta) * cos(phi));

                   ray.y = (float)(-sin(theta) * sin(phi));

                  

                   // 这里我们假定相机的视线方向是 -Z

                   ray.z = (float)(-cos(theta));

 

                   // 把光线转换为相机空间

                   mi_vector_from_camera(state, &ray, &ray);

                   // 发射新的改变方向之后的光线

                   return(mi_trace_eye(result, state, &state->org, &ray));

         } else {

                   result->r = result->g =

                            result->b = result->a = 0;

                   return(miFALSE);

         }

 

} /* end of ben_fisheye_lens() */

 

 

把以上代码放在VC++中编译成一个ben_fisheye_lens .dll,这样一个基于Mental Ray 的鱼眼镜头就开发完成了。

我们知道,光线追踪的光线发射是从相机窗口的每个像素出发的,那么,基于像素的二维的图像坐标,如何转换成球面坐标系的角度坐标呢?这里Paul Bourke给我们提供了一个方案:

 

 

 

 

逆向运算如下:

u = r cos(phi) + 0.5
v = r sin(phi) + 0.5

转换成球面坐标。

r = atan2(sqrt(x*x+y*y),p.z) / pi
phi = atan2(y,x)

 

三、安装和使用

安装我们编译好的鱼眼镜头插件。首先,用记事本新建一个ben_fisheye_lens.mi文件,然后把下面脚本写入到这个mi文件中去:

declare shader

        color "ben_fisheye_lens" (

                   scalar " FOV_Angle ",       #: softmin 0.0 softmax 360.0 default 180.0

        )

         apply lens

    version 1

end declare

 

完成之后,把ben_fisheye_lens.dll文件拷贝到:/Mayax.x/mentalray/lib文件夹,把ben_fisheye_lens.mi文件拷贝到/Mayax.x/mentalray/include文件甲。

 

打开MAYA,你就可以在mental rayShader中看到你所编译的鱼眼镜头了,新建一个镜头shader然后指定到MAYA的相机属性的镜头参数中去,这个你渲出来的图片,就会有鱼眼效果了。

 

 


         以上是一个简单的例子,用来解析如何编写一个Mental Ray 的镜头。事实上,如果我们能理解透彻光线追踪的原理,我们可以用其它你所相要的方式来改变光线的方线,从而实现不同的镜头效果,如环幕镜头,球幕镜头,天空盒镜头等等。

环幕全景镜头效果图

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页