使用两个着色器时的opengl奇怪行为
Posted
技术标签:
【中文标题】使用两个着色器时的opengl奇怪行为【英文标题】:opengl strange behavior when using two shaders 【发布时间】:2021-06-19 17:21:07 【问题描述】:我有两个着色器,一个用于实例化,一个用于绘制一条线。它们分别对应于两段代码(segment1 用于实例化,segment2 用于一行)。而且编程行为很奇怪:
-
当我将segment2 放在segment1 后面时,
segment1 work
就消失了。然后我注释段2的代码,段1有效。然后我取消注释段 2 代码并将其放在段 1 之前。然后这两个部分都有效。这很奇怪。
所以我只是把segment2 放在segment1 之前让它工作。但我想要的是当按下某些键时,视图会移动。但事情是这样的:
a. when both segments uncommented, the instancing will move as expected, but the line just stays at where it borns.
b. then I comment the segment2 code, then the line will move as expected when keys pressed.
这两个问题一定有一些联系。这是部分代码,无法运行,如有需要我会提供完整的可运行代码。
#include <stdio.h>
#include <stdlib.h>
#include <glad/glad.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/norm.hpp>
#include <thread>
#include <queue>
#include <mutex>
#include <glm/gtx/string_cast.hpp>
#include "../common/shader.hpp"
GLFWwindow *window;
using namespace glm;
using std::cout, std::endl;
int run_websocket(); // another thread run this function to get data into the queue
extern std::queue<std::tuple<unsigned long, float, float, bool>> queue1;
extern std::mutex m;
const int MaxParticles = 100000;
const int MaxLine = 1000;
int index = 0;
int width = 1024;
int height = 768;
float deltaTime = 0.0f;
float lastFrame = 0.0f;
void framebuffer_size_callback(GLFWwindow *window, int width1, int height1)
width = width1;
height = height1;
glViewport(0, 0, width1, height1);
void processInput(GLFWwindow *window)
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float f1 = 10000;
float f_up_down = 10;
float cameraSpeed = deltaTime;
if (glfwGetKey(window, GLFW_KEY_N) == GLFW_PRESS)
cameraPos += cameraSpeed * (cameraFront * f_up_down);
if (glfwGetKey(window, GLFW_KEY_M) == GLFW_PRESS)
cameraPos -= cameraSpeed * (cameraFront * f_up_down);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * (cameraSpeed * f1);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * (cameraSpeed * f1);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPos += glm::normalize(cameraUp) * (cameraSpeed * f_up_down);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPos -= glm::normalize(cameraUp) * (cameraSpeed * f_up_down);
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 10.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
unsigned long x0 = 0;
float y00 = 0.0f;
int main(void)
// Initialise GLFW
std::thread t1(run_websocket);
if (!glfwInit())
fprintf(stderr, "Failed to initialize GLFW\n");
getchar();
return -1;
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
window = glfwCreateWindow(width, height, "title", NULL, NULL);
if (window == NULL)
fprintf(stderr,
"Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
getchar();
glfwTerminate();
return -1;
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glfwPollEvents();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLuint programID = LoadShaders("Particle.vertexshader",
"Particle.fragmentshader");
GLuint shader2 = LoadShaders("line.vertexshader",
"line.fragmentshader");
GLuint ViewProjMatrixID = glGetUniformLocation(programID, "VP");
GLuint ViewProjMatrixID2 = glGetUniformLocation(shader2, "VP2");
static GLfloat *g_particule_position_size_data = new GLfloat[MaxParticles * 4];
static GLfloat *g_line_data = new GLfloat[MaxLine * 4];
static const GLfloat g_vertex_buffer_data[] =
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
;
// vao of segment2
GLuint LineVertexArrayID;
glGenVertexArrays(1, &LineVertexArrayID);
glBindVertexArray(LineVertexArrayID);
GLuint line_buffer;
glGenBuffers(1, &line_buffer);
glBindBuffer(GL_ARRAY_BUFFER, line_buffer);
glBufferData(GL_ARRAY_BUFFER, MaxLine * 4 * sizeof(float), NULL, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
2 * sizeof(float),
(void *) 0
);
glBindVertexArray(0);
// vao of segment2 ends
// vao of segment1
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint billboard_vertex_buffer;
glGenBuffers(1, &billboard_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
2 * sizeof(float),
(void *) 0
);
GLuint particles_position_buffer;
glGenBuffers(1, &particles_position_buffer);
glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer);
glBufferData(GL_ARRAY_BUFFER, MaxParticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
4 * sizeof(float),
(void *) 0
);
glVertexAttribDivisor(1, 1);
glBindVertexArray(0);
// vao of segment1 ends
do
glClear(GL_COLOR_BUFFER_BIT);
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
projection = glm::perspective(glm::radians(90.0f), 1000.0f, 0.1f, 1000.0f);
glm::mat4 ViewProjectionMatrix = projection * view;
glm::mat4 ViewProjectionMatrix2 = projection * view;
glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &ViewProjectionMatrix[0][0]);
glUniformMatrix4fv(ViewProjMatrixID2, 1, GL_FALSE, &ViewProjectionMatrix2[0][0]);
// why move segment2 behind segment1 then segment1 will not show ???
///// segment2
int lineNum = 1;
int line_index = 0;
glUseProgram(shader2);
glBindVertexArray(LineVertexArrayID);
glBindBuffer(GL_ARRAY_BUFFER, line_buffer);
g_line_data[line_index * 2 + 0] = -1.0f;
g_line_data[line_index * 2 + 1] = 0;
line_index = 1;
g_line_data[line_index * 2 + 0] = 1.0f;
g_line_data[line_index * 2 + 1] = 0;
glBufferData(GL_ARRAY_BUFFER, MaxLine * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, lineNum * sizeof(GLfloat) * 4, g_line_data);
glDrawArrays(GL_LINES, 0, 2);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
///// segment2
// printing some here to make sure the Math is correct
// vec4 p1 = ViewProjectionMatrix * vec4(-1.0f, 0, -0.1, 1.0);
// vec4 p2 = ViewProjectionMatrix * vec4(1.0f, 0, -0.1, 1.0);
// cout << "p1 y " << p1.y / p1.w << " , p2 y " << p2.y / p2.w << endl;
//// segment1
std::lock_guard<std::mutex> lck(m);
while (!queue1.empty())
auto &t = queue1.front();
unsigned long x_raw = std::get<0>(t);
float y = std::get<1>(t);
if (x0 == 0)
x0 = x_raw;
y00 = y;
cameraPos += glm::vec3(0, 0, 0);
x_raw -= x0;
y -= y00;
float x = float(x_raw);
float s = std::get<2>(t);
bool is_sell_b = std::get<3>(t);
float is_buy = 1.0f - static_cast<float>(is_sell_b);
g_particule_position_size_data[index * 4 + 0] = x;
g_particule_position_size_data[index * 4 + 1] = y;
g_particule_position_size_data[index * 4 + 2] = s / 100;
g_particule_position_size_data[index * 4 + 3] = is_buy;
index++;
queue1.pop();
glUseProgram(programID);
glBindVertexArray(VertexArrayID);
glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer);
// glBufferData(GL_ARRAY_BUFFER, MaxParticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); // Buffer orphaning, a common way to improve streaming perf. See above link for details.
glBufferSubData(GL_ARRAY_BUFFER, 0, index * sizeof(GLfloat) * 4, g_particule_position_size_data);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 6, index);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//// segment1
glfwSwapBuffers(window);
glfwPollEvents();
// Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
delete[] g_particule_position_size_data;
// Cleanup VBO and shader
glDeleteBuffers(1, &particles_position_buffer);
glDeleteBuffers(1, &billboard_vertex_buffer);
glDeleteProgram(programID);
// glDeleteTextures(1, &Texture);
glDeleteVertexArrays(1, &VertexArrayID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
【问题讨论】:
【参考方案1】:glUniform*
在当前安装程序的默认uniform块中设置一个uniform变量。
在设置制服前用glUseProgram
安装程序:
glUseProgram(programID);
glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &ViewProjectionMatrix[0][0]);
glUseProgram(shader2);
glUniformMatrix4fv(ViewProjMatrixID2, 1, GL_FALSE, &ViewProjectionMatrix2[0][0]);
或者使用glProgramUniformMatrix4fv
:
glProgramUniformMatrix4fv(programID, ViewProjMatrixID, 1, GL_FALSE, &ViewProjectionMatrix[0][0]);
glProgramUniformMatrix4fv(shader2, ViewProjMatrixID2, 1, GL_FALSE, &ViewProjectionMatrix2[0][0]);
【讨论】:
以上是关于使用两个着色器时的opengl奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章
为啥在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216?