无纹理四边形未在 OpenGL ES 3.0 中呈现
Untextured Quad not rendering in OpenGL ES 3.0
我最近使用 javax.swing 框架编写了一个简单的游戏,并希望将其作为 android 应用程序发布。我做了一些研究,发现大多数应用程序都使用 java 和 OpenGL ES。我有一些 OpenGL 经验,但正在熟悉 OpenGL ES。但是,每当我尝试渲染一个简单的四边形(使用 GLES30 顶点数组)时,我只会看到我的红色背景(我用 GL10.glClearColor() 指定了它)。我很可能遗漏了一些非常明显的东西,但我花了很多时间研究但没有找到切实的结果。
这是我的 MainActivity 代码:
public class MainActivity extends Activity {
private Screen screen;
private Sketcher s;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
screen = findViewById(R.id.surface_view);
screen.setEGLContextClientVersion(3);
s = new Sketcher(getAssets());
screen.setRenderer(s);
screen.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
@Override
public void onPause() {
super.onPause();
screen.onPause();
}
@Override
public void onResume() {
super.onResume();
screen.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
s.free();
}
}
请记住,Screen class 仅复制 GLSurfaceView 的构造函数并生成 onPause() 和 onResume() 方法 public。
速写者class:
public class Sketcher implements GLSurfaceView.Renderer {
private Player p;
private Shader pShader;
private AssetManager am;
Sketcher(AssetManager am) {
this.am = am;
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
p = new Player();
//pShader = new Shader(am, "playerVertexShader.txt", "playerFragmentShader.txt");
//pShader.setUniforms();
GLES10.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
}
@Override
public void onDrawFrame(GL10 unused) {
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
//pShader.activate();
GLES30.glBindVertexArray(p.getVaoID());
GLES20.glEnableVertexAttribArray(0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_INT, 0);
GLES20.glDisableVertexAttribArray(0);
GLES30.glBindVertexArray(0);
//pShader.deactivate();
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES10.glViewport(0, 0, width, height);
}
void free() {
p.free();
//pShader.free();
}
}
玩家class:
public class Player {
public static final float RADIUS = 0.5f;
private static final float ACC = 0.02f;
private static final float MAX_SPEED = 2.0f;
private static final int PRECISION = 10;
private float x, y;
private float vx, vy;
private int vaoID;
private int vBufferID;
private int iBufferID;
public Player() {
int[] vao = new int[1];
int[] buffers = new int[2];
GLES30.glGenVertexArrays(1, vao, 0);
vaoID = vao[0];
GLES30.glGenBuffers(2, buffers, 0);
vBufferID = buffers[0];
iBufferID = buffers[1];
ByteBuffer vBuffer = ByteBuffer.allocateDirect(Float.BYTES * 8).order(ByteOrder.nativeOrder());
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.flip();
/*
vBuffer.put(0.0f);
vBuffer.put(0.0f);
for (int i = 0; i < PRECISION; i++) {
double angle = Math.PI / PRECISION * i;
vBuffer.put((float)(Math.sin(angle) * RADIUS));
vBuffer.put((float)(Math.cos(angle) * RADIUS));
}
*/
ByteBuffer iBuffer = ByteBuffer.allocateDirect(Integer.BYTES * 6).order(ByteOrder.nativeOrder());
iBuffer.putInt(0);
iBuffer.putInt(1);
iBuffer.putInt(2);
iBuffer.putInt(0);
iBuffer.putInt(2);
iBuffer.putInt(3);
iBuffer.flip();
/*
for (int i = 1; i < PRECISION - 1; i++) {
iBuffer.put(0);
iBuffer.put(i + 1);
iBuffer.put(i);
}
iBuffer.put(0);
iBuffer.put(1);
iBuffer.put(PRECISION - 1);
*/
GLES30.glBindVertexArray(vaoID);
GLES20.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vBuffer.capacity(), vBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glVertexAttribPointer(0, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, iBuffer.capacity(), iBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES30.glBindVertexArray(0);
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return 6;
}
public void free() {
GLES30.glDeleteVertexArrays(1, new int[] {vaoID}, 0);
GLES30.glDeleteBuffers(2, new int[] {vBufferID, iBufferID}, 0);
}
}
我注释掉了很多与游戏更相关的代码,因为我必须进行简化,直到达到最低点(绘制一个简单的无纹理四边形)。
这是着色器代码:
#version 300 es
layout(location = 0) in vec2 vertex;
void main() {
gl_Position = vec4(vertex, 0.0, 1.0);
}
#version 300 es
out vec4 fragment;
void main() {
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
当您创建 Index buffers 时,您就创建了一个“字节”缓冲区。这意味着每个索引都存储在一个字节中:
ByteBuffer iBuffer = ByteBuffer.allocateDirect(Integer.BYTES*6).order(ByteOrder.nativeOrder());
iBuffer.putInt(0);
iBuffer.putInt(1);
GLES20.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, iBuffer.capacity(), iBuffer, GLES20.GL_STATIC_DRAW);
因此绘制网格时指定的索引类型必须是GL_UNSIGNED_BYTE
(glDrawElements
)
GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_BYTE, 0);
而不是GL_UNSIGNED_INT
:
GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_INT, 0);
也可以,也可以使用IntBuffer
对应元素类型GL_UNSIGNED_INT
.
或者将 ShortBuffer
与 GL_UNSIGNED_SHORT
.
结合使用
确实在片段着色器中缺少 Precision qualifiers,它们不是可选的 (OpenGL ES)。例如添加默认精度限定符:
precision medium float;
我最近使用 javax.swing 框架编写了一个简单的游戏,并希望将其作为 android 应用程序发布。我做了一些研究,发现大多数应用程序都使用 java 和 OpenGL ES。我有一些 OpenGL 经验,但正在熟悉 OpenGL ES。但是,每当我尝试渲染一个简单的四边形(使用 GLES30 顶点数组)时,我只会看到我的红色背景(我用 GL10.glClearColor() 指定了它)。我很可能遗漏了一些非常明显的东西,但我花了很多时间研究但没有找到切实的结果。
这是我的 MainActivity 代码:
public class MainActivity extends Activity {
private Screen screen;
private Sketcher s;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
screen = findViewById(R.id.surface_view);
screen.setEGLContextClientVersion(3);
s = new Sketcher(getAssets());
screen.setRenderer(s);
screen.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
@Override
public void onPause() {
super.onPause();
screen.onPause();
}
@Override
public void onResume() {
super.onResume();
screen.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
s.free();
}
}
请记住,Screen class 仅复制 GLSurfaceView 的构造函数并生成 onPause() 和 onResume() 方法 public。
速写者class:
public class Sketcher implements GLSurfaceView.Renderer {
private Player p;
private Shader pShader;
private AssetManager am;
Sketcher(AssetManager am) {
this.am = am;
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
p = new Player();
//pShader = new Shader(am, "playerVertexShader.txt", "playerFragmentShader.txt");
//pShader.setUniforms();
GLES10.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
}
@Override
public void onDrawFrame(GL10 unused) {
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
//pShader.activate();
GLES30.glBindVertexArray(p.getVaoID());
GLES20.glEnableVertexAttribArray(0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_INT, 0);
GLES20.glDisableVertexAttribArray(0);
GLES30.glBindVertexArray(0);
//pShader.deactivate();
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES10.glViewport(0, 0, width, height);
}
void free() {
p.free();
//pShader.free();
}
}
玩家class:
public class Player {
public static final float RADIUS = 0.5f;
private static final float ACC = 0.02f;
private static final float MAX_SPEED = 2.0f;
private static final int PRECISION = 10;
private float x, y;
private float vx, vy;
private int vaoID;
private int vBufferID;
private int iBufferID;
public Player() {
int[] vao = new int[1];
int[] buffers = new int[2];
GLES30.glGenVertexArrays(1, vao, 0);
vaoID = vao[0];
GLES30.glGenBuffers(2, buffers, 0);
vBufferID = buffers[0];
iBufferID = buffers[1];
ByteBuffer vBuffer = ByteBuffer.allocateDirect(Float.BYTES * 8).order(ByteOrder.nativeOrder());
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.putFloat(-RADIUS);
vBuffer.putFloat( RADIUS);
vBuffer.flip();
/*
vBuffer.put(0.0f);
vBuffer.put(0.0f);
for (int i = 0; i < PRECISION; i++) {
double angle = Math.PI / PRECISION * i;
vBuffer.put((float)(Math.sin(angle) * RADIUS));
vBuffer.put((float)(Math.cos(angle) * RADIUS));
}
*/
ByteBuffer iBuffer = ByteBuffer.allocateDirect(Integer.BYTES * 6).order(ByteOrder.nativeOrder());
iBuffer.putInt(0);
iBuffer.putInt(1);
iBuffer.putInt(2);
iBuffer.putInt(0);
iBuffer.putInt(2);
iBuffer.putInt(3);
iBuffer.flip();
/*
for (int i = 1; i < PRECISION - 1; i++) {
iBuffer.put(0);
iBuffer.put(i + 1);
iBuffer.put(i);
}
iBuffer.put(0);
iBuffer.put(1);
iBuffer.put(PRECISION - 1);
*/
GLES30.glBindVertexArray(vaoID);
GLES20.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vBuffer.capacity(), vBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glVertexAttribPointer(0, 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, iBuffer.capacity(), iBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES30.glBindVertexArray(0);
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return 6;
}
public void free() {
GLES30.glDeleteVertexArrays(1, new int[] {vaoID}, 0);
GLES30.glDeleteBuffers(2, new int[] {vBufferID, iBufferID}, 0);
}
}
我注释掉了很多与游戏更相关的代码,因为我必须进行简化,直到达到最低点(绘制一个简单的无纹理四边形)。
这是着色器代码:
#version 300 es
layout(location = 0) in vec2 vertex;
void main() {
gl_Position = vec4(vertex, 0.0, 1.0);
}
#version 300 es
out vec4 fragment;
void main() {
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
当您创建 Index buffers 时,您就创建了一个“字节”缓冲区。这意味着每个索引都存储在一个字节中:
ByteBuffer iBuffer = ByteBuffer.allocateDirect(Integer.BYTES*6).order(ByteOrder.nativeOrder()); iBuffer.putInt(0); iBuffer.putInt(1);
GLES20.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, iBufferID); GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, iBuffer.capacity(), iBuffer, GLES20.GL_STATIC_DRAW);
因此绘制网格时指定的索引类型必须是GL_UNSIGNED_BYTE
(glDrawElements
)
GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_BYTE, 0);
而不是GL_UNSIGNED_INT
:
GLES20.glDrawElements(GLES20.GL_TRIANGLES, p.getVertexCount(), GLES20.GL_UNSIGNED_INT, 0);
也可以,也可以使用IntBuffer
对应元素类型GL_UNSIGNED_INT
.
或者将 ShortBuffer
与 GL_UNSIGNED_SHORT
.
确实在片段着色器中缺少 Precision qualifiers,它们不是可选的 (OpenGL ES)。例如添加默认精度限定符:
precision medium float;