今天的这个蜗牛真是太猛了,计算量超大,GPU直接拉到最高频,而且负载99%!!这是什么样的计算量,我们相机使用Opengl ES平时绘制的预览,GPU是最低频,而且负载也只有3%--10%左右,看来我们的技术还不够深,要能真正实现一个功能,正常使用GPU达到这样的频率的话,那才能突显出一定的水平。来看下蜗牛的效果。
GlSnailRender类的完整源码如下:
package com.opengl.learn.aric;
import android.content.Context;
import android.opengl.GLES32;
import android.opengl.GLSurfaceView;
import android.util.Log;
import com.opengl.learn.OpenGLUtils;
import com.opengl.learn.R;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_TEST;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_STATIC_DRAW;
import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE1;
import static android.opengl.GLES20.GL_TEXTURE2;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.glGenBuffers;
import static android.opengl.GLES20.glGetUniformLocation;
public class GlSnailRender implements GLSurfaceView.Renderer {
private static final String TAG = GlSnailRender.class.getSimpleName();
private final float[] mVerticesData =
{
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
};
private static final int BYTES_PER_FLOAT = 4;
private static final int POSITION_COMPONENT_COUNT = 3;
private Context mContext;
private FloatBuffer mVerticesBuffer;
private int mProgramObject, mVAO, mVBO, iTime, iResolution;
private int iChannel1, channel1, iChannel2, channel2, iChannel3, channel3;
private int mWidth, mHeight;
private long startTime;
public GlSnailRender(Context context) {
mContext = context;
mVerticesBuffer = ByteBuffer.allocateDirect(mVerticesData.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVerticesBuffer.put(mVerticesData).position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mProgramObject = OpenGLUtils.loadProgram(mContext, R.raw.glsea_vertex, R.raw.glsnail_fragment);
iResolution = glGetUniformLocation(mProgramObject, "iResolution");
iTime = glGetUniformLocation(mProgramObject, "iTime");
iChannel1 = glGetUniformLocation(mProgramObject, "iChannel1");
iChannel2 = glGetUniformLocation(mProgramObject, "iChannel2");
iChannel3 = glGetUniformLocation(mProgramObject, "iChannel3");
int[] array = new int[1];
GLES32.glGenVertexArrays(array.length, array, 0);
mVAO = array[0];
array = new int[1];
glGenBuffers(array.length, array, 0);
mVBO = array[0];
Log.e(TAG, "onSurfaceCreated, " + mProgramObject + ", uTime: " + iTime + ", uResolution: " + iResolution);
GLES32.glBindVertexArray(mVAO);
mVerticesBuffer.position(0);
GLES32.glBindBuffer(GL_ARRAY_BUFFER, mVBO);
GLES32.glBufferData(GL_ARRAY_BUFFER, BYTES_PER_FLOAT * mVerticesData.length, mVerticesBuffer, GL_STATIC_DRAW);
GLES32.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0, 0);
GLES32.glEnableVertexAttribArray(0);
channel1 = OpenGLUtils.loadTexture(mContext, R.mipmap.snail_channel1);
channel2 = OpenGLUtils.loadTexture(mContext, R.mipmap.snail_channel2);
channel3 = OpenGLUtils.loadTexture(mContext, R.mipmap.snail_channel3);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mWidth = width;
mHeight = height;
}
@Override
public void onDrawFrame(GL10 gl) {
long now = System.currentTimeMillis();
if (startTime == 0) {
startTime = now;
}
float time = (now - startTime) / (1000f * 5f);
GLES32.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLES32.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GLES32.glEnable(GL_DEPTH_TEST);
GLES32.glUseProgram(mProgramObject);
GLES32.glUniform1f(iTime, time);
GLES32.glUniform2f(iResolution, mWidth, mHeight);
GLES32.glActiveTexture(GL_TEXTURE0);
GLES32.glBindTexture(GL_TEXTURE_2D, channel1);
GLES32.glUniform1i(iChannel1, 0);
GLES32.glActiveTexture(GL_TEXTURE1);
GLES32.glBindTexture(GL_TEXTURE_2D, channel2);
GLES32.glUniform1i(iChannel2, 1);
GLES32.glActiveTexture(GL_TEXTURE2);
GLES32.glBindTexture(GL_TEXTURE_2D, channel3);
GLES32.glUniform1i(iChannel3, 2);
GLES32.glEnableVertexAttribArray(0);
GLES32.glBindVertexArray(mVAO);
GLES32.glDrawArrays(GL_TRIANGLES, 0, mVerticesData.length);
GLES32.glBindVertexArray(0);
GLES32.glDisableVertexAttribArray(0);
}
}
重点还是在片段着色器,网上有些说法也叫像素着色器,不过两个的重点不一样,片段着色器的重点是FragColor;像素着色器的重点是gl_FragCoord,一个变量就可以展开无数种炫丽的效果,像素着色器的魔法也就在gl_FragCoord内建变量中了。片段着色器的源码如下:
// Created by inigo quilez - 2015
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0
// You can buy a metal print of this shader here:
// https://www.redbubble.com/i/metal-print/Snail-by-InigoQuilez/39845499.0JXQP
#version 320 es
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
// antialiasing - make AA 2, meaning 4x AA, if you have a fast machine
#define AA 1
#define ZERO (min(2, 0)