Недавно я начал изучать OpenGL, и я пытался написать программу, которая отображает бриллиант на экране с использованием VAO и VBOs с шейдерами. Мой код в основном основан на этом учебнике: https://www.opengl.org/wiki/Tutorial2:_VAOs,_VBOs,_Vertex_and_Fragment_Shaders_%28C_/_SDL%29 и я также использовал шейдеры из учебника. Предполагается, что алмаз должен быть нарисован с использованием информации о цвете из объекта массива вершин, но вместо этого он просто нарисован в белом цвете. Похоже, что шейдеры загружаются, поэтому я думаю, что это проблема с моими объектами вершинного и буферного массивов. Может кто-то объяснить, почему мой код не работает, как я ожидал, или показать ясный пример того, как визуализировать VAO, используя цвета из массива атрибутов цвета.VAO не отображает цвет с шейдерами
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 код:
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 Код
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;
}
Вы уверены, что атрибут цвета находится в местоположении 1? Вы должны установить это либо с квалификатором макета местоположения в вершинном шейдерном коде, либо с вызовом 'glBindAttribLocation() перед связыванием шейдерной программы. –
Да, сразу после того, как я прикрепил два шейдера и прямо перед тем, как связать программу, я установил местоположение с помощью glBindAttribLocation (shaderProg, 0, "in_Position") и gl.glBindAttribLocation (shaderProg, 1, "in_Color") в методе attachShaders ShaderControl2 – Frosty
Для меня этот код выглядит отлично. Можете ли вы добавить шейдеры?Два дополнительных совета: во-первых: повторное использование атрибутов вершин на дисплее не требуется, поскольку оно уже хранится в vao. Во-вторых: я бы отвязал vao после инициализации, чтобы последующие вызовы повлияли на его состояние. – BDL