1

I recently started learning OpenGL and I have been trying to write a program that displays a diamond on the screen using VAOs and VBOs with shaders. My code is mostly based on this tutorial: https://www.opengl.org/wiki/Tutorial2:_VAOs,_VBOs,_Vertex_and_Fragment_Shaders_%28C_/_SDL%29 and I also used the shaders from the tutorial. The diamond is supposed to be drawn using the color information from the vertex array object but instead it is just drawn in white. The shaders seem to be loading fine so I think it is a problem with my vertex and buffer array objects. Can someone please explain why my code is not working how I expected or show a clear example of how to render VAOs using colors from an array of color attributes.

package windows;

import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;

import shaders.ShaderControl2;

import com.jogamp.common.nio.Buffers;

public class Test4 implements GLEventListener{

ShaderControl2 sc;
FloatBuffer vertexPos, vertexCol;
IntBuffer vao, vbo; 
GLU glu = new GLU();

public static void main(String[] args){
    GLProfile glp = GLProfile.getDefault();
    GLCapabilities caps = new GLCapabilities(glp);
    GLCanvas canvas = new GLCanvas(caps);

    Test4 t = new Test4();

    canvas.addGLEventListener(t);

    Frame f = new Frame("TEST #4");
    f.setSize(400,400);
    f.add(canvas);
    f.setVisible(true);
    f.addWindowListener(new WindowAdapter(){
        public void windowClosing(WindowEvent e){
            System.exit(0);
        }
    });
}


@Override
public void display(GLAutoDrawable drawable) {
    GL2 gl = drawable.getGL().getGL2();
    gl.glClearColor(0, 0, 0, 1f);
    gl.glClear(GL2.GL_COLOR_BUFFER_BIT);

    sc.useShader(gl);

    gl.glBindVertexArray(vao.get(0));
    gl.glEnableVertexAttribArray(0);
    gl.glEnableVertexAttribArray(1);
    gl.glDrawArrays(GL2.GL_LINE_LOOP, 0 , 4);

    sc.dontUseShader(gl);

}

@Override
public void dispose(GLAutoDrawable drawable) {
    // TODO Auto-generated method stub

}

@Override
public void init(GLAutoDrawable drawable) {
    GL2 gl = drawable.getGL().getGL2();
    System.out.println(gl.glGetString(GL2.GL_VERSION));

    vertexPos = Buffers.newDirectFloatBuffer(8);
    vertexPos.put(new float[]{0f, 1f});
    vertexPos.put(new float[]{1f, 0f});
    vertexPos.put(new float[]{0f, -1f});
    vertexPos.put(new float[]{-1f, 0});
    vertexPos.flip();

    vertexCol = Buffers.newDirectFloatBuffer(12);
    vertexCol.put(new float[]{1f, 0f, 0f});
    vertexCol.put(new float[]{0f, 1f, 0f});
    vertexCol.put(new float[]{0f, 0f, 1f});
    vertexCol.put(new float[]{1f, 1f, 1f});
    vertexCol.flip();

    vao = IntBuffer.allocate(1);
    vbo = IntBuffer.allocate(2);

    gl.glGenVertexArrays(1, vao);
    gl.glGenBuffers(2, vbo);

    int bytesPerFloat = Float.SIZE/Byte.SIZE;

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER,  vbo.get(0));
    gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertexPos.capacity() * bytesPerFloat, vertexPos, GL2.GL_STATIC_DRAW);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo.get(1));
    gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertexCol.capacity() * bytesPerFloat, vertexCol, GL2.GL_STATIC_DRAW);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);

    gl.glBindVertexArray(vao.get());
    gl.glEnableVertexAttribArray(0);
    gl.glEnableVertexAttribArray(1);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo.get(0));
    gl.glVertexAttribPointer(0, 2, GL2.GL_FLOAT, false, 0, 0);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo.get(1));
    gl.glVertexAttribPointer(1, 3, GL2.GL_FLOAT, false, 0, 0);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);


    sc = new ShaderControl2();
    sc.vSrc = sc.loadShader("v.txt");
    sc.fSrc = sc.loadShader("f.txt");

}

@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width,
        int height) {

}

}

ShaderControl2 code:

package shaders;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.media.opengl.*;

public class ShaderControl2 {

private int vertexShaderProg, fragmentShaderProg, shaderProg;
public String[] vSrc, fSrc;

public String[] loadShader(String sFile){
    String line = new String();
    StringBuilder fileContent = new StringBuilder();

    try{
        InputStream is = getClass().getResourceAsStream(sFile);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        while((line = br.readLine()) != null){
            fileContent.append(line + "\n");
        }
        is.close();
    } catch(Exception e){
        e.printStackTrace();
    }
    System.out.println("Shader file content:\n" + fileContent);
    return new String[]{fileContent.toString()};
}

public void attachShader(GL2 gl){
    IntBuffer isCompiledVS = IntBuffer.allocate(1), isCompiledFS = IntBuffer.allocate(1), isLinked = IntBuffer.allocate(1);
    IntBuffer vLogLength = IntBuffer.allocate(1), fLogLength = IntBuffer.allocate(1), linkLogLength = IntBuffer.allocate(1);
    ByteBuffer vertexInfoLog, fragmentInfoLog, linkInfoLog;
    int size;

    vertexShaderProg = gl.glCreateShader(GL2.GL_VERTEX_SHADER);

    gl.glShaderSource(vertexShaderProg, 1, vSrc, null);
    gl.glCompileShader(vertexShaderProg);

    gl.glGetShaderiv(vertexShaderProg, GL2.GL_COMPILE_STATUS, isCompiledVS);
    if(isCompiledVS.get(0) == 0){
        System.out.println("Failed to compile vertexShaderProg");

        gl.glGetShaderiv(vertexShaderProg, GL2.GL_INFO_LOG_LENGTH, vLogLength); 
        size = vLogLength.get(0);
        vertexInfoLog = ByteBuffer.allocate(size);
        gl.glGetShaderInfoLog(vertexShaderProg, size, vLogLength, vertexInfoLog);

        for(byte b : vertexInfoLog.array()){
            System.err.print((char)b);
        }
    }

    fragmentShaderProg = gl.glCreateShader(GL2.GL_VERTEX_SHADER);

    gl.glShaderSource(fragmentShaderProg, 1, vSrc, null);
    gl.glCompileShader(fragmentShaderProg);

    gl.glGetShaderiv(fragmentShaderProg, GL2.GL_COMPILE_STATUS, isCompiledFS);
    if(isCompiledFS.get(0) == 0){
        System.out.println("Failed to compile fragmentShaderProg");

        gl.glGetShaderiv(fragmentShaderProg, GL2.GL_INFO_LOG_LENGTH, fLogLength);   
        size = fLogLength.get(0);
        fragmentInfoLog = ByteBuffer.allocate(size);
        gl.glGetShaderInfoLog(fragmentShaderProg, size, fLogLength, fragmentInfoLog);

        for(byte b : fragmentInfoLog.array()){
            System.err.print((char)b);
        }

    }

    shaderProg = gl.glCreateProgram();
    gl.glAttachShader(shaderProg, vertexShaderProg);
    gl.glAttachShader(shaderProg, fragmentShaderProg);

    gl.glBindAttribLocation(shaderProg, 0, "in_Position");
    gl.glBindAttribLocation(shaderProg, 1, "in_Color");

    gl.glLinkProgram(shaderProg);

    gl.glGetProgramiv(shaderProg, GL2.GL_LINK_STATUS, isLinked);
    if(isLinked.get(0) == 0){
        System.out.println("Failed to link shaderProg");

        gl.glGetShaderiv(shaderProg, GL2.GL_INFO_LOG_LENGTH, linkLogLength);
        size = linkLogLength.get(0);
        linkInfoLog = ByteBuffer.allocate(size);
        gl.glGetProgramInfoLog(shaderProg, size, linkLogLength, linkInfoLog);

        for(byte b : linkInfoLog.array()){
            System.err.print((char)b);
        }
    }       
}

public int useShader(GL2 gl){
    gl.glUseProgram(shaderProg);
    return shaderProg;
}

public void dontUseShader(GL2 gl){
    gl.glUseProgram(0);
}
}

Shader Code

f.txt:

#version 210
// It was expressed that some drivers required this next line to function properly
precision highp float;

in  vec3 ex_Color;
out vec4 gl_FragColor;

void main(void) {
    // Pass through our original color with full opacity.
    gl_FragColor = vec4(ex_Color,1.0);
}

v.txt:

#version 210
// in_Position was bound to attribute index 0 and in_Color was bound to attribute index 1
in  vec2 in_Position;
in  vec3 in_Color;

// We output the ex_Color variable to the next shader in the chain
out vec3 ex_Color;
void main(void) {
// Since we are using flat lines, our input only had two points: x and y.
// Set the Z coordinate to 0 and W coordinate to 1

gl_Position = vec4(in_Position.x, in_Position.y, 0.0, 1.0);

// GLSL allows shorthand use of vectors too, the following is also valid:
// gl_Position = vec4(in_Position, 0.0, 1.0);
// We're simply passing the color through unmodified

ex_Color = in_Color;
}
4

1 回答 1

0

您只看到白线的原因是根本没有使用着色器程序。

我看不到你在哪里调用附加着色器(你从不调用 sc.attachShader(gl),我在 init 方法的末尾添加了 sc.attachShader(gl)。

现在会出现很多错误。

在 attachshader 中,当您创建 fragmentShaderProg 时,您将其创建为 GL_VERTEX_SHADER,它应该是 GL_FRAGMENT_SHADER,并且在其下方发送顶点着色器的源以代替片段着色器。

GLSL语言的210版本不存在,改成130版本。GLSL版本的事情是它独立于OpenGL版本,https://github.com/mattdesl/lwjgl-basics/wiki/GLSL -版本

#version 130

现在添加到 init 方法的末尾

sc.attachShader(gl) 

和改变

fragmentShaderProg = gl.glCreateShader(GL2.GL_VERTEX_SHADER);
gl.glShaderSource(fragmentShaderProg, 1, vSrc, null);

为了

fragmentShaderProg = gl.glCreateShader(GL2.GL_FRAGMENT_SHADER);
gl.glShaderSource(fragmentShaderProg, 1, fSrc, null);

现在它可以工作了。

工作成果

于 2015-01-07T16:23:07.903 回答