IQ大神博客閱讀隨筆1

IQ大神博客閱讀心得1

the game of life:一個簡單有趣的算法

Plane deformations:較為古老,但效果不錯,基于UV坐標(biāo)重定位的特效技術(shù)

CellEffect:有機(jī)會深入研究

Simple color palettes:簡單的調(diào)色板技術(shù),用于物質(zhì)的色變(草、木,石頭等)

clever normalization of a mesh:網(wǎng)格中點(diǎn)的法向量的獲取與優(yōu)化分析

improved texture interpolation:主要介紹了SM的原理和應(yīng)用背景。實(shí)用的小技巧

Catmull-Rom splines:簡單的樣條,應(yīng)用于曲線擬合

Ray and Polygons:基本內(nèi)容,主要介紹引擎中的深度含義和計(jì)算(圖形學(xué)基礎(chǔ))

Avoiding rigonometry:以旋轉(zhuǎn)為例介紹用點(diǎn),叉乘代替三角函數(shù)的基本思路

fixing frustum culling:對于大物體進(jìn)行視椎體剔除的小技巧

1. simple effects

the game of life

網(wǎng)格中的每個像元可以是無效的(0)或有效的(1)?,F(xiàn)在,我們將執(zhí)行一次迭代(生成),每個單元的狀態(tài)將根據(jù)其當(dāng)前狀態(tài)和其周圍單元的狀態(tài)而變化。有一些簡單的規(guī)則可以驅(qū)動該過程:如果一個單元還活著,而八個周圍的單元中有兩個或三個還活著,則保持活動,否則死亡。如果該單元已經(jīng)死亡,但八個相鄰單元中有三個處于活動狀態(tài),則該單元將恢復(fù)活動。網(wǎng)格中的所有單元都更新后,我們便有了新一代,可以重新開始了。這個過程永遠(yuǎn)重復(fù),因此零和一的模式會演變,成型結(jié)構(gòu)等。當(dāng)然,您需要兩個緩沖區(qū),一個緩沖區(qū)擁有當(dāng)前代的單元格,另一個緩沖區(qū)將要計(jì)算新的單元格

Plane deformations

最好的老式效果之一是二維LUT變形和隧道。這些都是非??焖俚膶?shí)時計(jì)算,也非常出色,因此在當(dāng)時非常普遍。這個想法是取一個紋理,將笛卡爾坐標(biāo)轉(zhuǎn)換為極坐標(biāo),再依靠數(shù)學(xué)公式修改極坐標(biāo),并隨著時間的推移以幾種方式變形,以創(chuàng)建各種形狀,例如花朵,假的3D風(fēng)景,隧道,水坑,洞等。我也經(jīng)常使用它們,在1999年和2003年, 2000年,在《RareStorm》等幾個演示中。

以下是一些簡單的UV變化函數(shù):

[測試]?https://jmx-paper.oss-cn-beijing.aliyuncs.com/IQ%E5%A4%A7%E7%A5%9E%E5%8D%9A%E5%AE%A2%E9%98%85%E8%AF%BB/%E4%BB%A3%E7%A0%81/SimpleEffects/PlaneDeformations.shader?

CellEffect

蜂窩模式,或更確切地說是Voronoi圖,經(jīng)常出現(xiàn)在計(jì)算機(jī)圖形學(xué)和機(jī)器人技術(shù)中。給定一組特征(點(diǎn),線,圓,對象等),此圖表示給定距離度量(例如規(guī)則的歐幾里得距離)到最近的特征的距離。當(dāng)用顏色表示距離時,將獲得通常的細(xì)胞紋理,這對于生成過程紋理(用于巖石,瓷磚,樹木,皮膚等)非常有用。

2 Coding Tricks

Simple color palettes

在進(jìn)行過程圖形處理時,最好將顏色變化添加到圖像元素中。從草葉到草叢,再到巖石,樹木或山丘,所有尺度的細(xì)節(jié)都受益于某些顏色變化。為了實(shí)現(xiàn)這一目標(biāo),當(dāng)然可以采用不同的方法,但是在最便宜和最易于編碼的方法中,有一些是基于簡單(硬)編碼公式的方法。通常,這些顏色變化將是微妙而重要的,并且可以通過使用可更改元素(草,巖石或其他元素)基色的調(diào)色板來實(shí)現(xiàn)。簡單的加法或調(diào)制(乘法)就足夠了-通常,無需先將顏色轉(zhuǎn)換為HSV并在轉(zhuǎn)換回RGB之前在該空間中進(jìn)行色相或飽和度處理。創(chuàng)建程序調(diào)色板也很有趣,可以對灰度級且沒有自然著色的信號進(jìn)行著色,例如密度圖或分形。本文介紹了一種可能的方法,可以以一種便宜的方式(如前所述)用一個簡單的公式來計(jì)算用于調(diào)制或可視化的調(diào)色板。

vec3pal(infloatt,invec3a,invec3b,invec3c,invec3d)

{

returna+b*cos(6.28318*(c*t+d) );

}

?

voidmainImage(outvec4fragColor,invec2fragCoord)

{

? ? vec2p=fragCoord.xy/iResolution.xy;


// animate

p.x+=0.01*iTime;


// compute colors

vec3col=pal(p.x,vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.33,0.67) );

if(p.y>(1.0/7.0) )col=pal(p.x,vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.10,0.20) );

if(p.y>(2.0/7.0) )col=pal(p.x,vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.3,0.20,0.20) );

if(p.y>(3.0/7.0) )col=pal(p.x,vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,0.5),vec3(0.8,0.90,0.30) );

if(p.y>(4.0/7.0) )col=pal(p.x,vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,0.7,0.4),vec3(0.0,0.15,0.20) );

if(p.y>(5.0/7.0) )col=pal(p.x,vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(2.0,1.0,0.0),vec3(0.5,0.20,0.25) );

if(p.y>(6.0/7.0) )col=pal(p.x,vec3(0.8,0.5,0.4),vec3(0.2,0.4,0.2),vec3(2.0,1.0,1.0),vec3(0.0,0.25,0.25) );


?

// band

floatf=fract(p.y*7.0);

// borders

col*=smoothstep(0.49,0.47,abs(f-0.5) );

// shadowing

col*=0.5+0.5*sqrt(4.0*f*(1.0-f));

// dithering

//col += (1.0/255.0)*texture( iChannel0, fragCoord.xy/iChannelResolution[0].xy ).xyz;

?

? ? ragColor=vec4(col,1.0);

}

clever normalization of a mesh

一般來說,計(jì)算點(diǎn)法線的方法是:對于網(wǎng)格中的一個點(diǎn),獲取由它組成的所有的面的面法向量(這個容易,一個三角形面片abc的法向量n:a × b),累積法線,然后除以累積中使用的面數(shù)。但實(shí)際上,思考一下,法線的長度并不重要,而法線累加之后,方向已經(jīng)確定,因此最后的除法可以舍去。需要均一化嗎?回到叉乘,兩條邊叉乘的法線的長度為?,而這個長度很明顯是正比于三角形面片的面積,那么,按照一般的經(jīng)驗(yàn),面積越大的三角形面片的法向量對于點(diǎn)法向量的貢獻(xiàn)是不是更大呢?因此,我們只需要在最后對結(jié)果進(jìn)行均一化,而單獨(dú)的每次面法向量計(jì)算,則無需。

voidMesh_normalize(Mesh*myself)

{

Vert*vert=myself->vert;

Triangle*face=myself->face;

?

for(inti=0;i<myself->mNumVerts;i++)vert[i].normal=vec3(0.0f);

?

for(inti=0;i<myself->mNumFaces;i++)

?? {

constintia=face[i].v[0];

constintib=face[i].v[1];

constintic=face[i].v[2];

?

constvec3e1=vert[ia].pos-vert[ib].pos;

constvec3e2=vert[ic].pos-vert[ib].pos;

constvec3no=cross(e1,e2);

?

vert[ia].normal+=no;

vert[ib].normal+=no;

vert[ic].normal+=no;

?? }

?

for(i=0;i<myself->mNumVerts;i++)verts[i].normal=normalize(verts[i].normal);

}

?

improved texture interpolation

當(dāng)前的圖形卡功能非常強(qiáng)大,但這僅是因?yàn)樗鼈兛梢酝瓿伞昂唵巍钡氖虑?。換句話說,GPU僅對那些可以使游戲看起來很棒的事物具有快速實(shí)現(xiàn)。當(dāng)然不用抱怨。但是,當(dāng)需要其他某些東西,而又有些其他東西超出了游戲的通常要求時,事情就不會那么順利了。例如,紋理過濾是在游戲中看起來不錯的東西之一,但實(shí)際上,當(dāng)前實(shí)現(xiàn)的質(zhì)量對于其他目的而言是很差的。本文介紹如何改進(jìn)在硬件中實(shí)現(xiàn)的線性濾波。

線性插值比對紋理采樣的更簡單的最近舍入方法要好得多。但是,線性插值只是一階多項(xiàng)式插值,因此重新采樣紋理的斜率/導(dǎo)數(shù)是分段常數(shù)。這意味著當(dāng)使用線性插值的高度圖紋理生成某些法線/凹凸貼圖或浮雕濾鏡時,會出現(xiàn)不連續(xù)性(因?yàn)榉ň€/凹凸貼圖或浮雕濾鏡是微分算子。通常應(yīng)該使用三次三次插值(或什至更高階的插值器)來獲得平滑的結(jié)果。但這需要額外的硬件,更重要的是,還需要更多的帶寬,因?yàn)槊看蜗窬€性插值一樣,不僅必須訪問四個紋理像素,而且必須訪問十六個。如今,GPU幾乎受到內(nèi)存訪問時間的限制,因此,將一個紋理提取所需的帶寬乘以4聽起來并不是一個好主意(您可以在Wikipedia文章中了解三次插值)。因此,我們要做的就是使用GPU提供的雙線性過濾:

vec4 getTexel(vec2 p){return texture2D(myTex,p); }

但是有一個技巧是著色器編寫人員非常熟悉的,那就是在執(zhí)行線性插值時使用smoothstep()作為中間步驟。SmoothStep通常用于在輸入mix()或lerp()之前 fade the interpolation parameter。因?yàn)檫@是一條平滑的變化曲線,它消除了線性插值的尖銳邊緣。實(shí)際上,平滑函數(shù)的導(dǎo)數(shù)在插值邊界處是固定的(在本例中為零)

x = 0x = 1的值均為0 ,這是通常插值范圍(0..1)的極值。因此,如果我們有辦法修改硬件的插值因子,那么我們能在紋理插值中應(yīng)用smoothstep()技術(shù),而插值因子當(dāng)然是在硬件的紋理單元中進(jìn)行深層計(jì)算的。我們當(dāng)然不能訪問硬件的這一部分(至少不是現(xiàn)在),但是我們可以人為地修改傳遞給texture2D()的紋理坐標(biāo)以獲得相同的效果。

當(dāng)硬件通過texture2D()函數(shù)接收紋理坐標(biāo)p時,它首先計(jì)算采樣點(diǎn)所在的紋理像素。那通常是介于兩者之間像素,這就是插值進(jìn)入游戲的地方。四個最接近的紋理元件是基于整數(shù)部分選擇,并在鄰近于每個紋理像素的基礎(chǔ)的,所述四種顏色混合以得到最終的顏色。直接從采樣位置的小數(shù)部分*f**p = i + f*),這就是線性關(guān)系代表的直接關(guān)系,這就是我們要欺騙的東西。我們希望隨著采樣點(diǎn)的增加,四個紋理像素的影響逐漸消失,但不是呈線性方式。因此,我們必須使用漸變曲線對小數(shù)部分進(jìn)行預(yù)失真,這就是平滑步長可以提供幫助的地方。當(dāng)然可以使用除平滑步長以外的其他曲線。我更喜歡使用五次度曲線,該曲線不僅在插值極值上具有零導(dǎo)數(shù),而且在該位置具有二階導(dǎo)數(shù)。這樣可以確保照明(取決于法線)始終保持平滑。

vec4getTexel(vec2p)

{

p=p*myTexResolution+0.5;

?

vec2i=floor(p);

vec2f=p-i;

f=f*f*f*(f*(f*6.0-15.0)+10.0);

p=i+f;

?

p=(p-0.5)/myTexResolution;

returntexture2D(myTex,p);

}

?

Catmull-Rom splines

本樣條不提供切線控制,但足夠簡單和實(shí)用,能夠插值3維,甚至n維點(diǎn),IQ大神提到他用這個對照相機(jī)進(jìn)行控制

建立一個三次多項(xiàng)式:?

導(dǎo)數(shù):?

確保t=0時,曲線通過第一個點(diǎn)p1

確保t=0時,這個曲線有且切線?

確保t=1時,曲線通過第二個點(diǎn)p2

確保t=1時,曲線有切線為?

求解參數(shù)如下

Ray and Polygons

基本內(nèi)容。假設(shè)您正在對片段著色器中的某些對象進(jìn)行光線進(jìn)給或光線追蹤,并且想要將它們與您已渲染或?qū)⑼ㄟ^常規(guī)柵格化渲染的其他某些幾何圖形進(jìn)行合成。唯一需要做的就是在光線跟蹤/行進(jìn)著色器中輸出一個深度值,然后讓深度緩沖區(qū)完成其余的工作。在raytracer / marcher中,您可能可以訪問從射線原點(diǎn)(相機(jī)位置)到最近的幾何圖形/相交點(diǎn)的距離。那個距離不是您要寫入深度緩沖區(qū)的內(nèi)容,因?yàn)橛布鈻呕绦颍∣penGL或DirectX)不存儲到相機(jī)的距離,而是存儲幾何相交點(diǎn)的z(下面的Z是點(diǎn)視覺空間的Z坐標(biāo))

floata=(far+near)/(far-near);

floatb=2.0*far*near/(far-near);

gl_FragDepth=a+b/z;

Avoiding Trigonometry

IQ在這里表達(dá)了自己不喜歡三角函數(shù)的一些原因,并就旋轉(zhuǎn)提出了一些看法

mat3x3rotationAxisAngle(constvec3&v,floata)

{

constfloatsi=sinf(a);

constfloatco=cosf(a);

constfloatic=1.0f-co;

?

returnmat3x3(v.x*v.x*ic+co,v.y*v.x*ic-si*v.z,v.z*v.x*ic+si*v.y,

v.x*v.y*ic+si*v.z,v.y*v.y*ic+co,v.z*v.y*ic-si*v.x,

v.x*v.z*ic-si*v.y,v.y*v.z*ic+si*v.x,v.z*v.z*ic+co);

}

.....

constvec3axi=normalize(cross(z,d) );

constfloatang=acosf(clamp(dot(z,d),-1.0f,1.0f) );

constmat3x3rot=rotationAxisAngle(axi,ang);

對于上述常規(guī)的計(jì)算,明顯存在多余步驟:反cos函數(shù)求出角度,后面又使用cos,但可能會有質(zhì)疑:不求出角度,怎么計(jì)算sin值?但仔細(xì)想想,對于Sin值可以有:?,因此,我們求旋轉(zhuǎn)等方法可以直接:

mat3x3rotationAlign(constvec3&d,constvec3&z)

{

constvec3v=cross(z,d);

constfloatc=dot(z,d);

//k=(1-cos)/sin

//const float k = (1.0f-c)/(1.0f-c*c);

constfloatk=1/(1.0f+c);

?

returnmat3x3(v.x*v.x*k+c,v.y*v.x*k-v.z,v.z*v.x*k+v.y,

v.x*v.y*k+v.z,v.y*v.y*k+c,v.z*v.y*k-v.x,

v.x*v.z*K-v.y,v.y*v.z*k+v.x,v.z*v.z*k+c);

}

?

fixing frustum culling

一般的視椎體剔除,是將物體的點(diǎn)和視椎體的六個面進(jìn)行比較判斷,這對于小物體的剔除是合適的,但據(jù)IQ舉例,大物體在某些情況下會導(dǎo)致剔除錯誤(為什么也沒怎么看懂),因此需要額外增加一個簡單的點(diǎn)范圍測試。

用md做的,所以直接復(fù)制過來一點(diǎn)都不好看,附上鏈接https://jmx-paper.oss-cn-beijing.aliyuncs.com/IQ%E5%A4%A7%E7%A5%9E%E5%8D%9A%E5%AE%A2%E9%98%85%E8%AF%BB/%E7%AC%94%E8%AE%B0/IQ%E5%A4%A7%E7%A5%9E%E5%8D%9A%E5%AE%A2%E9%98%85%E8%AF%BB%E5%BF%83%E5%BE%971.md

谷歌翻譯+略微修改譯文+菜鳥提取

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容