我是一个固定功能的管道人员,习惯了新奇的着色器。
我正在尝试将Android OpenGL ES示例扩展为纹理方形。如果我的着色器的最后一行是gl_Fragcolor = vColor;
,我会得到一个白色方块。如果是gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);
,我只会变黑。
这里有更奇怪的地方:当我开始检查GL错误时,我发现draw()函数开头的行GLES20.glUseProgram(mProgram);
给出了GL错误1280,GL_INVALID_ENUM。这对我没有意义 - 没有传递给该函数的枚举。
思想?
DemoRenderer.java:
package com.wtracy.executivedemo;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.Matrix;
import android.util.Log;
public class DemoRenderer implements Renderer {
float ratio;
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private SplashScreen splash;
Activity parent;
public DemoRenderer(Activity parent) {
this.parent = parent;
}
public void onDrawFrame(GL10 arg0) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Draw square
splash.draw(mMVPMatrix);
}
public void onSurfaceChanged(GL10 arg0, int width, int height) {
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES20.glViewport(0, 0, width, height);
ratio = (float) width / height;
float newWidth;
float newHeight;
if (ratio >= 1f) {
newWidth = ratio;
newHeight = 1f;
} else {
newWidth = 1f;
newHeight = 1f/ratio;
}
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjectionMatrix, 0, -newWidth, newWidth, -newHeight, newHeight, 3, 7);
}
public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
splash = new SplashScreen(parent.getResources());
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
checkGlError("glCreateShader");
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
checkGlError("glShaderSource");
GLES20.glCompileShader(shader);
checkGlError("glCompileShader");
return shader;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e("com.wtracy.executivedemo", glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
SplashScreen.java:
package com.wtracy.executivedemo;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import com.wtracy.executivedemo.R;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
/**
* A two-dimensional square for use as a drawn object in OpenGL ES 2.0.
*/
public class SplashScreen {
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_TexCoordinate; " +// Per-vertex texture coordinate information we will pass in.
"varying vec2 v_TexCoordinate;" +
"void main() {" +
// The matrix must be included as a modifier of gl_Position.
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
" v_TexCoordinate = a_TexCoordinate;" +
"}";
private final String fragmentShaderCode =
"precision mediump float; " +
"uniform vec4 vColor; " +
"uniform sampler2D u_Texture; " +
"varying vec2 v_TexCoordinate; " +
"void main() {" +
/*" float diffuse;" +
" diffuse = diffuse * (1.0 / (1.0 + (0.10 * distance)));" +
" diffuse = diffuse + 0.3;" +*/
" gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);" +
//" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
/** Store our model data in a float buffer. */
private final FloatBuffer mCubeTextureCoordinates;
/** This will be used to pass in the texture. */
private int mTextureUniformHandle;
/** This will be used to pass in model texture coordinate information. */
private int mTextureCoordinateHandle;
/** Size of the texture coordinate data in elements. */
private final int mTextureCoordinateDataSize = 2;
/** This is a handle to our texture data. */
private int mTextureDataHandle;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float squareCoords[] = {
-1.f, 1.f, 0.0f, // top left
-1.f, -1.f, 0.0f, // bottom left
1.f, -1.f, 0.0f, // bottom right
1.f, 1.f, 0.0f }; // top right
private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
final float color[] = { 1f, 1f, 1f, 1.0f };
final int[] textureHandle = new int[1];
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public SplashScreen(Resources resources) {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
bb = ByteBuffer.allocateDirect(squareCoords.length*4);
bb.order(ByteOrder.nativeOrder());
mCubeTextureCoordinates = bb.asFloatBuffer();
mCubeTextureCoordinates.put(squareCoords);
mCubeTextureCoordinates.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
// prepare shaders and OpenGL program
int vertexShader = DemoRenderer.loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = DemoRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
DemoRenderer.checkGlError("glCreateProgramr");
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
DemoRenderer.checkGlError("glAttachShader");
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
DemoRenderer.checkGlError("glAttachShader");
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
DemoRenderer.checkGlError("glLinkProgram");
GLES20.glGenTextures(1, textureHandle, 0);
DemoRenderer.checkGlError("glGenTextures");
Bitmap bitmap;
BitmapFactory.Options bo = new BitmapFactory.Options();
bo.inScaled = false;
bitmap = BitmapFactory.decodeResource(
resources,
R.drawable.myfirstdemo,
bo);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
DemoRenderer.checkGlError("glBindTexture");
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
DemoRenderer.checkGlError("glTexParameter");
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* @param mvpMatrix - The Model View Project matrix in which to draw
* this shape.
*/
public void draw(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
DemoRenderer.checkGlError("glUseProgram");
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
DemoRenderer.checkGlError("glGetUniformLocation");
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
DemoRenderer.checkGlError("glGetAttribLocation");
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
DemoRenderer.checkGlError("glGetUniformLocation");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
DemoRenderer.checkGlError("glGetAttribLocation");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//DemoRenderer.checkGlError("glUniform4fv");
GLES20.glActiveTexture(textureHandle[0]);
//DemoRenderer.checkGlError("glActiveTexture");
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
//DemoRenderer.checkGlError("glBindTexture");
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
//DemoRenderer.checkGlError("glUniform1i");
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
//DemoRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
//DemoRenderer.checkGlError("glUniformMatrix4fv");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// Pass in the texture coordinate information
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false,
0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
// Draw the square
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle);
}
}
答案 0 :(得分:1)
您的GL_INVALID_ENUM
错误几乎肯定是来自不同的电话。请记住,错误值会一直持续到您检查它为止。所以它可以来自glGetError()
的最后一次调用以来的任何调用。
从快速扫描代码,我看到两个调用得到错误的参数:
GLES20.glActiveTexture(textureHandle[0]);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
glActiveTexture()
采用枚举来定义要绑定的纹理单元,同时传递纹理名称。glBindTexture()
需要一个纹理名称作为第二个参数,而传递一个未在发布的代码中的任何位置赋值的变量。这些电话应该是:
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);