Painter 的方法在 OpenGL 4 中失败了吗?
Painter's method failing with OpenGL 4?
我会留下这个问题作为对其他人的警示故事。简短的回答是 GLSL 中的统一变量需要在 glUseProgram 之后绑定到当前程序。他们不会自己神奇地找到着色器。我加了一个
glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, glm::value_ptr(投影));
在每个 glUseProgram 和事情改进之后。
~
我正在绘制平面图。这是一个正射投影。在渲染回调中,首先我用一个图案绘制地板 (z=0),现在我用那个图案填充整个屏幕。都好。现在是时候粉刷墙壁了,它只是许多切成三角形的细长方形,因为显然画粗线应该是这样。
最初我用一个片段着色器同时处理地板和墙壁。我会绘制地板三角形,为着色器设置一个标志,然后绘制瘦墙三角形。片段着色器通过使用不同的颜色来纪念旗帜,我满意地绘制了顶部的地板和墙壁。
但是随着我添加功能,我将在地板上绘制越来越多的东西,所以我决定将片段着色器分开 - 一个用于地板,一个用于墙壁,还有其他的用于其他特性。我为地板调用 glUSeProgram(),绘制我的三角形,然后调用 glUseProgram() [这里似乎是龙] 设置墙壁着色器并绘制墙壁(在 z=0.5,只是为了确定)。一切都以一种有趣的方式崩溃了:如果我注释掉第二个 glUseProgram 和相关的绘制,我可以看到地板。如果我放回第 2 个使用和绘制操作,我只会看到墙壁。如果我画墙但不操作墙着色器 (void main() {return;}),我什么也得不到。通过测试,我确定仅调用第二个 glUSeProgram() 就会造成损害。即使我没有画墙并且在那之后有一个无操作片段着色器,地板也不见了并且 window 是空白的。所以它不是离开 rails.
的墙片段着色器
我有一个疯狂的理论。我猜这都是异步的,第二个 UseProgram 会破坏第一个 UseProgram 正在进行的任何事情(也许还没有开始绘制?)如果那是真的,我需要某种方式说“好的,等待第一个程序到处完成”。如果那是错误的,我将完全不知所措,因为我没有看到任何迹象表明 glUSeProgram() 将彻底改变。
我哪里做错了?理论上我可以在一个片段着色器中做所有事情,但这将是巨大的,我知道你不需要那样做。
这是渲染回调中的代码; #if 01 仅表示我关闭和打开以尝试的东西。
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //start clean
mapData.selectShader(mapData.programDMFloor); //does glUseProgram (see below)
glEnableVertexAttribArray(0); //needed, no idea why?
glBindBuffer(GL_ARRAY_BUFFER, VBOS); //2 triangles (that for now cover the window)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); //indexed draw for these
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); //paint the window with the floor
glDisableVertexAttribArray(0); //needed, no idea why?
//If we stop here, we see the floor pattern as expected. But..!
#if 01
mapData.selectShader(mapData.programDMWall);
//The floor is now gone (or maybe never happened)
//this draws the walls
glEnableVertexAttribArray(0); //needed, don't know why
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //no indexed draw for these
glBindBuffer(GL_ARRAY_BUFFER, mapData.wallBuffer_); //Select a lot of skinny triangles
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
//std::cout << "Wall draw " << mapData.triangles_.size() * 3 << " floats from buf " << mapData.wallBuffer_ << '\n';
glDrawArrays(GL_TRIANGLES, 0, mapData.triangles_.size() * 3); //no indexed draw for this one
glDisableVertexAttribArray(0);
//we see the walls, but no floor!
#else
//we see the floor, and of course no walls.
//Need both!
#endif
glutSwapBuffers();
至于mapData.selectShader(),就是
void selectShader(GLuint ShaderProgram) //in Map::
{
glUseProgram(ShaderProgram);
//All the shaders should be sharing gWorld, so I probably don't need
// to set this over and over, since it's not going to change. But it needs
// to follow a glUseProgram so for now it's here. Needed each time?
gWorldLocation = glGetUniformLocation(ShaderProgram, "gWorld");
assert(gWorldLocation != 0xFFFFFFFF);
}
这实际上应该如何工作?
附录:墙的 .vs:
#version 430
//buffer indexes
#define BI_LIGHTS 0
#define BI_WALLS 1
#define BI_WALLWALK 2
#define BI_DOORS 3
#define BI_WALLINDEXES 4
layout (location = 0) in vec3 Position;
uniform mat4 gWorld;
layout (std430, binding=BI_WALLINDEXES) buffer wallIndexesSkip
{
unsigned int wallIndexes[];
};
out vec4 Color; //unused; the fragment shader calculates all colors
//but maybe we pass the initial floor texture here someday
flat out unsigned int wallIndex;
void main()
{
gl_Position = gWorld * vec4(Position, 1.0);
//We must the fragment shader which wall it should NOT use to
// occlude walls, otherwise the wall currently being drawing
// will be occluded by itself!
wallIndex = wallIndexes[gl_VertexID/9];
}
和带有声明的 .fs 的开头:
#version 430
#define BI_LIGHTS 0
#define BI_WALLS 1
#define BI_WALLWALK 2
#define BI_DOORS 3
#define BI_WALLINDEXES 4
#define AMB_NONE 0
#define AMB_SUNLIGHT 1
#define AMB_CLOUDY 2
#define AMB_RAIN 3
#define AMB_FOG 4
#define AMB_DIM 5
#define AMB_TEST 6
#define LIT_NONE 0
#define LIT_MAGICAL 1
#define LIT_FIRE 2
#define LIT_INFRAVISION 3
layout (std430, binding=BI_LIGHTS) buffer lights
{
unsigned int lightCount;
//12 bytes wasted in this packing
vec4 lightData[]; //x, y, radius, typeflag
};
layout (std430, binding=BI_WALLS) buffer walls
{
vec2 wp[];
};
layout (std430, binding=BI_WALLWALK) buffer wallRuns
{
// 0 this wall is ok
//>0 number to skip including this one
//0xffffffff marks end
unsigned int skipWalls[];
};
layout (std430, binding=BI_DOORS) buffer doors
{
unsigned int doorCount;
//12 bytes wasted in this packing
vec4 dp[]; //hinge x, hinge y, end x, end y
};
flat in unsigned int wallIndex;
in vec4 Color;
out vec4 FragColor;
我会留下这个问题作为对其他人的警示故事。简短的回答是 GLSL 中的统一变量需要在 glUseProgram 之后绑定到当前程序。他们不会自己神奇地找到着色器。我添加了一个 glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, glm::value_ptr(projection));在每个 glUseProgram 和事情改进之后。
感谢评论中的人们,他们在创纪录的时间内解决了这个问题。
我会留下这个问题作为对其他人的警示故事。简短的回答是 GLSL 中的统一变量需要在 glUseProgram 之后绑定到当前程序。他们不会自己神奇地找到着色器。我加了一个 glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, glm::value_ptr(投影)); 在每个 glUseProgram 和事情改进之后。
~
我正在绘制平面图。这是一个正射投影。在渲染回调中,首先我用一个图案绘制地板 (z=0),现在我用那个图案填充整个屏幕。都好。现在是时候粉刷墙壁了,它只是许多切成三角形的细长方形,因为显然画粗线应该是这样。
最初我用一个片段着色器同时处理地板和墙壁。我会绘制地板三角形,为着色器设置一个标志,然后绘制瘦墙三角形。片段着色器通过使用不同的颜色来纪念旗帜,我满意地绘制了顶部的地板和墙壁。
但是随着我添加功能,我将在地板上绘制越来越多的东西,所以我决定将片段着色器分开 - 一个用于地板,一个用于墙壁,还有其他的用于其他特性。我为地板调用 glUSeProgram(),绘制我的三角形,然后调用 glUseProgram() [这里似乎是龙] 设置墙壁着色器并绘制墙壁(在 z=0.5,只是为了确定)。一切都以一种有趣的方式崩溃了:如果我注释掉第二个 glUseProgram 和相关的绘制,我可以看到地板。如果我放回第 2 个使用和绘制操作,我只会看到墙壁。如果我画墙但不操作墙着色器 (void main() {return;}),我什么也得不到。通过测试,我确定仅调用第二个 glUSeProgram() 就会造成损害。即使我没有画墙并且在那之后有一个无操作片段着色器,地板也不见了并且 window 是空白的。所以它不是离开 rails.
的墙片段着色器我有一个疯狂的理论。我猜这都是异步的,第二个 UseProgram 会破坏第一个 UseProgram 正在进行的任何事情(也许还没有开始绘制?)如果那是真的,我需要某种方式说“好的,等待第一个程序到处完成”。如果那是错误的,我将完全不知所措,因为我没有看到任何迹象表明 glUSeProgram() 将彻底改变。
我哪里做错了?理论上我可以在一个片段着色器中做所有事情,但这将是巨大的,我知道你不需要那样做。
这是渲染回调中的代码; #if 01 仅表示我关闭和打开以尝试的东西。
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //start clean
mapData.selectShader(mapData.programDMFloor); //does glUseProgram (see below)
glEnableVertexAttribArray(0); //needed, no idea why?
glBindBuffer(GL_ARRAY_BUFFER, VBOS); //2 triangles (that for now cover the window)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); //indexed draw for these
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); //paint the window with the floor
glDisableVertexAttribArray(0); //needed, no idea why?
//If we stop here, we see the floor pattern as expected. But..!
#if 01
mapData.selectShader(mapData.programDMWall);
//The floor is now gone (or maybe never happened)
//this draws the walls
glEnableVertexAttribArray(0); //needed, don't know why
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //no indexed draw for these
glBindBuffer(GL_ARRAY_BUFFER, mapData.wallBuffer_); //Select a lot of skinny triangles
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
//std::cout << "Wall draw " << mapData.triangles_.size() * 3 << " floats from buf " << mapData.wallBuffer_ << '\n';
glDrawArrays(GL_TRIANGLES, 0, mapData.triangles_.size() * 3); //no indexed draw for this one
glDisableVertexAttribArray(0);
//we see the walls, but no floor!
#else
//we see the floor, and of course no walls.
//Need both!
#endif
glutSwapBuffers();
至于mapData.selectShader(),就是
void selectShader(GLuint ShaderProgram) //in Map::
{
glUseProgram(ShaderProgram);
//All the shaders should be sharing gWorld, so I probably don't need
// to set this over and over, since it's not going to change. But it needs
// to follow a glUseProgram so for now it's here. Needed each time?
gWorldLocation = glGetUniformLocation(ShaderProgram, "gWorld");
assert(gWorldLocation != 0xFFFFFFFF);
}
这实际上应该如何工作?
附录:墙的 .vs:
#version 430
//buffer indexes
#define BI_LIGHTS 0
#define BI_WALLS 1
#define BI_WALLWALK 2
#define BI_DOORS 3
#define BI_WALLINDEXES 4
layout (location = 0) in vec3 Position;
uniform mat4 gWorld;
layout (std430, binding=BI_WALLINDEXES) buffer wallIndexesSkip
{
unsigned int wallIndexes[];
};
out vec4 Color; //unused; the fragment shader calculates all colors
//but maybe we pass the initial floor texture here someday
flat out unsigned int wallIndex;
void main()
{
gl_Position = gWorld * vec4(Position, 1.0);
//We must the fragment shader which wall it should NOT use to
// occlude walls, otherwise the wall currently being drawing
// will be occluded by itself!
wallIndex = wallIndexes[gl_VertexID/9];
}
和带有声明的 .fs 的开头:
#version 430
#define BI_LIGHTS 0
#define BI_WALLS 1
#define BI_WALLWALK 2
#define BI_DOORS 3
#define BI_WALLINDEXES 4
#define AMB_NONE 0
#define AMB_SUNLIGHT 1
#define AMB_CLOUDY 2
#define AMB_RAIN 3
#define AMB_FOG 4
#define AMB_DIM 5
#define AMB_TEST 6
#define LIT_NONE 0
#define LIT_MAGICAL 1
#define LIT_FIRE 2
#define LIT_INFRAVISION 3
layout (std430, binding=BI_LIGHTS) buffer lights
{
unsigned int lightCount;
//12 bytes wasted in this packing
vec4 lightData[]; //x, y, radius, typeflag
};
layout (std430, binding=BI_WALLS) buffer walls
{
vec2 wp[];
};
layout (std430, binding=BI_WALLWALK) buffer wallRuns
{
// 0 this wall is ok
//>0 number to skip including this one
//0xffffffff marks end
unsigned int skipWalls[];
};
layout (std430, binding=BI_DOORS) buffer doors
{
unsigned int doorCount;
//12 bytes wasted in this packing
vec4 dp[]; //hinge x, hinge y, end x, end y
};
flat in unsigned int wallIndex;
in vec4 Color;
out vec4 FragColor;
我会留下这个问题作为对其他人的警示故事。简短的回答是 GLSL 中的统一变量需要在 glUseProgram 之后绑定到当前程序。他们不会自己神奇地找到着色器。我添加了一个 glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, glm::value_ptr(projection));在每个 glUseProgram 和事情改进之后。
感谢评论中的人们,他们在创纪录的时间内解决了这个问题。