GameDesign 板


LINE

[2022/06/19] 为了让观念更清楚,我大改程式,所以更新文章 这次我也有自己做 shader 当教材唷,影片在这。 https://youtu.be/Je88e5KKYJU (没有鱼眼)
https://youtu.be/_RTsKbjj0iw (有鱼眼)
本篇也是讲 ray marching,主要是讲些实作上的小技巧。 如果你打算做的 3D 游戏有户外或是看的到天空的场景, 那这篇就挺重要的,请务必看一下。 [准备] 完整的程式在这: https://www.shadertoy.com/view/sdVcDG 请务必先搞懂前一篇 (六) 的程式, 如果前一篇有模糊不清的地方,这篇只会更搞不懂的。 [天空的构造] 这次的世界有二部分, 一个是天空 (sky),一个是河流 (river), 二部分的程式几乎是一样的。 为了当教材,我刻意写二份, 让他们各自独立且可以分拆来显示。 先用 sky 当说明。 前一篇 (六) 的范例,我们有个 world(pos), 它会回传 pos 这个点的密度。 这次的范例除了密度,还会回传一个 distance 的值, 那个值是 pos 离天空最近的距离值, 主要的用途是加快 ray marching 的速度。 因为天空是水平平面, 所以最近距离就是 pos 和天空的垂直距离。 再者,最近距离 > 0 时,通常密度就是 0, 要到天空里面才会有天空密度,这是当然的。 void sky( pos, out distance, out density ) 在抽象上,我把天空当成一个高度是 1.0 的无限大的水平平面。 float sky( pos, out distance, out density ) { // pos 和 sky 的最短距离 distance = 1. - pos.y + fbm(pos*4.-iTime*0.2) * 0.3; // pos 的密度 density = step(distance, 0.05) * (0.05 - distance); } 分行说明 一、distance = 1. - pos.y + fbm(pos*4.-iTime*0.2) * 0.3; (1.0 - pos.y) 的意思可以用简单的示意图来说明: 高度 distance density +3 -2.0 2.05 +2 -1.0 1.05 +1 ------- sky ----- +0.07 0.03 0.02 +0.05 0.05 0 +0 1.0 0 -1 2.0 0 -2 3.0 0 天空以上是负值距离,天空以下是正值距离。 但如果只有 (1.0 - pos.y), 我们只会画出一个完美的如镜面般的天空, 而不是画面看到的凹凸云朵,所以我们加了 fbm 在後面。 二、density = step(distance, 0.05) * (0.05 - distance); 这行其实等於 if ( distance < 0.05 ) density = 0.05 - distance; 也就是如果高度比天空低超过 0.05 的所有点,密度都是 0。 只有比天空下 0.05 高的点才有密度。 顺便讲一下为什麽不用 if-statement。 显示卡 (GPU) 的设计上, 对 if-statement 很不擅长,会拖累效能。 但也不是所有的 if-statement 都有效能问题, 这跟硬体有关,下面的文章有相关讨论: https://bit.ly/3y2snou 不过习惯上能少用就少用,能不用就不用, 这次因为判断基准是常数(constant) 0.05, 所以好像用了也没关系... 吧? 前一篇的范例是世界固定不变, 我们移动观察者 (摄影机) 来造成画面的变化。 这一篇则是相反,是摄影机不动, 我们让世界变形来造成画面的变化。 [ray marching] ray marching 的基本逻辑和前一篇差不多。 有一个起始点 pos,pos 会朝 rd 方向前进 20 次, 每次都会取得新点的密度,全部加起来後会回传总密度。 但细部有些小技巧,逐行说明如下: 一、if ( density_sum > 0.95 ) break; 总密度太大就不用再前进了,这点很正常, 不过为什麽不是 1.0 而是 0.95 呢? 因为我们希望就算是光线经过的密度累积到了极限, 每个 pixel 也会有色差的不同 (0.95 ~ 1.0), 而不是通通都是白白的 1.0。 二、sky(pos, distance, density ) 只是取的 pos 与天空的距离和密度, 密度只有 pos 在天空里面时才有。 三、density_sum += (1. - density_sum)*density; 这行跟前一篇 (六) 的范例不同, 我们不像前一篇那麽直觉的先乘个 0.2 再加总, 而是照比例加在总密度还剩下的空间。 这样加可以确保总密度不会一下就超过 1, 而且画出来的效果好很多。 四、二行一起看 distance = max(distance, 0.01 ); pos = pos + rd*distance; 前一篇 (六) 光线明明一次只移动零点零几的, 为什麽这里可以移动目前的位置离天空的高度 (distance) 那麽远? 因为 distance = sky( pos ) 回传的是垂直高度, 也就是 pos 离天空的最短距离, 既然是最短, 我们 "几乎" 可以确定这距离不会碰到天空任何一个有密度的点。 至於为什麽是 "几乎"? 因为天空平面被 fbm 恶搞过。 五、density_sum = pow( density_sum, 0.6 ); 这是 gamma correction, 玩摄影的应该都知道,只是调亮度。 为什麽调亮度不直接写 density_sum += 0.3 ? 因为这样会让比 0.7 大的点通通变成爆炸亮, 把细节就通通看不见了, 所以 gamma correction 比较好。 [河流的构造] void river( pos, out distance, out density ) 河流跟天空的构造完全一样, 唯一的差别是这行: density = step(distance, 0.05) * (0.05 - distance) * step(0.0, distance); 也就等於: if ( distance < 0.05 && distance > 0. ) density = 0.05 - distance; 意思是河流我只取河流水平面以上、高度 0.05 之内的点的密度。 因为很薄,所以可以透过河面看到河底。 当然这次的 shader 没画河底出来, 不过透光度的不同就是天空和水的差别。 [结语] 因为这篇是教学文, 所以河流和天空的 fbm 是一样的。 但回想前二篇 (五),我们不是有用外框画水底吗? 如果用那个当 texture/noise 来构成平静河流平面, 应该也是很不错的吧? [好玩的东西] 把河流拿掉,void sky() 改成下面的球, 画面上就会跑出一个球, 然後你可以加点 noise 进去喔,很好玩的。 void ball( vec3 pos, out float distance, out float density ) { vec3 center = vec3( 0., 0., 1. ); float radius = 0.5; distance = length(pos-center) - radius; density = (1. - step(0., distance))*(1.-length(pos-center)/radius); } --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 61.228.80.32 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/GameDesign/M.1655569365.A.8E7.html
1F:推 dklassic: 推推 06/19 14:08
※ 编辑: meowyih (61.228.80.32 台湾), 06/19/2022 19:13:57 ※ 编辑: meowyih (61.228.80.32 台湾), 06/19/2022 21:33:35
2F:→ iLeyaSin365: 加油 06/19 21:35
3F:推 a82611141: 推 06/21 08:34







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Tech_Job站内搜寻

TOP