光线追踪发射主光线

光线追踪是图形学领域里最为著名的一种技术,其中首要的一步是视点(相机,眼睛)穿过像素中心,发射一条射线,也就是主光线(次级光线指的是从物体表面反射或折射等发出的光线)。这一步看起来比较简单,但仍然涉及到一些细节和概念需要厘清。
我系统的学习这些东西是从renderman规范开始的,看的第一本书是advanced renderman,这本比较难,我更推荐看An Introduction to Ray Tracing (1989)。
开始正题。首先,要搞清楚fov角,advanced renderman上会讲到焦距,讲的非常细致深入,如果要深挖可以看书,我就不谈了(毕竟我也不记得了)。相机所看到的三维场景是一个视锥体,也叫平截头体,如下图:

顶点处会有两个角度,一个大,一个小,小的那个就是fov角,大的那个具体多大是由我们看到的屏幕的宽高比决定的。比如,屏幕宽和高分别是width=640,height=480,小的fov角为fov_little,大的那个角度是not_fov_but_big,有如下关系:tan(fov_little/2)/tan(not_fov_but_big/2) = height/width。fov角是做什么用的呢?它决定了我们能看到的视锥体的角度,或者更直白的说,决定了我们能看到的世界的大小,当然,这样说也不准确,我们仍然讲前面这个例子,屏幕的宽和高分别是640和480,眼睛朝着正前方看去,fov角决定的就是眼睛的上下所能看到的世界的范围,而左右所能看到的范围则由640决定,如果宽变成了1000,自然能看到的就会更多,如果不是这样,1000和640看到的世界是一样的,那么必然会导致图像的拉伸,通常这不是我们想要的结果。而另一方面,如果宽变小,自然看到的世界就会变小;但如果宽小于480,那么fov角又变成了决定眼睛左右所能看的世界的范围了。

然后,我们穿过像素发射光线,像素所在的空间是光栅化空间,比如,宽是从0到639,高是从0到479,但我们现在需要在三维世界(相机坐标系)里发射光线,所以我们需要把像素(px,py)变换到三维世界中去(wx,wy,wz)。如果我们已经变换过去从而得到了(wx,wy,wz),那么连接相机所在的点(0,0,0)和(wx,wy,wz),就是我们想要的射线。怎么做这个变换呢?直观的看,就是把这块屏幕(640,480)放到三维世界中,使得z轴穿过屏幕中心(忘了说一点,本文基于renderman讨论,所以相机朝向z轴正方向),同时屏幕的x轴(0~639)和三维世界的x轴平行,屏幕的y轴(0~479)和三维世界的y轴平行。由此,我们引入另一个坐标系,屏幕坐标系,其实就是把光栅化空间归一化,把0~479变到-1~1,相应的0~639变到-1.333~1.333。(这只是一种约定,或者较为方便的做法,数值上并不是非要如此)然后,我们把归一化的屏幕放到planez=cot(fov/2)的位置,此时,屏幕刚好和平截头体内切(不知道准确的叫法,反正就是刚好在平截头体内部,再大一点就会出来),如图:


然后说一下变换,对于任意像素(px,py),先做一个平移,使得z轴穿过屏幕中心,平移之后得到,px1 = px - width/2,py1 = py - height/2,(此处只讨论宽和高都能被2整除的情形)。然后,需要注意,我们是从像素点的中心发射光线,而px1和py1是像素左上角的坐标,所以需要把它们加0.5,得到px2 = px1 + 0.5,py2 = py1 + 0.5,然后,做归一化,px2和py2同除以height/2,px3 = px2 / (2*height),py3 = py2 / (2*height),这就是我们最终想要的屏幕空间的坐标。注意,我们把屏幕放在了planez=cot(fov/2)的位置,所以,我们已经得到了射线与屏幕空间相交的三维坐标(px3,py3,planez)。我们已知射线的起点是(0,0,0),且射线经过点(px3,py3,planez),根据相似三角形的性质,可以得到射线在z=z0时,经过的点是(px3/planez*z0,py3/planez*z0,z0)。连接射线起点(0,0,0)和射线上任意点都可以得到我们所需要的向量,所以,我们可以选择z=planez的点,也可以选z=z0(比如是1)的点。得到的向量归一化之后是一样的。

如果我不能把事情讲清楚,我是会有很强的挫败感的,所以我努力准确的去表达,同时希望对方能精确的提问,比如说清楚自己哪里懂了,哪里不懂,不太确定的地方就说一下自己的理解,看对不对,觉得很困惑的地方也可以说一下自己认为的应该是什么样子,问为什么不是这样。懂得倾听是非常好的美德,但交流问题的时候,还是应该适当的发表自己的观点,对错并不重要,重要的是你说了自己的想法,别人就知道你哪里没搞清楚,哪里搞清楚了,更有针对性的去解释,否则,回答者会有一种在森林里迷路的感觉,一会问一下A问题,一会问一下B问题,完全不知道你搞清楚了哪些没搞清楚哪些,会很挫败很苦恼。还是那个道理,我们做任何事情,都是需要激励的,无论来自外界的,还是自我的,解释问题也是一样,回答方希望提问方给出明确的反馈,这个问题的哪些子问题搞明白了,但另一些子问题没搞明白,这样,一方面,回答方受到了激励,就不会觉得辛苦,另一方面,再回答的时候也会更有针对性。

时间: 2024-10-23 09:59:15

光线追踪发射主光线的相关文章

全局光照:光线追踪、路径追踪与GI技术进化编年史

全局光照(Global Illumination,简称 GI), 作为图形学中比较酷的概念之一,是指既考虑场景中来自光源的直接光照,又考虑经过场景中其他物体反射后的间接光照的一种渲染技术. 大家常听到的光线追踪,路径追踪等同样很酷的概念,都是全局光照中人气较高的算法流派. 而这篇文章将围绕全局光照技术,介绍的要点有: 全局光照的基本概念 全局光照的算法主要流派 全局光照技术进化编年史 光线追踪 Ray Tracing 路径追踪 Path Tracing 光线追踪.路径追踪.光线投射的区别 环境光

【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-5 random direction & ONB

 Preface 往后看了几章,对这本书有了新的理解 上一篇,我们第一次尝试把MC积分运用到了Lambertian材质中,当然,第一次尝试是失败的,作者发现它的渲染效果和现实有些出入,所以结尾处声明要通过实践,改进当前的效果 于是乎,就有了后面的章节,几乎整本书都在讲,如何一步一步地改进上一篇的画质,使其更加符合现实,上一篇其实是抛砖引玉 这本书的小标题名为the rest of your life 通过前面几章,我们可以更好地理解这句话:我们通过MC积分优化效果,采用的是pdf函数,之前说过,

洛谷P1901 发射站

P1901 发射站 245通过 468提交 题目提供者该用户不存在 标签NOI导刊云端↑ 难度普及/提高- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 大神路过的看一下 输入后面为什么带空格. 有人说是单调队列,但不明明- 题目描述 某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(当 然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比 它高的发射站接收. 显然,每个发射站发来的能量有可能被 0 或

【经典程序】STC89C52RC 12M红外二极管发射测试成功

/* 89C52RC 12M晶振  红外发射试验, 在红外解码和机顶盒上都测试可用! 发射的编码是      SendIRdata(0x48,0x77,0x01);这个一个向下的按键编码 红外发射管的正极接VCC 5V 红外发射管的负极接21号引脚  */ #include <REG51.h>  static bit wave;              //红外发射管的亮灭 static unsigned int count;    //延时计数器 static unsigned int e

win10笔记本怎么发射无线信号

1.通过命令查看网卡是否可以做发射热点用.看图,点运行后输入"cmd",然后在黑框框里输入 netsh wlan show drivers 看图中红框内,如果是"是",恭喜你,你可以的.如果是"否",就不行了. 2.启用并设定虚拟WiFi网卡:运行命令:netsh wlan set hostednetwork mode=allow ssid=Diligent key=password此命令有三个参数,如下:mode:是否启用虚拟WiFi网卡,改为

一个光线追踪demo

去年写的一个练手项目,完成了三维场景的光线追踪,基于Phong模型. 支持的基本类型为球和矩形,其中矩形支持函数纹理贴图. 直接上图: 图中只有一个球,左侧为一个镜子. 左侧为一个折射率为1.5的折射球,右侧为一个全反射球. http://files.cnblogs.com/files/PiedmontStream/trace.zip

stc89c52开发板遥控器解码 红外线发射 内置 eeprom 存储 串口显示编码

单片机,大概三年前,就买了一本 <爱上单片机> 最后就学会,用面包板了,编程书上基本没讲. 看原理图,看时序图,看数据手册, 都没讲. 而且书上自带的代码写的很烂. 1,缩近控制不好 2,命名混乱 3,做if 的时候 不变的常量放在左侧,这是很基本的约定 ... 最后,还是什么也没有学会. 直到去年,开始学 ARM 了. 学完了 ARM 前面发的(s3c2440)以后, 在回头看单片机,发现单片机真是,简单的不得了! 但是也发现,单片机,不如 ARM 功能强大.速度也慢.很多控制器,没有,要用

PyQt4发射信号

继承自QtCore.QObject的对象均可以发射信号.如果我们单击一个按钮,那么一个clicked()信号就会被触发.下面的示例演示如何手动发射一个信号. #!/usr/bin/python # -*- coding: utf-8 -*- import sys from PyQt4 import QtGui, QtCore class Emit(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__init__(s

cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第十步---发射子弹&amp;怪物受伤---所有源码和资源完结下载

好吧,到这一步,整个游戏基本上弄完啦,由于自己的水平也就这样.....重写的过程中很多细节处理的不好. 游戏中很多地方都留下了可扩充的代码,可是时间方面有点不够...而且也没美工 本次笔记内容: 1.思路&代码&效果展示 2.完结代码&资源下载 一:思路&代码 后面的内容基本上是木头书上的内容,没什么太大修改 和之前很多地方一样,把子弹单独抽离出来,然后绑定在英雄身上,那么英雄就可以带着子弹进行攻击 这样也方便之后的扩展.....毕竟这个游戏很多地方都是基本的,但是也留给可