1. 畫圓
1.1. 圓的方程
圓的方程是:(x^2 + y^2 = r^2),其中(r)是圓的半徑。
我們可以使用 desmos 來驗證一下。
輸入 x^2 + y^2 -1=0,即可得到圓。
類似下圖
1.2. 畫圓的方式
- 畫圓:使用圓的方程,判斷每個像素點是否在圓內,在圓內則為白色,否則為黑色。
- 畫圓:使用圓的方程,判斷每個像素點到圓心的距離是否小于半徑,小于半徑則為白色,否則為黑色。
目前我們在畫圓時,先設定圓心在屏幕的中心(0,0)。
這樣的好處是 length(uv)
可以直接計算出像素點到圓心的距離。
1.3. 方式1 畫圓
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)//vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xy;vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;// vec2 uv = (2.0*fragCoord-iResolution.xy)/min(iResolution.x,iResolution.y);//取x和y的最小值作為比例float c=0.;//默認黑色float r=0.3;//圓的半徑if( length(uv) < r )//矢量長度小于半徑,就為白色c=1.;// Output to screenfragColor = vec4(vec3(c),1.0);
}
注意:
1.4. 方式2 畫圓
如果代碼是如下形式,那么圓會變成橢圓,因為x和y的比例不一樣
vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xy;
1.5. 方式3 畫圓
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;// vec2 uv = (2.0*fragCoord-iResolution.xy)/min(iResolution.x,iResolution.y);//取x和y的最小值作為比例float c=0.;//默認黑色float r=0.5;//圓的半徑c=1.-step(0.,length(uv)-r);// Output to screenfragColor = vec4(vec3(c),1.0);
}
注意:
- 在fragment shader中,盡量不要用if 語句,因為if語句會降低性能
1.6. 方式4 畫圓(平滑 smoothstep)
可以看到邊緣的30個像素是平滑過渡的
#define PIXW (1./iResolution.y)
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;float c=smoothstep(0.,0.+30.*PIXW,length(uv)-r);// Output to screenfragColor = vec4(vec3(c),1.0);
}
1.7. 極坐標系
極坐標系是一種二維坐標系統,它用以確定平面上點的位置。與常用的笛卡爾坐標系不同,極坐標系使用一個距離和一個角度來描述點的位置。
在極坐標系中,每個點的位置由兩個數值定義:
- 徑向坐標(r):也稱為極徑,是從原點(也稱為極點)到該點的直線距離。
- 角坐標(θ):也稱為極角或方位角,是指從固定的參考方向(通常是正x軸)到通過原點和該點的線段之間所夾的角度。角坐標通常以弧度或度為單位。
因此,在極坐標系中,一個點的位置表示為 (P(r, \theta))。
極坐標系特別適用于那些具有圓形對稱性的問題,例如物理學中的圓周運動、工程學中的旋轉機械設計、以及數學中的某些類型的方程和圖形等。轉換公式如下:
-
從極坐標到笛卡爾坐標的轉換:
- (x = r \cdot \cos(\theta))
- (y = r \cdot \sin(\theta))
-
從笛卡爾坐標到極坐標的轉換:
- (r = \sqrt{x^2 + y^2})
- (\theta = \arctan2(y, x)),這里(\arctan2)函數用于根據x和y的值正確地確定角度,即使在x或y為零的情況下也能返回正確的象限。
在計算機圖形學、圖像處理以及游戲開發等領域,理解如何在不同坐標系之間轉換是非常有用的,尤其是在需要實現基于角度和距離的計算時,如光線追蹤、物理模擬、用戶界面設計等。
運行效果
#define PIXW (1./iResolution.y)
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{vec2 uv=(fragCoord.xy-.5*iResolution.xy)*PIXW;vec4 O=vec4(smoothstep(0.+10.*PIXW,0.,length(uv)-0.5));uv=vec2(length(uv),atan(-uv.y,-uv.x));//polar systemfragColor=mix(vec4(0),O,uv.y/6.28+.5);}
1.8. 參考資料
- shadertoy入門手冊1-掌控畫布
2. 移動圓
2.1. 圓的方程
圓的方程是:((x-offsetX)^2 + (y-offsetY)^2 = r^2),其中(r)是圓的半徑。
我們可以使用 desmos 來驗證一下。
((x-1)^2 + (y-1)^2 -1=0)
類似下圖
2.2. 思路
- 將uv坐標轉換成圓心坐標
(x,y) = (uv.x-offsetX,uv.y-offsetY)
- 計算
(x,y)
到圓心的距離d
- 如果
d
小于半徑r
,則為白色,否則為黑色。
2.3. 將圓心移動到(0.3,0.3)
#define PIXW (1./iResolution.y)vec3 sdfCircle(vec2 uv, float r,vec2 offset)
{uv=uv-offset;float d=length(uv)-r;return d>0.?vec3(0.):vec3(1.);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/min(iResolution.x,iResolution.y);float r=0.3;vec3 c=sdfCircle(uv,r,vec2(0.3,0.3));// Output to screenfragColor = vec4(vec3(c),1.0);
}
2.4. 讓圓動起來
思路:
- 讓圓的圓心坐標隨著時間變化
- 讓圓的顏色隨著時間變化
#define PIXW (1./iResolution.y)vec3 sdfCircle(vec2 uv, float r,vec2 offset)
{uv=uv-offset;float d=length(uv)-r;return d>0.?vec3(0.):vec3(abs(sin(iTime*0.3)),abs(cos(iTime*0.3)),abs(sin(iTime*0.3)));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/min(iResolution.x,iResolution.y);float r=0.3;vec3 c=sdfCircle(uv,r,vec2(0.+sin(iTime)*0.2,0.+cos(iTime)*0.2));// Output to screenfragColor = vec4(vec3(c),1.0);
}
2.5. 畫兩個圓
思路:
- 背景為黑色,即vec(0.,0.,0.)
- 圓為非黑色
- 兩個圓的顏色相加,由于這兩個圓沒有重疊,所以顏色相加后,剛好會顯示出兩個圓
注: 這種方法,只適用于兩個圓沒有重疊且背景色為黑色這種簡單情況。后續會說明更通用的方法。
//顯示兩個圓
#define PIXW (1./iResolution.y)vec3 sdfCircle(vec2 uv, float r,vec2 offset)
{uv=uv-offset;float d=length(uv)-r;return d>0.?vec3(0.):vec3(abs(sin(iTime*0.3)),abs(cos(iTime*0.3)),abs(sin(iTime*0.3)));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/min(iResolution.x,iResolution.y);float r=0.3;vec3 c=sdfCircle(uv,r,vec2(0.5,0.5));c=c+sdfCircle(uv,r,vec2(-0.5,0.5));//c=max(c,sdfCircle(uv,r,vec2(-0.5,0.5)));// Output to screenfragColor = vec4(vec3(c),1.0);
}