无法在 OpenGL ES 中渲染简单的三角形
Cannot render simple triangle in OpenGL ES
我正在尝试通过渲染一个简单的三角形开始使用 OpenGL ES。
我使用 Android 和 Java 代码完成所有 EGL 初始化,然后 JNI 调用以便我可以使用 C 进行实际渲染。我已经通过简单地在 glClearColor
命令中更改颜色,然后调用 glClear
(然后会出现正确的颜色)来验证所有内容都已正确连接。但是,当我尝试下面的代码时,什么也没有出现,我也不知道为什么。请原谅许多 glGetError
电话。我只是想确定没有调用失败,确实如此。
#include "gl_render.h"
#include "gl_wrapper.h"
#include <math.h>
GLuint programObject;
GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
GLuint shader;
GLint compiled;
GLenum error;
shader = glCreateShader ( type );
error = glGetError();
if (error != GL_NO_ERROR) {
return -50;
}
glShaderSource ( shader, 1, &shaderSrc, NULL );
error = glGetError();
if (error != GL_NO_ERROR) {
return -51;
}
glCompileShader ( shader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -52;
}
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
error = glGetError();
if (error != GL_NO_ERROR) {
return -53;
}
if ( !compiled ) {
GLint infoLen = 0;
glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
error = glGetError();
if (error != GL_NO_ERROR) {
return -54;
}
if ( infoLen > 1 ) {
char *infoLog = malloc ( sizeof ( char ) * infoLen );
glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
error = glGetError();
if (error != GL_NO_ERROR) {
return -55;
}
free ( infoLog );
}
glDeleteShader ( shader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -56;
}
return -2;
}
return shader;
}
int on_surface_created() {
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";
GLuint vertexShader;
GLuint fragmentShader;
GLuint programObject;
GLint linked;
GLenum error;
vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
if (vertexShader < 0) {
return vertexShader;
}
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
if (fragmentShader < 0) {
return fragmentShader;
}
programObject = glCreateProgram ( );
error = glGetError();
if (error != GL_NO_ERROR) {
return -57;
}
glAttachShader ( programObject, vertexShader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -58;
}
glAttachShader ( programObject, fragmentShader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -59;
}
glLinkProgram ( programObject );
error = glGetError();
if (error != GL_NO_ERROR) {
return -60;
}
glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
error = glGetError();
if (error != GL_NO_ERROR) {
return -61;
}
if ( !linked ) {
GLint infoLen = 0;
glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
error = glGetError();
if (error != GL_NO_ERROR) {
return -62;
}
if ( infoLen > 1 ) {
char *infoLog = malloc ( sizeof ( char ) * infoLen );
glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
error = glGetError();
if (error != GL_NO_ERROR) {
return -63;
}
free ( infoLog );
}
glDeleteProgram ( programObject );
error = glGetError();
if (error != GL_NO_ERROR) {
return -64;
}
return -2;
}
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
error = glGetError();
if (error != GL_NO_ERROR) {
return -65;
}
return 0;
}
int on_draw_frame() {
GLenum error;
GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
glViewport ( 0, 0, 200, 200 );
error = glGetError();
if (error != GL_NO_ERROR) {
return -66;
}
glClear ( GL_COLOR_BUFFER_BIT );
error = glGetError();
if (error != GL_NO_ERROR) {
return -67;
}
glUseProgram ( programObject );
error = glGetError();
if (error != GL_NO_ERROR) {
return -68;
}
glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
error = glGetError();
if (error != GL_NO_ERROR) {
return -69;
}
glEnableVertexAttribArray ( 0 );
error = glGetError();
if (error != GL_NO_ERROR) {
return -70;
}
glDrawArrays ( GL_TRIANGLES, 0, 3 );
error = glGetError();
if (error != GL_NO_ERROR) {
return -71;
}
return 0;
}
作为参考,这里是挂接到此的 Java 代码:
package com.example.spike_opengl;
import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;
import android.util.Log;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
public final class OpenGLRenderer implements Runnable {
private static final String LOG_TAG = "OpenGL.Worker";
protected final SurfaceTexture texture;
private EGL10 egl;
private EGLDisplay eglDisplay;
private EGLContext eglContext;
private EGLSurface eglSurface;
private boolean running;
private Worker worker;
public OpenGLRenderer(SurfaceTexture texture, Worker worker) {
this.texture = texture;
this.running = true;
this.worker = worker;
Thread thread = new Thread(this);
thread.start();
}
@Override
public void run() {
initGL();
int initResult = worker.onCreate();
if (initResult != 0) {
Log.d(LOG_TAG, "OpenGL init FAILED with code" + initResult + ".");
} else {
Log.d(LOG_TAG, "OpenGL init OK.");
}
while (running) {
long loopStart = System.currentTimeMillis();
int drawResult = worker.onDraw();
if (drawResult != 0) {
Log.d(LOG_TAG, "OpenGL draw FAILED with code" + drawResult + ".");
} else {
if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) {
Log.d(LOG_TAG, String.valueOf(egl.eglGetError()));
}
}
long waitDelta = 16 - (System.currentTimeMillis() - loopStart);
if (waitDelta > 0) {
try {
Thread.sleep(waitDelta);
} catch (InterruptedException e) {
}
}
}
deinitGL();
}
private void initGL() {
egl = (EGL10) EGLContext.getEGL();
eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
int[] version = new int[2];
if (!egl.eglInitialize(eglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
EGLConfig eglConfig = chooseEglConfig();
eglContext = createContext(egl, eglDisplay, eglConfig);
eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, texture, null);
if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("GL Error: " + GLUtils.getEGLErrorString(egl.eglGetError()));
}
if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
throw new RuntimeException("GL make current error: " + GLUtils.getEGLErrorString(egl.eglGetError()));
}
}
private void deinitGL() {
egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl.eglDestroySurface(eglDisplay, eglSurface);
egl.eglDestroyContext(eglDisplay, eglContext);
egl.eglTerminate(eglDisplay);
Log.d(LOG_TAG, "OpenGL deinit OK.");
}
private EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
int[] attribList = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
}
private EGLConfig chooseEglConfig() {
int[] configsCount = new int[1];
EGLConfig[] configs = new EGLConfig[1];
int[] configSpec = getConfig();
if (!egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, configsCount)) {
throw new IllegalArgumentException("Failed to choose config: " + GLUtils.getEGLErrorString(egl.eglGetError()));
} else if (configsCount[0] > 0) {
return configs[0];
}
return null;
}
private int[] getConfig() {
return new int[]{
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_STENCIL_SIZE, 0,
EGL10.EGL_SAMPLE_BUFFERS, 1,
EGL10.EGL_SAMPLES, 4,
EGL10.EGL_NONE
};
}
@Override
protected void finalize() throws Throwable {
super.finalize();
running = false;
}
public void onDispose() {
running = false;
}
public interface Worker {
int onCreate();
int onDraw();
}
}
谁能告诉我哪里做错了?
变量programObject
被声明了两次。
在全局范围内声明一次:
GLuint programObject;
第2次在函数中声明on_surface_created
:
int on_surface_created() {
// ...
GLuint programObject;
// ...
programObject = glCreateProgram ( );
// ...
}
虽然设置了局部变量,但永远不会设置全局范围内的变量。这导致着色器程序未作为当前渲染状态的一部分安装,在 "on_draw frame":
int on_draw_frame() {
// ...
glUseProgram ( programObject );
// ...
}
只需删除on_surface_created
中的局部变量programObject
即可解决问题。
我正在尝试通过渲染一个简单的三角形开始使用 OpenGL ES。
我使用 Android 和 Java 代码完成所有 EGL 初始化,然后 JNI 调用以便我可以使用 C 进行实际渲染。我已经通过简单地在 glClearColor
命令中更改颜色,然后调用 glClear
(然后会出现正确的颜色)来验证所有内容都已正确连接。但是,当我尝试下面的代码时,什么也没有出现,我也不知道为什么。请原谅许多 glGetError
电话。我只是想确定没有调用失败,确实如此。
#include "gl_render.h"
#include "gl_wrapper.h"
#include <math.h>
GLuint programObject;
GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
GLuint shader;
GLint compiled;
GLenum error;
shader = glCreateShader ( type );
error = glGetError();
if (error != GL_NO_ERROR) {
return -50;
}
glShaderSource ( shader, 1, &shaderSrc, NULL );
error = glGetError();
if (error != GL_NO_ERROR) {
return -51;
}
glCompileShader ( shader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -52;
}
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
error = glGetError();
if (error != GL_NO_ERROR) {
return -53;
}
if ( !compiled ) {
GLint infoLen = 0;
glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
error = glGetError();
if (error != GL_NO_ERROR) {
return -54;
}
if ( infoLen > 1 ) {
char *infoLog = malloc ( sizeof ( char ) * infoLen );
glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
error = glGetError();
if (error != GL_NO_ERROR) {
return -55;
}
free ( infoLog );
}
glDeleteShader ( shader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -56;
}
return -2;
}
return shader;
}
int on_surface_created() {
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";
GLuint vertexShader;
GLuint fragmentShader;
GLuint programObject;
GLint linked;
GLenum error;
vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
if (vertexShader < 0) {
return vertexShader;
}
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
if (fragmentShader < 0) {
return fragmentShader;
}
programObject = glCreateProgram ( );
error = glGetError();
if (error != GL_NO_ERROR) {
return -57;
}
glAttachShader ( programObject, vertexShader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -58;
}
glAttachShader ( programObject, fragmentShader );
error = glGetError();
if (error != GL_NO_ERROR) {
return -59;
}
glLinkProgram ( programObject );
error = glGetError();
if (error != GL_NO_ERROR) {
return -60;
}
glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
error = glGetError();
if (error != GL_NO_ERROR) {
return -61;
}
if ( !linked ) {
GLint infoLen = 0;
glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
error = glGetError();
if (error != GL_NO_ERROR) {
return -62;
}
if ( infoLen > 1 ) {
char *infoLog = malloc ( sizeof ( char ) * infoLen );
glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
error = glGetError();
if (error != GL_NO_ERROR) {
return -63;
}
free ( infoLog );
}
glDeleteProgram ( programObject );
error = glGetError();
if (error != GL_NO_ERROR) {
return -64;
}
return -2;
}
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
error = glGetError();
if (error != GL_NO_ERROR) {
return -65;
}
return 0;
}
int on_draw_frame() {
GLenum error;
GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
glViewport ( 0, 0, 200, 200 );
error = glGetError();
if (error != GL_NO_ERROR) {
return -66;
}
glClear ( GL_COLOR_BUFFER_BIT );
error = glGetError();
if (error != GL_NO_ERROR) {
return -67;
}
glUseProgram ( programObject );
error = glGetError();
if (error != GL_NO_ERROR) {
return -68;
}
glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
error = glGetError();
if (error != GL_NO_ERROR) {
return -69;
}
glEnableVertexAttribArray ( 0 );
error = glGetError();
if (error != GL_NO_ERROR) {
return -70;
}
glDrawArrays ( GL_TRIANGLES, 0, 3 );
error = glGetError();
if (error != GL_NO_ERROR) {
return -71;
}
return 0;
}
作为参考,这里是挂接到此的 Java 代码:
package com.example.spike_opengl;
import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;
import android.util.Log;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
public final class OpenGLRenderer implements Runnable {
private static final String LOG_TAG = "OpenGL.Worker";
protected final SurfaceTexture texture;
private EGL10 egl;
private EGLDisplay eglDisplay;
private EGLContext eglContext;
private EGLSurface eglSurface;
private boolean running;
private Worker worker;
public OpenGLRenderer(SurfaceTexture texture, Worker worker) {
this.texture = texture;
this.running = true;
this.worker = worker;
Thread thread = new Thread(this);
thread.start();
}
@Override
public void run() {
initGL();
int initResult = worker.onCreate();
if (initResult != 0) {
Log.d(LOG_TAG, "OpenGL init FAILED with code" + initResult + ".");
} else {
Log.d(LOG_TAG, "OpenGL init OK.");
}
while (running) {
long loopStart = System.currentTimeMillis();
int drawResult = worker.onDraw();
if (drawResult != 0) {
Log.d(LOG_TAG, "OpenGL draw FAILED with code" + drawResult + ".");
} else {
if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) {
Log.d(LOG_TAG, String.valueOf(egl.eglGetError()));
}
}
long waitDelta = 16 - (System.currentTimeMillis() - loopStart);
if (waitDelta > 0) {
try {
Thread.sleep(waitDelta);
} catch (InterruptedException e) {
}
}
}
deinitGL();
}
private void initGL() {
egl = (EGL10) EGLContext.getEGL();
eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
int[] version = new int[2];
if (!egl.eglInitialize(eglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
EGLConfig eglConfig = chooseEglConfig();
eglContext = createContext(egl, eglDisplay, eglConfig);
eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, texture, null);
if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("GL Error: " + GLUtils.getEGLErrorString(egl.eglGetError()));
}
if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
throw new RuntimeException("GL make current error: " + GLUtils.getEGLErrorString(egl.eglGetError()));
}
}
private void deinitGL() {
egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl.eglDestroySurface(eglDisplay, eglSurface);
egl.eglDestroyContext(eglDisplay, eglContext);
egl.eglTerminate(eglDisplay);
Log.d(LOG_TAG, "OpenGL deinit OK.");
}
private EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
int[] attribList = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
}
private EGLConfig chooseEglConfig() {
int[] configsCount = new int[1];
EGLConfig[] configs = new EGLConfig[1];
int[] configSpec = getConfig();
if (!egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, configsCount)) {
throw new IllegalArgumentException("Failed to choose config: " + GLUtils.getEGLErrorString(egl.eglGetError()));
} else if (configsCount[0] > 0) {
return configs[0];
}
return null;
}
private int[] getConfig() {
return new int[]{
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_STENCIL_SIZE, 0,
EGL10.EGL_SAMPLE_BUFFERS, 1,
EGL10.EGL_SAMPLES, 4,
EGL10.EGL_NONE
};
}
@Override
protected void finalize() throws Throwable {
super.finalize();
running = false;
}
public void onDispose() {
running = false;
}
public interface Worker {
int onCreate();
int onDraw();
}
}
谁能告诉我哪里做错了?
变量programObject
被声明了两次。
在全局范围内声明一次:
GLuint programObject;
第2次在函数中声明on_surface_created
:
int on_surface_created() {
// ...
GLuint programObject;
// ...
programObject = glCreateProgram ( );
// ...
}
虽然设置了局部变量,但永远不会设置全局范围内的变量。这导致着色器程序未作为当前渲染状态的一部分安装,在 "on_draw frame":
int on_draw_frame() {
// ...
glUseProgram ( programObject );
// ...
}
只需删除on_surface_created
中的局部变量programObject
即可解决问题。