为此,我已经把头撞在墙上两天了。我正在尝试提取最简单的 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,布局限定符为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+")");
}
}
这并不重要,但该卡是支持 GL4 的 ATI Radeon HD 8550G(A8 APU 的一部分)。
我会根据要求更新更多信息,我只是不知道还有什么可能有助于诊断。
编辑:我更新了上面的代码以反映 Reto Koradi 建议的更改。我还有一个使用备用顶点声明运行的代码变体:
float[] coords = [
0.0f, 0.8f,
-0.8f, -0.8f,
Math.random(), Math.random(),
//0.8f, -0.8f,
];
这确实会在屏幕上产生光栅化的东西,但这根本不是我所期望的。它不是简单地重新定位右下角(右上角?)点,而是在什么都没有、完全白色和以下两种形状之间翻转:
如果我替换第二个或第三个顶点,就会发生这种情况。如果我替换第一个顶点,屏幕上不会出现任何内容。因此,为了检查我关于哪个顶点实际出现在窗口中心的假设,我尝试了以下操作:
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);
}
""";
很简单,对吧?中间的顶点可能应该是第一个“红色”顶点,因为它是非可选顶点,没有它我似乎无法在屏幕上绘制任何东西。实际上并非如此。半屏块总是像预期的那样是红色的,但是朝左的三角形总是我替换的任何顶点的颜色——替换第二个顶点使其变为绿色,替换第三个顶点使其变为蓝色。看起来“-0.8,-0.8”和“0.8,-0.8”都离屏幕太远了,可见的三角形部分实际上是一条无限细的线。但我不认为这是由于变换 - 这更像是一个对齐问题,其任意阈值约为 0.9,将坐标发射到远地。
为了继续深入研究,我增加了硬编码 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;
}
""";
这会产生所需的结果,一个漂亮的大三角形,每个顶点都有不同的颜色。显然,我想从顶点缓冲区中取出同一个三角形,但这是一个非常好的开始 - 有两个顶点,我至少可以判断最终顶点射向的方向。对于第一个顶点,它肯定是down。
我还想出了如何在配置文件中启用调试模式,它向我吐出颜色缓冲区错误。好的!这是一个开始。现在为什么不抛出大量的 VBO 错误?