-
Notifications
You must be signed in to change notification settings - Fork 129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在canvas中模拟光照效果——光照下颜色的计算 #2
Comments
可以,老哥 |
数据可视化靠你带路了 |
想问一下第二个例子里面算光强的时候为什么要使用单位向量呢? |
@asd123freedom 因为光强只和它的方向有关,和计算出来的向量长度没关系。第一个例子也是用单位向量,只是平行光源的方向已经是单位向量了,不需要再计算一下。 |
哈哈哈,同样喜欢可视化的路过。可惜线性代数学的烂,矩阵变换搞不清。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
光照
我们能看到物体,是因为光照射在物体上然后反射到我们的眼睛当中。其中的影响因素非常多:观察者的位置、光源的位置、光的颜色、物体表面的颜色、材质和粗糙程度等等。以后我们将会详细探究如何模拟物体的材质,在这篇文章中我们只讨论光源。
平行光源
太阳的尺度相对地球来说非常大,所以可以认为从太阳照射来的光线都是平行的,即太阳是一个平行光源。
模拟平行光源的光照非常简单,当光垂直照射到平面上,即光线方向和平面呈90度角时,这时光照是最强的。如果照射的角度不断变大(或者说光线和平面的夹角不断变小),光照也会随之变弱,当光线方向完全和平面平行时,这时没有光能照射到平面上,光强变成了0。
可以总结出,平行光的光照情况和两个方向有关:光线的方向和受光照平面的朝向。
我们用一个垂直于平面的向量去描述平面的朝向,在图形学中,一般把这个向量称为“法向量”。
我们可以用向量的“点乘”运算来计算光强变化。
这里我们计算的是三维向量,我们用数组来表示向量,写一个简单的方法来计算点乘:
还有几个重要的向量运算我们也会用到,在这里我们提前定义好,为减小篇幅,这里省略掉具体实现,代码可以看最后的实例源码。
我们假设页面的左上角为原点O,右方向为x轴正方向,下方向为y轴正方向,垂直屏幕向外的方向为z轴正方向。我们可以这样定义一个宽高都为500的平面:
对于平行光,只需要关心它的方向和颜色,我们可以这样来定义一个平行光源:
平行光的光线都是平行的,所以它照射到平面上各个位置的效果都是一样的,换言之,整个平面都应该是同一个颜色。
根据上面的规则(光强等于光线反方向向量点乘平面法向量),我们可以计算出这个颜色:
我写了一个示例,可以调整光线方向来观察不同方向下的光照效果。
在线运行示例
点光源
在日常生活中,点光源更加常见,白炽灯、台灯等都可以认为是点光源。
首先,我们先定义一个点光源,对于一个点光源来说,我们只需要关心它的位置和颜色:
光强的计算规则仍然不变:光强等于光线反方向向量点乘平面法向量。但是点光源的光是从一个点发射出来,它们照射到平面上时,所有光线的方向都不一样。所以,我们必须挨个计算平面上所有像素的光强。
这里需要用到canvas提供的putImageData,这个方法可以直接填入一个区域的像素颜色值来绘图。代码如下:
这样就可以看到结果了:
我写了一个更复杂一点的例子,可以通过鼠标去移动光源,滑动滚轮来改变光源高度:
在线运行示例
动态图看起来有很多圈圈,实际上并没有,可以自己玩一下
WebGL的优势
对于一个
500*500
的平面,我们去计算它在点光源光照下的颜色,需要挨个计算平面上所有点,需要循环500*500=250000
次,这其实是非常低效的。并且在做复杂场景的渲染时,不会只有一个光源,而且还会有投影等计算,计算量将会非常大。从更底层的角度来说,这是因为每次计算都是由CPU完成的,而CPU只能串行计算,它只能完成一个计算以后才能开始下一次计算,所以非常缓慢。
这种复杂的渲染其实更适合用WebGL来做,因为每一次计算其实前后无关,WebGL可以利用GPU的并行计算能力,同时去计算所有点的光照强度。一个
500*500
的平面,理论上只需要花一次计算的时间,这个提升是非常大的。这篇文章也是想通过这个简单的光照计算来引出WebGL,后面的文章我会用WebGL来重新实现这个效果。
WebGL渲染的光照效果
关于我的博客
这篇文章到这里就结束了。
我计划写一系列关于前端图形渲染的文章,将会涵盖常用的前端图形绘制技术:canvas、svg和WebGL。希望通过这一系列文章能让读者对前端的各种图形绘制接口以及图像处理、图形学的基础知识有所了解。希望在分享的同时,也能巩固和复习自己所学知识,和大家共同进步。
如果能帮助到你,欢迎star,这样也能及时追踪博客的更新。
The text was updated successfully, but these errors were encountered: