上一篇文章里绘制的三角形,颜色都是写死在Fragment Shader里的,这篇文章介绍如何把颜色写到顶点数据里并且在Shader里使用Varying变量实现颜色插值。
代码和效果
把下面的脚本复制到OpenGL Console里:
import java.nio.ByteBuffer
import java.nio.ByteOrder
import javax.media.opengl.GL
def vertexShaderCode = """
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
v_Color = a_Color;
}
"""
def fragmentShaderCode = """
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
"""
def shaderProgram = glob.compileAndLink(vertexShaderCode, fragmentShaderCode)
def aPositionLocation = shaderProgram.getAttribLocation("a_Position")
def aColorLocation = shaderProgram.getAttribLocation("a_Color")
shaderProgram.use()
def BYTES_PER_FLOAT = 4
def POSITION_ELEMENT_COUNT = 2
def COLOR_ELEMENT_COUNT = 3
def STRIDE = (POSITION_ELEMENT_COUNT + COLOR_ELEMENT_COUNT) * BYTES_PER_FLOAT
def POINT_COUNT = 3
def vertices = [
//x y r g b
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.8f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.8f, 0.0f, 0.0f, 1.0f,
] as float[]
def vertexData = ByteBuffer
.allocateDirect(vertices.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
vertexData.put(vertices)
vertexData.position(0)
gl.glVertexAttribPointer(aPositionLocation,
POSITION_ELEMENT_COUNT, gl.GL_FLOAT, false, STRIDE, vertexData)
gl.glEnableVertexAttribArray(aPositionLocation)
vertexData.position(POSITION_ELEMENT_COUNT)
gl.glVertexAttribPointer(aColorLocation,
COLOR_ELEMENT_COUNT, gl.GL_FLOAT, false, STRIDE, vertexData)
gl.glEnableVertexAttribArray(aColorLocation)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
gl.glDrawArrays(gl.GL_TRIANGLES, 0, POINT_COUNT)
效果:
顶点颜色属性
先来看看Vertex Shader代码:
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
v_Color = a_Color;
}
现在有两个vec4类型的
attribute变量,一个代表顶点的位置(
xyzw),一个代表颜色(
rgba)。我画了个示意图:
def BYTES_PER_FLOAT = 4
def POSITION_ELEMENT_COUNT = 2
def COLOR_ELEMENT_COUNT = 3
def STRIDE = (POSITION_ELEMENT_COUNT + COLOR_ELEMENT_COUNT) * BYTES_PER_FLOAT
def POINT_COUNT = 3
def vertices = [
//x y r g b
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.8f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.8f, 0.0f, 0.0f, 1.0f,
] as float[]
除了位置(x和y坐标)外,我们把颜色(rgb)也放到了数组里,如下图所示:
def shaderProgram = glob.compileAndLink(vertexShaderCode, fragmentShaderCode)
def aPositionLocation = shaderProgram.getAttribLocation("a_Position")
def aColorLocation = shaderProgram.getAttribLocation("a_Color")
shaderProgram.use()
...
vertexData.position(0)
gl.glVertexAttribPointer(aPositionLocation,
POSITION_ELEMENT_COUNT, gl.GL_FLOAT, false, STRIDE, vertexData)
gl.glEnableVertexAttribArray(aPositionLocation)
vertexData.position(POSITION_ELEMENT_COUNT)
gl.glVertexAttribPointer(aColorLocation,
COLOR_ELEMENT_COUNT, gl.GL_FLOAT, false, STRIDE, vertexData)
gl.glEnableVertexAttribArray(aColorLocation)
上面这段代码把Vertex Shader和顶点数据联系在了一起:
Varying变量
Vertex Shader和Fragment Shader都定义了一个vec4类型的Varying变量,这个变量将Vertex和Fragment Shader连接了起来。Vertex Shader把顶点的颜色属性传递给varying变量(v_Color = a_Color;),然后OpenGL会对其进行插值,这样我们就可以在Fragment Shader里使用插值后的变量了(gl_FragColor = v_Color;)。