Android OpenGL 为整个网格渲染纹理的第一个像素
Android OpenGL rendering first pixel of a texture for the entire mesh
我正在尝试在正方形上渲染纹理。该正方形由 2 个三角形构成,并使用索引缓冲区。我遇到的问题是整个正方形是单一颜色,即使对于 S 和 T 坐标,我指定了整个纹理(其中有不同的颜色。)
我的贴图
如您所见,这是结果...
显示
这就是我想要做的...
我的着色器非常简单,只是一个简单的模型视图矩阵和一个位置
顶点着色器
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec2 aTextureCoordinates;
varying vec2 vTextureCoordinates;
void main()
{
vTextureCoordinates = aTextureCoordinates;
gl_Position = uMVPMatrix * aPosition;
}
片段着色器
precision mediump float;
uniform sampler2D uTextureUnit;
varying vec2 vTextureCoordinates;
void main()
{
gl_FragColor = texture2D(uTextureUnit, vTextureCoordinates);
}
GL 表面视图
在我的 GlSurfaceView 实例中,我获取了这些 GPU 变量并创建了一个新的 SquareTexture2
对象
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig)
{
int mvpHandle = -1;
int positionHandle = -1;
int textureHandle = -1;
int textureUniform = -1;
shader = new Shader(context, R.raw.vertex_texture, R.raw.fragment_texture);
mvpHandle = GLES20.glGetUniformLocation(shader.getProgramID(),"uMVPMatrix");
positionHandle = GLES20.glGetAttribLocation(shader.getProgramID(), "aPosition");
textureHandle = GLES20.glGetAttribLocation(shader.getProgramID(),"aTextureCoordinate");
textureUniform = GLES20.glGetUniformLocation(shader.getProgramID(),"uTextureUnits");
camera = new Camera(mvpHandle);
squareTexture = new SquareTexture2(positionHandle,textureUniform,textureHandle, this.context, R.raw.texture1);
GLES20.glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
}
SquareTexture2
我的 SquareTexture2 class 真的很简单...只有 2 个方法。构造函数和渲染函数。
public SquareTexture2(int aPositionHandle, int uTextureHandle, int aTextureHandle, Context context, int resourceId)
{
float[] shape =
{
1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
};
int[] index =
{
0, 2, 1,
0, 3, 2,
};
this.aPositionHandle = aPositionHandle;
this.uTextureHandle = uTextureHandle;
this.aTextureHandle = aTextureHandle;
vertexObject = new VertexObject(shape,index);
texture = new Texture(context, resourceId);
this.textureId = texture.getTextureId();
}
public void render()
{
GLES20.glEnableVertexAttribArray(aPositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,this.textureId);
GLES20.glUniform1i(this.uTextureHandle, 0);
vertexObject.bind(aPositionHandle, aTextureHandle,16);
vertexObject.render();
}
最后是 Texture class 定义和 VertexBuffer class 定义,这也非常简单。
顶点对象
public class VertexObject
{
private FloatBuffer vertexData;
private IntBuffer indexData;
private int vertexBufferId;
private int indexBufferId;
public VertexObject(float[] shape, int[] index)
{
this.createVertexData(shape);
this.createIndexData(index);
}
private void createVertexData(float[] shape)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(shape.length*4);
vbb.order(ByteOrder.nativeOrder());
vertexData = vbb.asFloatBuffer();
vertexData.put(shape);
vertexData.position(0);
int[] buffer = new int[1];
GLES20.glGenBuffers(1,buffer,0);
if(buffer[0] == 0)
{
throw new RuntimeException("Unable to generate Buffer");
}
this.vertexBufferId = buffer[0];
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexData.capacity()*4, vertexData,GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
private void createIndexData(int[] index)
{
ByteBuffer ibb = ByteBuffer.allocateDirect(index.length*4);
ibb.order(ByteOrder.nativeOrder());
indexData = ibb.asIntBuffer();
indexData.put(index);
indexData.position(0);
int[] buffer = new int[1];
GLES20.glGenBuffers(1,buffer,0);
if(buffer[0] == 0)
{
throw new RuntimeException("Unable to generate Buffer");
}
this.indexBufferId = buffer[0];
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexData.capacity()*4, indexData, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,0);
}
public void bind(int aPosition, int aTextureCoordinate, int stride)
{
vertexData.position(0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,this.vertexBufferId);
GLES20.glVertexAttribPointer(aPosition, 2, GLES20.GL_FLOAT,false, stride, 0);
GLES20.glEnableVertexAttribArray(aPosition);
vertexData.position(2);
GLES20.glVertexAttribPointer(aTextureCoordinate,2,GLES20.GL_FLOAT,false,stride,vertexData);
GLES20.glEnableVertexAttribArray(aTextureCoordinate);
}
public void render()
{
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, this.indexBufferId);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT,0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,0);
}
}
纹理
public class Texture
{
private int textureId;
public Texture(Context context, int resourceId)
{
int[] textureObjectIds = new int[1];
GLES20.glGenTextures(1, textureObjectIds, 0);
if (textureObjectIds[0] == 0)
{
throw new RuntimeException("Unable to create a texture");
}
this.textureId = textureObjectIds[0];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
if (bitmap == null)
{
throw new RuntimeException("Unable to decode a bitmap");
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureObjectIds[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
public int getTextureId()
{
return this.textureId;
}
}
我正在编写的“OpenGL ES 2 for Android”这本书没有纹理和索引缓冲区,这似乎是问题所在。我也看过这个视频一百万次,但仍然无法正常工作。 https://www.youtube.com/watch?v=n4k7ANAFsIQ&ab_channel=TheCherno
当命名缓冲区对象绑定到目标 GL_ARRAY_BUFFER
时,glVertexAttribPointer
的最后一个参数被视为该缓冲区中的字节偏移量。
指定纹理坐标时,glVertexAttribPointer
的最后一个参数必须是 8(字节)而不是缓冲区:
GLES20.glVertexAttribPointer(aTextureCoordinate,2,GLES20.GL_FLOAT,false,stride,vertexData);
GLES20.glVertexAttribPointer(aTextureCoordinate,2,GLES20.GL_FLOAT,false,stride, 8);
指定顶点坐标时,偏移量为0,您做对了。
我正在尝试在正方形上渲染纹理。该正方形由 2 个三角形构成,并使用索引缓冲区。我遇到的问题是整个正方形是单一颜色,即使对于 S 和 T 坐标,我指定了整个纹理(其中有不同的颜色。)
如您所见,这是结果...
这就是我想要做的... 我的着色器非常简单,只是一个简单的模型视图矩阵和一个位置
顶点着色器
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec2 aTextureCoordinates;
varying vec2 vTextureCoordinates;
void main()
{
vTextureCoordinates = aTextureCoordinates;
gl_Position = uMVPMatrix * aPosition;
}
片段着色器
precision mediump float;
uniform sampler2D uTextureUnit;
varying vec2 vTextureCoordinates;
void main()
{
gl_FragColor = texture2D(uTextureUnit, vTextureCoordinates);
}
GL 表面视图
在我的 GlSurfaceView 实例中,我获取了这些 GPU 变量并创建了一个新的 SquareTexture2
对象
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig)
{
int mvpHandle = -1;
int positionHandle = -1;
int textureHandle = -1;
int textureUniform = -1;
shader = new Shader(context, R.raw.vertex_texture, R.raw.fragment_texture);
mvpHandle = GLES20.glGetUniformLocation(shader.getProgramID(),"uMVPMatrix");
positionHandle = GLES20.glGetAttribLocation(shader.getProgramID(), "aPosition");
textureHandle = GLES20.glGetAttribLocation(shader.getProgramID(),"aTextureCoordinate");
textureUniform = GLES20.glGetUniformLocation(shader.getProgramID(),"uTextureUnits");
camera = new Camera(mvpHandle);
squareTexture = new SquareTexture2(positionHandle,textureUniform,textureHandle, this.context, R.raw.texture1);
GLES20.glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
}
SquareTexture2
我的 SquareTexture2 class 真的很简单...只有 2 个方法。构造函数和渲染函数。
public SquareTexture2(int aPositionHandle, int uTextureHandle, int aTextureHandle, Context context, int resourceId)
{
float[] shape =
{
1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
};
int[] index =
{
0, 2, 1,
0, 3, 2,
};
this.aPositionHandle = aPositionHandle;
this.uTextureHandle = uTextureHandle;
this.aTextureHandle = aTextureHandle;
vertexObject = new VertexObject(shape,index);
texture = new Texture(context, resourceId);
this.textureId = texture.getTextureId();
}
public void render()
{
GLES20.glEnableVertexAttribArray(aPositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,this.textureId);
GLES20.glUniform1i(this.uTextureHandle, 0);
vertexObject.bind(aPositionHandle, aTextureHandle,16);
vertexObject.render();
}
最后是 Texture class 定义和 VertexBuffer class 定义,这也非常简单。
顶点对象
public class VertexObject
{
private FloatBuffer vertexData;
private IntBuffer indexData;
private int vertexBufferId;
private int indexBufferId;
public VertexObject(float[] shape, int[] index)
{
this.createVertexData(shape);
this.createIndexData(index);
}
private void createVertexData(float[] shape)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(shape.length*4);
vbb.order(ByteOrder.nativeOrder());
vertexData = vbb.asFloatBuffer();
vertexData.put(shape);
vertexData.position(0);
int[] buffer = new int[1];
GLES20.glGenBuffers(1,buffer,0);
if(buffer[0] == 0)
{
throw new RuntimeException("Unable to generate Buffer");
}
this.vertexBufferId = buffer[0];
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexData.capacity()*4, vertexData,GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
private void createIndexData(int[] index)
{
ByteBuffer ibb = ByteBuffer.allocateDirect(index.length*4);
ibb.order(ByteOrder.nativeOrder());
indexData = ibb.asIntBuffer();
indexData.put(index);
indexData.position(0);
int[] buffer = new int[1];
GLES20.glGenBuffers(1,buffer,0);
if(buffer[0] == 0)
{
throw new RuntimeException("Unable to generate Buffer");
}
this.indexBufferId = buffer[0];
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexData.capacity()*4, indexData, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,0);
}
public void bind(int aPosition, int aTextureCoordinate, int stride)
{
vertexData.position(0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,this.vertexBufferId);
GLES20.glVertexAttribPointer(aPosition, 2, GLES20.GL_FLOAT,false, stride, 0);
GLES20.glEnableVertexAttribArray(aPosition);
vertexData.position(2);
GLES20.glVertexAttribPointer(aTextureCoordinate,2,GLES20.GL_FLOAT,false,stride,vertexData);
GLES20.glEnableVertexAttribArray(aTextureCoordinate);
}
public void render()
{
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, this.indexBufferId);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT,0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER,0);
}
}
纹理
public class Texture
{
private int textureId;
public Texture(Context context, int resourceId)
{
int[] textureObjectIds = new int[1];
GLES20.glGenTextures(1, textureObjectIds, 0);
if (textureObjectIds[0] == 0)
{
throw new RuntimeException("Unable to create a texture");
}
this.textureId = textureObjectIds[0];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
if (bitmap == null)
{
throw new RuntimeException("Unable to decode a bitmap");
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureObjectIds[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
public int getTextureId()
{
return this.textureId;
}
}
我正在编写的“OpenGL ES 2 for Android”这本书没有纹理和索引缓冲区,这似乎是问题所在。我也看过这个视频一百万次,但仍然无法正常工作。 https://www.youtube.com/watch?v=n4k7ANAFsIQ&ab_channel=TheCherno
当命名缓冲区对象绑定到目标 GL_ARRAY_BUFFER
时,glVertexAttribPointer
的最后一个参数被视为该缓冲区中的字节偏移量。
指定纹理坐标时,glVertexAttribPointer
的最后一个参数必须是 8(字节)而不是缓冲区:
GLES20.glVertexAttribPointer(aTextureCoordinate,2,GLES20.GL_FLOAT,false,stride,vertexData);
GLES20.glVertexAttribPointer(aTextureCoordinate,2,GLES20.GL_FLOAT,false,stride, 8);
指定顶点坐标时,偏移量为0,您做对了。