Невозможно отобразить простой треугольник в OpenGL ES - PullRequest
1 голос
/ 11 июля 2019

Я пытаюсь начать работу с 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();
    }
}

Может кто-нибудьскажите, где я ошибся?

1 Ответ

1 голос
/ 12 июля 2019

Переменная programObject объявляется дважды.

Один раз он объявлен в глобальной области видимости:

GLuint programObject;

Второй раз, когда она объявлена ​​в функции on_surface_created:

int on_surface_created() {

    // ...

    GLuint programObject;

    // ...

    programObject = glCreateProgram ( );

    // ...
}

Пока локальная переменная установлена, переменная в глобальной области видимости никогда не устанавливается. Это приводит к тому, что шейдерная программа не устанавливается как часть текущего состояния рендеринга в «on_draw frame»:

int on_draw_frame() {

    // ...

    glUseProgram ( programObject );

    // ...
}

Просто удалите локальную переменную programObject в on_surface_created, чтобы решить проблему.

...