回顾上一篇 ShaderToy入门教程(1) - SDF 和 Raymarching 算法

继续上篇,这篇涵盖以下黑体所示内容

  • 符号距离函数
  • Ray-marching算法
  • 曲面法线和光照
  • 相机变换
  • 构造实体形状(CSG)
  • 模型变换
    • 平移和旋转
    • 比例缩放
    • 非均匀缩放
  • 结论
  • 参考

曲面法线和光照

计算机图形中的大多数光照模型使用曲面法线的概念来计算材料在表面上的给定点处应该是什么颜色。 当曲面由显式几何体(如多边形)定义时,通常会为每个顶点指定法线,在表面上的给定点的法线通过它周围的顶点法线通过插值计算获得。

那么我们如何找到由有符号距离函数定义的场景曲面法线? 利用梯度! 从概念上讲,函数fff在(x,y,z)(x,y,z)(x,y,z)处的梯度告诉你从(x,y,z)(x,y,z)(x,y,z)向哪个方向移动将最快增加fff的值。
这是直觉:对于表面上的一个点,fff(我们的SDF),评估为零。在该表面的内侧,fff变为负,而在外侧,它变为正。 因此,表面上最快速地从负到正的方向将与表面正交。
梯度公式:
∇f=(∂f∂x,∂f∂y,∂f∂z)\nabla f = \left( \frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}, \frac{\partial f}{\partial z} \right)∇f=(∂x∂f​,∂y∂f​,∂z∂f​)

但是没有必要使用微积分。 我们不是采用函数的实数导数,而是通过对表面上的点周围的采样点进行近似,就像在学习如何做之前学习如何计算函数中的斜率作为过度一样。

vec3 estimateNormal(vec3 p) {return normalize(vec3(sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)),sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)),sceneSDF(vec3(p.x, p.y, p.z  + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON))));
}

有了这些知识,我们可以计算表面上任何一点的法线,在Phong反射模型中使用两个光源,我们得到这个结果:

完整代码如下:

// 这一部分略去, 拷贝上面part1的代码即可/*** 对于那些SDF求出来在曲面上的点求标准化的法线向量*/
vec3 estimateNormal(vec3 p) {return normalize(vec3(sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)),sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)),sceneSDF(vec3(p.x, p.y, p.z  + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON))));
}/*** Lighting contribution of a single point light source via Phong illumination.* * The vec3 returned is the RGB color of the light's contribution.** k_a: 环境色* k_d: 漫反射颜色* k_s: 镜面颜色* alpha: 光泽系数* p: position of point being lit* eye: 相机的位置* lightPos: 光的位置* lightIntensity: 光的颜色/强度** See https://en.wikipedia.org/wiki/Phong_reflection_model#Description*/
vec3 phongContribForLight(vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye, vec3 lightPos, vec3 lightIntensity) {vec3 N = estimateNormal(p);vec3 L = normalize(lightPos - p);vec3 V = normalize(eye - p);vec3 R = normalize(reflect(-L, N));float dotLN = dot(L, N);float dotRV = dot(R, V);if (dotLN < 0.0) {// Light not visible from this point on the surfacereturn vec3(0.0, 0.0, 0.0);} if (dotRV < 0.0) {// Light reflection in opposite direction as viewer, apply only diffuse// componentreturn lightIntensity * (k_d * dotLN);}return lightIntensity * (k_d * dotLN + k_s * pow(dotRV, alpha));
}/*** Lighting via Phong illumination.* * The vec3 returned is the RGB color of that point after lighting is applied.* k_a: 环境色* k_d: 漫反射颜色* k_s: 镜面颜色* alpha: 光泽系数* p: position of point being lit* eye: 相机的位置** See https://en.wikipedia.org/wiki/Phong_reflection_model#Description*/
vec3 phongIllumination(vec3 k_a, vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye) {const vec3 ambientLight = 0.5 * vec3(1.0, 1.0, 1.0);vec3 color = ambientLight * k_a;vec3 light1Pos = vec3(4.0 * sin(iTime),2.0, 4.0 * cos(iTime));vec3 light1Intensity = vec3(0.4, 0.4, 0.4);color += phongContribForLight(k_d, k_s, alpha, p, eye, light1Pos, light1Intensity);vec3 light2Pos = vec3(2.0 * sin(0.37 * iTime),2.0 * cos(0.37 * iTime),2.0);vec3 light2Intensity = vec3(0.4, 0.4, 0.4);color += phongContribForLight(k_d, k_s, alpha, p, eye,light2Pos,light2Intensity);    return color;
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{vec3 dir = rayDirection(45.0, iResolution.xy, fragCoord);vec3 eye = vec3(0.0, 0.0, 5.0);float dist = shortestDistanceToSurface(eye, dir, MIN_DIST, MAX_DIST);if (dist > MAX_DIST - EPSILON) {// Didn't hit anythingfragColor = vec4(0.0, 0.0, 0.0, 0.0);return;}// The closest point on the surface to the eyepoint along the view rayvec3 p = eye + dist * dir;vec3 K_a = vec3(0.2, 0.2, 0.2);vec3 K_d = vec3(0.7, 0.2, 0.2);vec3 K_s = vec3(1.0, 1.0, 1.0);float shininess = 10.0;vec3 color = phongIllumination(K_a, K_d, K_s, shininess, p, eye);fragColor = vec4(color, 1.0);
}

相机变换

我不会花太多时间,因为这种解决方案并不是Ray marching行进所独有的。 正如在光线跟踪(ray tracing)中一样,要在相机上进行变换,您可以通过变换矩阵来改变视线以定位和旋转相机。

但是,根据一系列的平移和旋转来确定如何定位相机不是那么直观,不是那么实用。 一种更好的描述方法是“我希望相机在这一点上,看相另一点。这正是gluLookAt在OpenGL中的用途。

在着色器内部,我们无法使用该功能,但是我们可以通过gluLookAt使用页的描述,看看它如何计算自己的转换矩阵,然后在GLSL中创建自己的矩阵。

mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) {vec3 f = normalize(center - eye);vec3 s = normalize(cross(f, up));vec3 u = cross(s, f);return mat4(vec4(s, 0.0),vec4(u, 0.0),vec4(-f, 0.0),vec4(0.0, 0.0, 0.0, 1));
}

由于球的各个角度看起来都一样,因此我在这里把它换成了一个立方体。 将相机放置在(8,5,7)处,并使用新的viewMatrix函数将其指向原点,现在我们有了:

代码在这里

继续阅读下一篇

ShaderToy入门教程(2) - 光照和相机相关推荐

  1. ShaderToy入门教程(1) - SDF 和 Raymarching 算法

    许多演示场景中使用的技术之一称为 光线追踪(Ray Marching) .该算法与一种称为 有符号距离函数 的特殊函数结合使用,可以实时创建一些非常酷的东西.这是系列教程,陆续推出,这篇涵盖以下黑体所 ...

  2. shadertoy入门教程

    shadertoy for beginners shadertoy入门 介绍 画一个圆 首先看一下uv坐标关于屏幕位置的变化规律 画一个椭圆 画一个圆 画多个圆 画一个笑脸:) shadertoy入门 ...

  3. ROS2与turtlebot4仿真入门教程-turtlebot4多点导航

    目录: ROS2与turtlebot4仿真入门教程-目录 ROS2与turtlebot4仿真入门教程-安装ROS2 ROS2与turtlebot4仿真入门教程-安装turtlebot4 ROS2与tu ...

  4. zed相机拆机_TX2入门教程硬件篇-外接双目相机ZED

    TX2入门教程硬件篇-外接双目相机ZED 说明:介绍如何在TX2安装ZED双目相机 步骤:准备:接上显示屏,键盘和鼠标 刷机:TX2通过jetpack3.0需要采用full模式完成刷机 确保有CUDA ...

  5. zed相机拆机_TX1入门教程硬件篇-外接双目相机ZED

    TX2入门教程硬件篇-外接双目相机ZED 说明:介绍如何在TX2安装ZED双目相机 步骤:准备:接上显示屏,键盘和鼠标 刷机:通过jetpack3.0需要采用full模式完成刷机 确保有CUDA8.0 ...

  6. Android WebRTC 入门教程(一) -- 使用相机

    前言,最近在搞网页投屏,发现 WebRTC 的Android 版本较少,这里的话,参考了一些优秀的博客,主要是这个大佬的 https://www.jianshu.com/p/eb5fd116e6c8 ...

  7. 奥比中光深度摄像头_ros与深度相机入门教程-在ROS使用奥比中光Orbbec Astra Pro

    ros与深度相机入门教程-在ROS使用奥比中光Orbbec Astra Pro 说明: 介绍如何在ros安装和使用奥比中光Orbbec Astra Pro OrbbecAstra介绍 astra_ca ...

  8. oak深度相机入门教程-Mask R-CNN 算法

      系列文章目录: oak深度相机入门教程-识别眼睛的凝视方向 oak深度相机入门教程-检测是否佩戴口罩 oak深度相机入门教程-文本检测+光学字符识别(OCR)管道 oak深度相机入门教程-识别人的 ...

  9. oak深度相机入门教程-识别车道线

      系列文章目录: oak深度相机入门教程-识别眼睛的凝视方向 oak深度相机入门教程-检测是否佩戴口罩 oak深度相机入门教程-文本检测+光学字符识别(OCR)管道 oak深度相机入门教程-识别人的 ...

最新文章

  1. cass3d基础版_v1.1_仪表不凡说表:N厂“一劳永逸”V11版实至名归!
  2. python条件表达式:多项分支,双向分支
  3. android自定义抽奖,Android自定义view制作抽奖转盘
  4. oracle z中rowid,oracle 10g中的ROWID
  5. 网上一个仿TP挂钩内核的源码
  6. js最简单数组去重_js简单数组去重
  7. 如何搭建html运行环境,搭建真实的运行环境2019.4.22
  8. php order by where,无合适where条件过滤时尽量选择order by后的字段以驱动表进行查询...
  9. 滴滴人脸识别申诉照片怎么拍_涅槃乐队Nevermind封面照片是怎么拍出来的?
  10. command模式 java_命令模式(Command)_java实现
  11. SVN学习总结(4)——解决Win10 SVN图标不显示问题
  12. python制作的游戏如何转化为swf_PYTHON实现swf提取
  13. poj 3450 Corporate Identity 枚举+kmp,话说这家伙给我一顿超时啊!!!!
  14. win7 ASP.NET 2.0 部署
  15. 第一部分 第五章 数组 1102-1149
  16. Azure School女神相邀,把每分钟都过的更充实
  17. 每日英语Daily English
  18. 微信提现(商户向商家转账)
  19. 运指如飞 拼音输入法三剑客功能横测!
  20. 这些自媒体平台可以帮你实现大目标

热门文章

  1. 中软面试:飞机加油飞地球一圈的问题
  2. JS导出html的table表格
  3. python机器学习——主成分分析理论简介
  4. 计算机磁盘管理看不到盘符,新装的固态硬盘系统里看不见?解决方法来了
  5. 计算机二级题库access选择题_[转]计算机二级Access试题及答案_74
  6. 学习尚硅谷Nginx整理的笔记
  7. 必须收藏!企业邮箱申请的详细流程
  8. Bigo的Java面试,我挂在了第三轮技术面上.........
  9. 自定义View -- 蜘蛛网图
  10. houdini 蜘蛛网