效果圖:
頂點數據
float vertices[]={
-0.6f, -0.8f, 0.0f, //首尾填充
-0.6f, -0.8f, 0.0f,
-0.4f, -0.3f, 0.0f,
-0.2f, -0.5f, 0.0f,
0.0f, 0.4f, 0.0f,
0.2f, 0.4f, 0.0f,
0.3f, 0.1f, 0.0f,
0.3f, 0.1f, 0.0f
};
關於幾何着色器:
其作用大致是:根據已有頂點數據,構建出新的頂點數據,甚至修改圖元。
關於Bezier曲線,可以看這篇文章:傳送門
這裏我們使用二階Bezier方程
因此我們需要三個點(起點、一個控制點、終點)才能繪製一段Bezier曲線,我們需要考慮兩個問題:
如何選取控制點?
這裏我的策略是,每三個連續點(p0,p1,p2),取兩條線(p0p1,p1p2)的中點作爲起點和終點,中間點(p1)作爲控制點,也就是下圖的效果:
這三個點從哪來?
由於我們的頂點數據本意是用來構建GL_LINE_STRIP的,但GL_LINE_STRIP圖元只會傳遞兩個頂點數據給幾何着色器,而我們繪製bezier曲線需要三個頂點。很顯然GL_LINE_STRIP已經無法滿足我們了,因此我們需要使用GL_TRIANGLE_STRIP。真奇怪,我們現在正使用三角形圖元來畫線。
還沒完,使用GL_TRIANGLE_STRIP有一個細節,假設有一系列頂點分別爲(0,1,2,3,4,5)。使用GL_TRIANGLE_STRIP第一個繪製的三角形頂點是(0,1,2), 重點來了,第二個三角形的頂點是(1,2,3)嗎?
既然我這麼問了,那肯定不是了,其實第二個三角形的頂點是(2,1,3),爲什麼會這樣?
這個順序是爲了保證所有的三角形都是按照相同的方向繪製的,使這個三角形串能夠正確形成表面的一部分。對於某些操作,維持方向是很重要的,比如剔除。
具體規律請看這篇文章:傳送門
爲了避免這一問題,我們需要讓幾何着色器能夠識別出頂點的處理順序。我們需要藉助頂點着色器輸出頂點的序號。
頂點着色器
#version 330 core
layout (location = 0) in vec3 pos;
out VS_OUT{
int id;
} vs_out;
void main()
{
gl_Position = vec4(pos,1.0f);
vs_out.id = gl_VertexID;
}
幾何着色器
#version 330 core
in VS_OUT {
int id;
}gs_in[];
layout (triangles) in; //以三角形爲單位進行擴張,每次從VertexShader往GeomShader傳進三個點進行數據處理
layout (line_strip, max_vertices = 32) out; //將一個點變爲最多32個可連成線條的點 交給FragShader
void creatBezier(){
const int max_len=20; //使用20條線來繪製一段bezier曲線
vec4 p0=mix(gl_in[0].gl_Position,gl_in[1].gl_Position,0.5); //取前兩個點的中點
vec4 p1;
vec4 p2;
if(gs_in[2].id%2==0){
p1=gl_in[1].gl_Position; //調整點
p2=mix(gl_in[1].gl_Position,gl_in[2].gl_Position,0.5); //取後兩個點的中點
}
else{
p1=gl_in[0].gl_Position; //同上
p2=mix(gl_in[0].gl_Position,gl_in[2].gl_Position,0.5);
}
for(int i=0;i<=max_len;i++){ //根據公式生成頂點,並提交
float t=i*0.05;
gl_Position=p0*(1.0-t)*(1.0-t)+p1*2*t*(1.0-t)+p2*t*t;
EmitVertex();
}
EndPrimitive();
}
void main(){
creatBezier();
}
端點bug
使用上方的方式無法繪製兩端的端點連線,比較好的解決方法是,把第一個點再添加到開始,末尾的點再添加到末尾
float vertices[]={
-0.6f, -0.8f, 0.0f,
-0.4f, -0.3f, 0.0f,
-0.2f, -0.5f, 0.0f,
0.0f, 0.4f, 0.0f,
0.2f, 0.4f, 0.0f,
0.3f, 0.1f, 0.0f,
};
float vertices[]={
-0.6f, -0.8f, 0.0f, //首尾填充
-0.6f, -0.8f, 0.0f,
-0.4f, -0.3f, 0.0f,
-0.2f, -0.5f, 0.0f,
0.0f, 0.4f, 0.0f,
0.2f, 0.4f, 0.0f,
0.3f, 0.1f, 0.0f,
0.3f, 0.1f, 0.0f
};