平滑著色
實現(xiàn)矩形中間亮,邊緣暗淡的效果艘蹋,使用三角形扇繪制矩形锄贼,并給頂點(diǎn)添加顏色信息
三角形扇
如下圖所示,如果用四個三角形組成矩形女阀,有很多頂點(diǎn)是可以共用的宅荤,三角形扇就是一種共用頂點(diǎn)的方式
一個三角形扇以一個中心頂點(diǎn)作為起始,使用相鄰的兩個頂點(diǎn)創(chuàng)建第一個三角形浸策,接下來的每個頂點(diǎn)都會創(chuàng)建一個三角形冯键,圍繞起始的中心點(diǎn)按扇形展開。為了使這個扇形閉合庸汗,我們只需要在最后重復(fù)第二個點(diǎn)
添加顏色屬性
給頂點(diǎn)數(shù)組增加顏色屬性
// 頂點(diǎn)數(shù)據(jù)
float[] vertex = new float[]{
// 位置(x,y)+顏色(r,g,b)信息
0f, 0f, 0.9f, 0.9f, 0.9f,
-0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
-0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
-0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
-0.8f, 0f, 1f, 0f, 0f,
0.8f, 0f, 1f, 0f, 0f,
0f, -0.5f, 0f, 1f, 0f,
0f, 0.5f, 0f, 0f, 1f
};
OpenGL中的一種顏色有4個分量(紅色惫确、綠色、藍(lán)色和阿爾法)蚯舱,但不必指定所有分量的值改化,不像uniform 必須傳入4個分量,OpenGL 會用默認(rèn)值替換 attribute 中未指定值的分量:前三個分量會被設(shè)為0枉昏,而最后一個分量會被設(shè)為1
我這里的顏色分量是隨意寫的陈肛,可以使用下面的方法獲取顏色分量
int parsedColor = Color.parseColor("#874326");
float red = Color.red(parsedColor) / 255f;
float green = Color.green(parsedColor) / 255f;
float blue = Color.blue(parsedColor) / 255f;
給著色器增加顏色屬性
頂點(diǎn)著色器
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main(){
v_Color=a_Color;
gl_Position=a_Position;
gl_PointSize=10.0;
}
加入了一個新的 attribute 類型的 a_Color,也加入了一個 varying 類型的 v_Color
varying 是一個特殊的變量類型兄裂,它會把給它的那些值進(jìn)行混合句旱,并把這些混合后的值發(fā)送給片段著色器
例如:兩個頂點(diǎn) A 和 B 構(gòu)成一條直線,并為這條直線生成片段懦窘,如果頂點(diǎn) A 的 a_Color 是紅色前翎,且頂點(diǎn) B 的 a_Color 是綠色,通過把 a_Color 賦值給 v_Color畅涂,來告訴 OpenGL 我們需要每個片段都接收一個混合后的顏色港华,接近頂點(diǎn)0的片段,混合后的顏色顯得更紅午衰,而越接近頂點(diǎn)1的片段立宜,顏色就會越綠。
片段著色器
precision mediump float;
varying vec4 v_Color;
void main(){
gl_FragColor=v_Color;
}
用 varying 類型的變量 v_Color 替換了原來代碼中的 uniform 類型的 u_Color臊岸,如果那個片段屬于一條直線橙数,那么 OpenGL 就會用構(gòu)成那條直線的兩個頂點(diǎn)計算其混合后的顏色,如果那個片段屬于一個三角形帅戒,那 OpenGL 就會用構(gòu)成那個三角形的三個頂點(diǎn)計算其混合后的顏色灯帮,然后傳給 v_Color 崖技,而 v_Color 的值又會被賦值給最終的顏色值 gl_FragColor 作為當(dāng)前片段的最終顏色
使用新的顏色屬性渲染
已經(jīng)給數(shù)據(jù)增加了一個顏色屬性,并且更新了頂點(diǎn)和片段著色器钟哥,讓它們使用這個屬性迎献,因此要去掉使用 unifom 傳遞顏色的舊代碼,并告訴 OpenGL 把顏色作為一個頂點(diǎn)屬性讀入
public class MyRenderer implements GLSurfaceView.Renderer {
private final FloatBuffer mVertexBuffer;
private Context mContext;
private int a_color;
private int a_position;
public MyRenderer(Context context) {
mContext = context;
// 頂點(diǎn)數(shù)據(jù)
float[] vertex = new float[]{
// 位置(x,y)+顏色(r,g,b)信息
0f, 0f, 0.9f, 0.9f, 0.9f,
-0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
-0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
-0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
-0.8f, 0f, 1f, 0f, 0f,
0.8f, 0f, 1f, 0f, 0f,
0f, -0.5f, 0f, 1f, 0f,
0f, 0.5f, 0f, 0f, 1f
};
mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertex);
mVertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
glClearColor(1f, 1f, 1f, 1f);
int vertexShader = ShaderHelper.compileVertexShader(mContext, R.raw.gradient2_vertex);
int fragmentShader = ShaderHelper.compileFragmentShader(mContext, R.raw.gradient2_fragment);
int program = ProgramHelper.getProgram(vertexShader, fragmentShader);
glUseProgram(program);
a_color = glGetAttribLocation(program, "a_Color");
a_position = glGetAttribLocation(program, "a_Position");
// 調(diào)節(jié)緩沖區(qū)的指針腻贰,從第一個數(shù)據(jù)讀
mVertexBuffer.position(0);
// STRIDE 傳入一個頂點(diǎn)的所有屬性占用的 Float 個數(shù)吁恍,表示下一個頂點(diǎn)數(shù)據(jù)從哪里開始讀
glVertexAttribPointer(a_position, POSITION_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, mVertexBuffer);
// 使能頂點(diǎn)屬性數(shù)組,每個attribute都要調(diào)用一次播演,相當(dāng)于一個開關(guān)冀瓦,調(diào)用后,OpenGL才知道到哪里找到屬性對應(yīng)的數(shù)據(jù)
glEnableVertexAttribArray(a_position);
// 調(diào)節(jié)緩沖區(qū)的指針写烤,從表示顏色的位置開始讀
mVertexBuffer.position(POSITION_COMPONENT_COUNT);
glVertexAttribPointer(a_color, COLOR_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, mVertexBuffer);
glEnableVertexAttribArray(a_color);
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl10) {
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
glDrawArrays(GL_LINES, 6, 2);
glDrawArrays(GL_POINTS, 8, 1);
glDrawArrays(GL_POINTS, 9, 1);
}
}