为什么我的OpenGL"你好世界"渲染?

时间:2014-05-28 20:00:31

标签: groovy lwjgl vbo opengl-3 vao

我已经在墙上撞了两天了。我试图提取最简单的OpenGL Core~2.0-3.2绘图序列,以便我可以构建代码并真正理解API。我遇到的问题是,这些教程似乎从来没有为他们正在使用的OpenGL版本提供有用的标签,而且纯粹是靠运气,我发生了关于如何均衡的文档从我的上下文中请求特定版本。

我确定我现在启用了3.2核心,因为即时模式绘制会导致错误(这是一件好事!我想立即离开模式!),我已经尝试过剥离任何花哨的东西,如坐标变换或三角形缠绕,可能会搞砸我的显示器。问题是,我无法在屏幕上显示任何内容。

在此程序的先前迭代中,我确实设法在屏幕上有时使用随机坐标获得白色三角形,但在我看来,顶点并未正确设置,奇怪的位组合会产生奇怪的结果。符号在三角形出现的位置无关紧要 - 因此我的理论是顶点信息没有被正确地传递到顶点着色器,或者着色器正在破坏它。问题是,我正在查看我能找到的所有结果和日志,并且着色器可以很好地编译和链接。

我将在下面提供链接和代码,但除了在屏幕上获取三角形之外我还想知道,我可以让着色器程序将文本和/或诊断值吐出到其shaderInfoLog吗?这将极大地简化调试过程。

我咨询的各种教程都是......

  

http://arcsynthesis.org/gltut/Basics/Tutorial%2001.html   http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Introduction   https://en.wikipedia.org/wiki/Vertex_Buffer_Object   http://www.opengl.org/wiki/Tutorial2:_VAOs,_VBOs,_Vertex_and_Fragment_Shaders_(C_/_SDL)   http://antongerdelan.net/opengl/hellotriangle.html   http://lwjgl.org/wiki/index.php?title=The_Quad_with_DrawArrays   http://lwjgl.org/wiki/index.php?title=Using_Vertex_Buffer_Objects_(VBO)   http://www.opengl.org/wiki/Vertex_Rendering

     

http://www.opengl.org/wiki/Layout_Qualifier_(GLSL)(不在   提供代码,但我尝试的是#version 420 with layout   限定符0(in_Position)和1(in_Color))

代码(LWJGL + Groovy)

package com.thoughtcomplex.gwdg.core

import org.lwjgl.input.Keyboard
import org.lwjgl.opengl.ContextAttribs
import org.lwjgl.opengl.Display
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL15
import org.lwjgl.opengl.GL20
import org.lwjgl.opengl.GL30
import org.lwjgl.opengl.PixelFormat
import org.lwjgl.util.glu.GLU

import java.nio.ByteBuffer
import java.nio.FloatBuffer

/**
 * Created by Falkreon on 5/21/2014.
 */
class GwDG {

    static final String vertexShader = """
        #version 150
        in vec2 in_Position;
        in vec3 in_Color;

        smooth out vec3 ex_Color;
        void main(void) {
            gl_Position = vec4(in_Position,0.0,1.0);
            ex_Color = in_Color;
        }

    """;

    static final String fragmentShader = """
        #version 150

        smooth in vec3 ex_Color;
        out vec4 fragColor;

        void main(void) {
            //fragColor = vec4(ex_Color, 1.0);
            fragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    """;

    static int vaoHandle = -1;
    static int vboHandle = -1;
    protected static int colorHandle = -1;
    static int vertexShaderHandle = -1;
    static int fragmentShaderHandle = -1;
    static int shaderProgram = -1;

    protected static FloatBuffer vboBuffer = ByteBuffer.allocateDirect(6*4).asFloatBuffer();
    protected static FloatBuffer colorBuffer = ByteBuffer.allocateDirect(9*4).asFloatBuffer();


    public static void main(String[] args) {
        //Quick and dirty hack to get something on the screen; this *works* for immediate mode drawing
        System.setProperty("org.lwjgl.librarypath", "C:\\Users\\Falkreon\\IdeaProjects\\GwDG\\native\\windows");

        Display.setTitle("Test");
        ContextAttribs attribs = new ContextAttribs();
        attribs.profileCompatibility = false;
        attribs.profileCore = true;
        attribs.majorVersion = 3;
        attribs.minorVersion = 2;
        Display.create( new PixelFormat().withDepthBits(24).withSamples(4).withSRGB(true), attribs );

        //Kill any possible winding error
        GL11.glDisable(GL11.GL_CULL_FACE);

        vaoHandle = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vaoHandle);

        reportErrors("VERTEX_ARRAY");

        vboHandle = GL15.glGenBuffers();
        colorHandle = GL15.glGenBuffers();

        vertexShaderHandle = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
        fragmentShaderHandle = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
        reportErrors("CREATE_SHADER");

        GL20.glShaderSource( vertexShaderHandle, vertexShader );
        GL20.glShaderSource( fragmentShaderHandle, fragmentShader );

        GL20.glCompileShader( vertexShaderHandle );
        String vertexResult = GL20.glGetShaderInfoLog( vertexShaderHandle, 700 );
        if (!vertexResult.isEmpty()) System.out.println("Vertex result: "+vertexResult);

        GL20.glCompileShader( fragmentShaderHandle );
        String fragmentResult = GL20.glGetShaderInfoLog( fragmentShaderHandle, 700 );
        if (!fragmentResult.isEmpty()) System.out.println("Fragment result: "+fragmentResult);

        shaderProgram = GL20.glCreateProgram();
        reportErrors("CREATE_PROGRAM");
        GL20.glAttachShader( shaderProgram, vertexShaderHandle );
        GL20.glAttachShader( shaderProgram, fragmentShaderHandle );
        GL20.glLinkProgram(shaderProgram);
        int result = GL20.glGetProgrami( shaderProgram, GL20.GL_LINK_STATUS );
        if (result!=1) System.out.println("LINK STATUS: "+result);
        reportErrors("SHADER_LINK");

        //Attribs
        int vertexParamID = GL20.glGetAttribLocation(shaderProgram, "in_Position");
        int colorParamID = GL20.glGetAttribLocation(shaderProgram, "in_Color");

        while (!Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {

            //Intentional flicker so I can see if something I did freezes or lags the program
            GL11.glClearColor(Math.random()/6 as Float, Math.random()/8 as Float, (Math.random()/8)+0.4 as Float, 1.0f);
            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT );

            float[] coords = [
                 0.0f,  0.8f,
                -0.8f, -0.8f,
                 0.8f, -0.8f
            ];

            vboBuffer.clear();
            coords.each {
                vboBuffer.put it;
            }
            vboBuffer.flip();

            float[] colors = [
                1.0f, 0.0f, 0.0f,
                0.0f, 1.0f, 0.0f,
                0.0f, 0.0f, 1.0f
            ];

            colorBuffer.clear();
            colors.each {
                colorBuffer.put it;
            }
            colorBuffer.flip();

            //System.out.println(dump(vboBuffer));
            reportErrors("SETUP_TRIANGLE_DATA");

            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
            GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vboBuffer, GL15.GL_STATIC_DRAW);
            reportErrors("BIND_VBO_AND_FILL_DATA");

            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorHandle);
            GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colorBuffer, GL15.GL_STATIC_DRAW);
            reportErrors("BIND_COLOR_BUFFER_AND_FILL_DATA");

            GL20.glEnableVertexAttribArray( vertexParamID );
            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
            GL20.glVertexAttribPointer(
                    vertexParamID, 2, GL11.GL_FLOAT, false, 0, 0
            );
            GL20.glEnableVertexAttribArray( colorParamID );
            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorHandle);
            GL20.glVertexAttribPointer(
                    colorParamID, 3, GL11.GL_FLOAT, false, 0, 0
            );

            reportErrors("VERTEX_ATTRIB_POINTERS");

            GL20.glUseProgram( shaderProgram );
            GL11.glDrawArrays( GL11.GL_TRIANGLES, 0, 3 );

            reportErrors("POST_RENDER");

            Display.update(true);
            Thread.sleep(12);
            Keyboard.poll();
        }
        Display.destroy();
    }


    private static String dump(FloatBuffer f) {
        String result = "[ ";
        f.position(0);
        //f.rewind();
        for(it in 0..<f.limit()) {
            result+= f.get(it);
            if (it!=f.limit()-1) result+=", ";
        }
        result +=" ]";
        f.position(0);
        result;
    }

    private static void reportErrors(String prefix) {
        int err = GL11.glGetError();
        if (err!=0) System.out.println("["+prefix + "]: "+GLU.gluErrorString(err)+" ("+err+")");
    }
}

不重要,但该卡是ATI Radeon HD 8550G(A8 APU的一部分),支持GL4。

我会根据要求更新更多信息,我只是不知道还有什么可能有助于诊断。

修改:我已更新上述代码,以反映Reto Koradi建议的更改。我还得到了一个使用备用顶点声明运行的代码变体:

float[] coords = [
    0.0f,  0.8f,
    -0.8f, -0.8f,
    Math.random(), Math.random(),
    //0.8f, -0.8f,
];

这实际上会在屏幕上产生某些光栅化的东西,但它完全不是我所期望的。它不是简单地重新定位右下角(右上角),而是在任何东西之间翻转,完全是白色,以及以下两种形状:

Strange Shape 1 Strange shape 2

如果我替换第二个或第三个顶点,则会发生这种情况。如果我替换第一个顶点,屏幕上不会显示任何内容。因此,为了检查我关于哪个顶点实际出现在窗口中心的假设,我尝试了以下内容:

static final String vertexShader = """
    #version 150
    in vec2 in_Position;
    in vec3 in_Color;

    smooth out vec3 ex_Color;
    void main(void) {
        gl_Position = vec4(in_Position,0.0,1.0);
        ex_Color = vec3(1.0, 1.0, 1.0);
        if (gl_VertexID==0) ex_Color = vec3(1.0, 0.0, 0.0);
        if (gl_VertexID==1) ex_Color = vec3(0.0, 1.0, 0.0);
        if (gl_VertexID==2) ex_Color = vec3(0.0, 0.0, 1.0);
        //ex_Color = in_Color;
    }

""";

static final String fragmentShader = """
    #version 150

    smooth in vec3 ex_Color;
    out vec4 fragColor;

    void main(void) {
        fragColor = vec4(ex_Color, 1.0);
        //fragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
""";

简单,对吧?中间的顶点应该是第一个,#34;红色&#34;顶点,因为它是非可选的顶点,没有它我似乎无法在屏幕上绘制任何东西。事实并非如此。半屏块总是按预期变红,但是面向左的三角形总是我替换的任何顶点的颜色 - 替换第二个顶点使其变为绿色,替换第三个顶点使其变为蓝色。它看起来似乎都是&#34; -0.8,-0.8&#34;和&#34; 0.8,-0.8&#34;离屏幕太远以至于可见的三角形部分实际上是无限细线。但我不认为这是由于变换造成的 - 这更像是对齐问题,其任意阈值约为0.9,会将坐标射入远地。也许顶点缓冲区中的值的有效位数可能是in_Position值的指数。

为了继续向下钻取,我增加了硬编码GLSL的数量以完全忽略缓冲区 -

static final String vertexShader = """
    #version 150
    in vec2 in_Position;
    in vec3 in_Color;

    smooth out vec3 ex_Color;
    void main(void) {
        gl_Position = vec4(in_Position,0.0,1.0);
        ex_Color = vec3(1.0, 1.0, 1.0);
        if (gl_VertexID==0) {
            ex_Color = vec3(1.0, 0.0, 0.0);
            gl_Position = vec4(0.0, 0.8, 0.0, 1.0);
        }
        if (gl_VertexID==1) {
            ex_Color = vec3(0.0, 1.0, 0.0);
            gl_Position = vec4(-0.8, -0.8, 0.0, 1.0);
        }
        if (gl_VertexID==2) {
            ex_Color = vec3(0.0, 0.0, 1.0);
            gl_Position = vec4(0.8, -0.8, 0.0, 1.0);
        }
        //ex_Color = in_Color;
    }

""";

这会产生所需的结果,一个漂亮的大三角形,每个顶点都有不同的颜色。显然我想从顶点缓冲区中获取相同的三角形,但它是一个非常好的开始 - 有两个顶点我至少可以告诉最终顶点射出的方向。在第一个顶点的情况下,它&& #39;肯定是 down

我还想出了如何在配置文件中启用调试模式,以及它在我身上随地吐出颜色缓冲区错误。好!这是一个开始。现在为什么它不会抛出大量的VBO错误?

2 个答案:

答案 0 :(得分:1)

您的代码与核心配置文件不兼容。你的reportErrors()实际应该开火。在核心配置文件中,您必须使用顶点数组对象(VAO)进行顶点设置。在设置顶点状态之前,您必须使用glGenVertexArrays()生成VAO,并将其与`glBindVertexArray()绑定。

也不推荐在片段着色器中使用gl_FragColor。您需要在核心配置文件中声明自己的out变量,例如:

out vec4 FragColor;
...
    FragColor = ...

答案 1 :(得分:0)

答案终于来自灵感 http://lwjgl.org/forum/index.php?topic=5171.0

这是相当错误的,所以让我解释一下最终是对的。我的开发环境是英特尔芯片上的java。所有java都以big-endian运行。我感到很困惑的是,我的花车的指数似乎在意义上消失了,但是看到这篇文章它最终让我感到震惊 - 如果翻转字符串就会发生最简单的方式! FloatBuffers仍然是大端的。除了本机字节顺序之外,OpenGL运行的可能性几乎为零。我咨询的lwjgl资源都没有提到这个怪癖,或者我错过了它们。

此程序中ByteBuffers的正确初始化程序为:

protected static FloatBuffer vboBuffer = ByteBuffer.allocateDirect(6*4).order( ByteOrder.nativeOrder(  ) ).asFloatBuffer();
protected static FloatBuffer colorBuffer = ByteBuffer.allocateDirect(9*4).order( ByteOrder.nativeOrder(  ) ).asFloatBuffer();

重要的部分是ByteOrder.nativeOrder()