首页
|
新闻
|
新品
|
文库
|
方案
|
视频
|
下载
|
商城
|
开发板
|
数据中心
|
座谈新版
|
培训
|
工具
|
博客
|
论坛
|
百科
|
GEC
|
活动
|
主题月
|
电子展
注册
登录
论坛
博客
搜索
帮助
导航
默认风格
uchome
discuz6
GreenM
»
消费电子
» 光线追踪技术的理论和实践(面向对象)2
返回列表
回复
发帖
发新话题
发布投票
发布悬赏
发布辩论
发布活动
发布视频
发布商品
光线追踪技术的理论和实践(面向对象)2
发短消息
加为好友
rise_ming
当前离线
UID
864567
帖子
4448
精华
0
积分
2224
阅读权限
70
在线时间
123 小时
注册时间
2011-12-12
最后登录
2014-8-25
金牌会员
UID
864567
1
#
打印
字体大小:
t
T
rise_ming
发表于 2013-7-23 22:46
|
只看该作者
光线追踪技术的理论和实践(面向对象)2
技术
,
而且
,
能力
CGObject类成员变量有五个,分别表示物体表面环境光反射系数(m_Ka),漫反射系数(m_Kd),镜面反射系数(m_Ks),镜面反射强度(m_Shininess)和环境反射强度(m_Reflectivity)。前四个变量是计算光照所需要的最基本量,而环境反射强度表示该物体能反射环境的能力。这些成员变量都的类型都是protected,因为我们要把CGObject最为物体的基类,这些protected成员变量可以被该类的子类所继承。该类的所有get方法和set方法都能被子类继承,而且所有继承了该类的子类的方法都相同。该类还有两个虚成员函数,分别是getNormal()和isIntersected()。getNormal()函数的作用是获取物体表面一点的法线,它接受一个GVector3类型的参数_Point,并返回物体表面点_Point处的法线。当然不同物体表面获得法线的方法是不一样的。比如,对于平面来说,平面上所有点的法线都是一样的。而对于球来说,球面上每一个的法线是球面上的该交点p和球心的c的差向量。
NSphere = p - c
所以将getNormal()设置为虚成员函数就可以实现类的多态性,凡是继承了该方法的子类,都可以实现自己的getNormal()方法。同样的道理,函数isInserted也是虚成员函数,该方法接受参数射线CRay
和距离Distance,CRay是输入参数,用于判断射线和该物体的交点,Distance是输出参数,如果物体和射线相交,则返回相机到该交点的距离。Distance还应该有个很大初始值,表示在无限远处物体和射线相交,这种情况用于判断物体和射线没有交点。函数isIntersected()还返回一个枚举类型INTERSECTION_TYPE,定义如下:
enum INTERSECTION_TYPE {INTERSECTED_IN = -1, MISS = 0, INTERSECTED = 1};
其中INTERSECTED_IN表示射线从物体内部出发并和物体有交点,MISS射线和物体没有交点,INTERSECTED表示射线从物体外部出发并且和物体有交点。射线和不同物体交点的计算方法不同,于是该函数为虚函数,继承该函数的子类可以实现自己的isIntersected()方法。下面的代码就可以判断一条射线和场景中所有物体的是否有交点,并且返回离相机最近的一个。
double distance = 1000000; // 初始化无限大距离
GVector3 Intersection; // 交点
for(int i = 0; i
{
CGObject *obj = objects_list
;
if( obj->isIntersected(ray, distance) != MISS) // 判断是否有交点
{
Intersection = ray.getPoint(distance); //如果相交,求出交点保存到Intersection
}
}
为了计算方便,这里就以球为例,创建一个CSphere的类,该类继承于CGObject。
作为球,只需要提供球心Center和半径Radius就可以决定它的几何性质。所以CSphere类只有两个私有成员变量。在所有成员函数中,我们重点来看看isIntersected()方法。
INTERSECTION_TYPE CSphere::isIntersected(CRay _ray, double& _dist)
{
GVector3 v = _ray.getOrigin() - m_Center;
double b = -(v * _ray.getDirection());
double det = (b * b) - v*v + m_Radius;
INTERSECTION_TYPE retval = MISS;
if (det > 0){
det = sqrt(det);
double t1 = b - det;
double t2 = b + det;
if (t2 > 0){
if (t1 < 0) {
if (t2 < _dist) {
_dist = t2;
retval = INTERSECTED_IN;
}
}
else{
if (t1 < _dist){
_dist = t1;
retval = INTERSECTED;
}
}
}
}
return retval;
}
如果射线和球有交点,那么交点肯定在球面上。球面上的点P都满足下面的关系,
| P – C | = R
很明显球面上的点和球心的差向量的大小等于球的半径。然后将射线的参数方程带入上面的公式,再利用求根公式判断解的情况。具体的方法这里就不详述了,有兴趣的同学可以参考另一篇文章“利用OpenGL实现RayPicking”,这篇文章详细讲解了射线和球交点的计算过程。
现在我们实现了射线CRay,球体CSphere,还差一个重要的角色——光源。光源也是物体的一种,完全可以从我们的基类CGObject类继承。这里做一点区别,我们单独创建一个所有光源的基类CLightSource,然后从它在派生出不同的光源种类,比如平行光源DirectionalLight,点光源CPointLight和聚光源CSpotLight。本文中只详细讲解平行光源的情况,其他两种光源有兴趣的同学可以自己实现。
类CLightSource的成员变量有四个,分别表示光源的位置,光源的环境光成分,漫反射成分和镜面反射成分。同样地,所有的set和get方法都为该类的子类提供相同的功能。最后也有三个虚成员函数,EvalAmbient(),EvalDiffuse()和EvalSpecular(),它们名字分别说明它们的功能,并且都返回GVector3类型的值——颜色。由于对于不同种类的光源,计算方法可能不同,于是将它们设置为虚函数为以后的扩展做准备。笔者这里将光照计算放在了光源类里面,当然你也可以放在物体类CGObject里,也可以单独写一个方法,将光源和物体作为参数传入,计算出颜色后最为返回值返回。具体使用哪一种好还是要根据具体情况具体分析。
上面的平行光源类CDirectionalLight是CLightSource的子类,它继承了父类三个虚函数方法。下面来看看这三个函数的具体实现。
环境光的计算是最简单的,将物体材质环境反射系数和光源的环境光成分相乘即可。
ambient = Ia•Ka
计算环境光的代码如下
GVector3 CDirectionalLight::EvalAmbient(const GVector3& _material_Ka)
收藏
分享
评分
回复
引用
订阅
TOP
返回列表
电商论坛
Pine A64
资料下载
方案分享
FAQ
行业应用
消费电子
便携式设备
医疗电子
汽车电子
工业控制
热门技术
智能可穿戴
3D打印
智能家居
综合设计
示波器技术
存储器
电子制造
计算机和外设
软件开发
分立器件
传感器技术
无源元件
资料共享
PCB综合技术
综合技术交流
EDA
MCU 单片机技术
ST MCU
Freescale MCU
NXP MCU
新唐 MCU
MIPS
X86
ARM
PowerPC
DSP技术
嵌入式技术
FPGA/CPLD可编程逻辑
模拟电路
数字电路
富士通半导体FRAM 铁电存储器“免费样片”使用心得
电源与功率管理
LED技术
测试测量
通信技术
3G
无线技术
微波在线
综合交流区
职场驿站
活动专区
在线座谈交流区
紧缺人才培训课程交流区
意见和建议