现在来看看的blending效果。
blending分为Additive blending,Multiplicative blending和Interpolative blending。
对应的方法分别为
glBlendFunc(GL_ONE, GL_ONE),
glBlendFunc(GL_DST_COLOR, GL_ZERO)和
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)。
现在就用Additive blending来写个例子。
这里的GLSurfaceView要处理点击消息来开启和关闭blending效果,所以单独提取一个类。
Test6SurfaceView.java
1 package com.android.jayce.test; 2 3 import android.content.Context; 4 import android.opengl.GLSurfaceView; 5 import android.view.MotionEvent; 6 7 public class Test6SurfaceView extends GLSurfaceView 8 { 9 private Test6Renderer mRenderer; 10 11 public Test6SurfaceView(Context context) { 12 super(context); 13 // TODO Auto-generated constructor stub 14 } 15 16 public boolean onTouchEvent(MotionEvent event) 17 { 18 if(event != null) 19 { 20 if(event.getAction() == MotionEvent.ACTION_DOWN) 21 { 22 if(mRenderer != null) 23 { 24 queueEvent(new Runnable(){ 25 26 @Override 27 public void run() { 28 // TODO Auto-generated method stub 29 mRenderer.switchMode(); 30 }}); 31 return true; 32 } 33 } 34 } 35 return super.onTouchEvent(event); 36 } 37 38 public void setRenderer(Test6Renderer renderer) 39 { 40 mRenderer = renderer; 41 super.setRenderer(renderer); 42 } 43 44 }
Renderer里面开关blending效果在switchMode里。
开启是:
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
关闭是:
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDisable(GLES20.GL_BLEND);
看完整代码:
Test6Renderer.java
1 package com.android.jayce.test; 2 3 import java.nio.ByteBuffer; 4 import java.nio.ByteOrder; 5 import java.nio.FloatBuffer; 6 7 import javax.microedition.khronos.egl.EGLConfig; 8 import javax.microedition.khronos.opengles.GL10; 9 10 import com.learnopengles.android.common.ShapeBuilder; 11 12 import android.opengl.GLES20; 13 import android.opengl.Matrix; 14 import android.opengl.GLSurfaceView; 15 import android.os.SystemClock; 16 17 public class Test6Renderer implements GLSurfaceView.Renderer 18 { 19 private static final int BYTES_PER_FLOAT = 4; 20 private final FloatBuffer mCubePositions; 21 private final FloatBuffer mCubeColors; 22 private float[] mMVPMatrix = new float[16]; 23 private float[] mViewMatrix = new float[16]; 24 private float[] mModelMatrix = new float[16]; 25 private float[] mProjectionMatrix = new float[16]; 26 private int mMVPMatrixHandle; 27 private int mPositionHandle; 28 private int mColorHandle; 29 private int mProgramHandle; 30 private final int POSITION_DATA_SIZE = 3; 31 private final int COLOR_DATA_SIZE = 4; 32 private boolean mBlending = true; 33 34 public Test6Renderer() 35 { 36 final float[] p1p = {-1.0f, 1.0f, 1.0f}; 37 final float[] p2p = {1.0f, 1.0f, 1.0f}; 38 final float[] p3p = {-1.0f, -1.0f, 1.0f}; 39 final float[] p4p = {1.0f, -1.0f, 1.0f}; 40 final float[] p5p = {-1.0f, 1.0f, -1.0f}; 41 final float[] p6p = {1.0f, 1.0f, -1.0f}; 42 final float[] p7p = {-1.0f, -1.0f, -1.0f}; 43 final float[] p8p = {1.0f, -1.0f, -1.0f}; 44 final float[] cubePosition = ShapeBuilder.generateCubeData(p1p, p2p, p3p, p4p, p5p, p6p, p7p, p8p, p1p.length); 45 46 final float[] p1c = {1.0f, 0.0f, 0.0f, 1.0f}; // red 47 final float[] p2c = {1.0f, 0.0f, 1.0f, 1.0f}; // magenta 48 final float[] p3c = {0.0f, 0.0f, 0.0f, 1.0f}; // black 49 final float[] p4c = {0.0f, 0.0f, 1.0f, 1.0f}; // blue 50 final float[] p5c = {1.0f, 1.0f, 0.0f, 1.0f}; // yellow 51 final float[] p6c = {1.0f, 1.0f, 1.0f, 1.0f}; // white 52 final float[] p7c = {0.0f, 1.0f, 0.0f, 1.0f}; // green 53 final float[] p8c = {0.0f, 1.0f, 1.0f, 1.0f}; // cyan 54 55 final float[] cubeColor = ShapeBuilder.generateCubeData(p1c, p2c, p3c, p4c, p5c, p6c, p7c, p8c, p1c.length); 56 57 mCubePositions = ByteBuffer.allocateDirect(cubePosition.length * BYTES_PER_FLOAT) 58 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 59 mCubePositions.put(cubePosition).position(0); 60 mCubeColors = ByteBuffer.allocateDirect(cubeColor.length * BYTES_PER_FLOAT) 61 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 62 mCubeColors.put(cubeColor).position(0); 63 } 64 65 @Override 66 public void onDrawFrame(GL10 gl) { 67 // TODO Auto-generated method stub 68 if (mBlending) 69 { 70 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 71 } 72 else 73 { 74 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 75 } 76 long time = SystemClock.uptimeMillis() % 10000L; 77 float angleInDegrees = (360.0f / 10000.0f) * ((int) time); 78 GLES20.glUseProgram(mProgramHandle); 79 mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix"); 80 mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position"); 81 mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color"); 82 83 Matrix.setIdentityM(mModelMatrix, 0); 84 Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -5.0f); 85 Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f); 86 drawCube(mCubePositions, mCubeColors); 87 } 88 89 public void switchMode() 90 { 91 mBlending = !mBlending; 92 93 if (mBlending) 94 { 95 // No culling of back faces 96 GLES20.glDisable(GLES20.GL_CULL_FACE); 97 98 // No depth testing 99 GLES20.glDisable(GLES20.GL_DEPTH_TEST); 100 101 // Enable blending 102 GLES20.glEnable(GLES20.GL_BLEND); 103 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE); 104 } 105 else 106 { 107 // Cull back faces 108 GLES20.glEnable(GLES20.GL_CULL_FACE); 109 110 // Enable depth testing 111 GLES20.glEnable(GLES20.GL_DEPTH_TEST); 112 113 // Disable blending 114 GLES20.glDisable(GLES20.GL_BLEND); 115 } 116 } 117 118 private void drawCube(final FloatBuffer cubePositionsBuffer, final FloatBuffer cubeColorsBuffer) 119 { 120 cubePositionsBuffer.position(0); 121 GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubePositionsBuffer); 122 GLES20.glEnableVertexAttribArray(mPositionHandle); 123 124 cubeColorsBuffer.position(0); 125 GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false, 0, cubeColorsBuffer); 126 GLES20.glEnableVertexAttribArray(mColorHandle); 127 Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 128 Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 129 130 GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 131 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36); 132 } 133 134 @Override 135 public void onSurfaceChanged(GL10 gl, int width, int height) { 136 // TODO Auto-generated method stub 137 GLES20.glViewport(0, 0, width, height); 138 139 final float ratio = (float) width / height; 140 final float left = -ratio; 141 final float right = ratio; 142 final float bottom = -1.0f; 143 final float top = 1.0f; 144 final float near = 1.0f; 145 final float far = 10.0f; 146 147 Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far); 148 } 149 150 @Override 151 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 152 // TODO Auto-generated method stub 153 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 154 GLES20.glDisable(GLES20.GL_CULL_FACE); 155 GLES20.glDisable(GLES20.GL_DEPTH_TEST); 156 157 GLES20.glEnable(GLES20.GL_BLEND); 158 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE); 159 160 // Position the eye behind the origin. 161 final float eyeX = 0.0f; 162 final float eyeY = 0.0f; 163 final float eyeZ = -0.5f; 164 165 // We are looking toward the distance 166 final float lookX = 0.0f; 167 final float lookY = 0.0f; 168 final float lookZ = -5.0f; 169 170 // Set our up vector. This is where our head would be pointing were we holding the camera. 171 final float upX = 0.0f; 172 final float upY = 1.0f; 173 final float upZ = 0.0f; 174 175 // Set the view matrix. This matrix can be said to represent the camera position. 176 // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and 177 // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose. 178 Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 179 180 final String vertexShader = 181 "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix. 182 183 + "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in. 184 + "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in. 185 + "varying vec4 v_Color; \n" // This will be passed into the fragment shader. 186 187 + "void main() \n" // The entry point for our vertex shader. 188 + "{ \n" 189 + " v_Color = a_Color; \n" // Pass the color through to the fragment shader. 190 // It will be interpolated across the triangle. 191 + " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position. 192 + " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in 193 + "} \n"; // normalized screen coordinates. 194 195 final String fragmentShader = 196 "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a 197 // precision in the fragment shader. 198 + "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the 199 // triangle per fragment. 200 + "void main() \n" // The entry point for our fragment shader. 201 + "{ \n" 202 + " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline. 203 + "} \n"; 204 205 int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); 206 if(vertexShaderHandle != 0) 207 { 208 GLES20.glShaderSource(vertexShaderHandle, vertexShader); 209 GLES20.glCompileShader(vertexShaderHandle); 210 211 final int[] compileStatus = new int[1]; 212 GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 213 214 if(compileStatus[0] == 0) 215 { 216 GLES20.glDeleteShader(vertexShaderHandle); 217 vertexShaderHandle = 0; 218 } 219 } 220 221 if(vertexShaderHandle == 0) 222 { 223 throw new RuntimeException("failed to creating vertex shader"); 224 } 225 226 int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); 227 if(fragmentShaderHandle != 0) 228 { 229 GLES20.glShaderSource(fragmentShaderHandle, fragmentShader); 230 GLES20.glCompileShader(fragmentShaderHandle); 231 232 final int[] compileStatus = new int[1]; 233 GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 234 235 if(compileStatus[0] == 0) 236 { 237 GLES20.glDeleteShader(fragmentShaderHandle); 238 fragmentShaderHandle = 0; 239 } 240 241 } 242 243 if(fragmentShaderHandle == 0) 244 { 245 throw new RuntimeException("failed to create fragment shader"); 246 } 247 248 mProgramHandle = GLES20.glCreateProgram(); 249 if(mProgramHandle != 0) 250 { 251 GLES20.glAttachShader(mProgramHandle, vertexShaderHandle); 252 GLES20.glAttachShader(mProgramHandle, fragmentShaderHandle); 253 254 GLES20.glBindAttribLocation(mProgramHandle, 0, "a_Position"); 255 GLES20.glBindAttribLocation(mProgramHandle, 1, "a_Color"); 256 257 GLES20.glLinkProgram(mProgramHandle); 258 259 final int[] linkStatus = new int[1]; 260 GLES20.glGetProgramiv(mProgramHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); 261 262 if(linkStatus[0] == 0) 263 { 264 GLES20.glDeleteProgram(mProgramHandle); 265 mProgramHandle = 0; 266 } 267 } 268 269 if(mProgramHandle == 0) 270 { 271 throw new RuntimeException("failed to create program"); 272 } 273 274 } 275 276 }
构造方法里用了内置方法来生成CubePosition和CubeColor。
来看看效果:
开启blending效果:
关闭blending效果: