上一篇文章里绘制的三角形,颜色都是写死在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和顶点数据联系在了一起:
Vertex Shader和Fragment Shader都定义了一个vec4类型的Varying变量,这个变量将Vertex和Fragment Shader连接了起来。Vertex Shader把顶点的颜色属性传递给varying变量(v_Color = a_Color;),然后OpenGL会对其进行插值,这样我们就可以在Fragment Shader里使用插值后的变量了(gl_FragColor = v_Color;)。