在OpenGL四边形上绘制正弦波却显示黑屏的问题
问题:OpenGL全屏着色器测试显示黑屏四边形
我用OpenGL和glfw3搭建着色器测试环境,写了个简单片段着色器测试,但始终显示黑屏四边形。调glEnable参数没用,改着色器只能在黑、白之间切换。
问题根源与修复方案
核心问题
- Uniform设置时机错误:你在
glUseProgram(programID)之前调用了glUniform2f,此时着色器程序未激活,Uniform值无法正确传入GPU。必须先激活程序再设置Uniform。 - 顶点着色器逻辑缺失:虽然未提供顶点着色器代码,但从主程序绑定的顶点属性来看,顶点着色器必须正确输出
gl_Position,否则图形无法被正确渲染到屏幕上。 - 冗余顶点(非致命):使用
GL_TRIANGLE_STRIP绘制全屏四边形仅需4个顶点,当前5个顶点属于冗余,不影响功能但可优化。
具体修复步骤
- 调整Uniform设置位置:将
glUniform2f移至渲染循环内的glUseProgram之后:
do{ glClear( GL_COLOR_BUFFER_BIT ); glUseProgram(programID); // 激活程序后再设置Uniform glUniform2f(glGetUniformLocation(programID,"u_resolution"),1024, 768); // 后续渲染代码 } while(...);
- 确保顶点着色器正确:顶点着色器需包含以下基础逻辑(对应主程序绑定的属性0):
#version 330 core layout(location = 0) in vec3 vertexPosition_modelspace; void main(){ gl_Position = vec4(vertexPosition_modelspace, 1.0); }
- 优化顶点数量(可选):将顶点数组改为4个顶点,绘制时使用
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4):
static const GLfloat g_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, };
提供的代码
片段着色器
#version 330 core #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; float line(vec2 uv,float x,float width){ return smoothstep(x-width,x,uv.y)-smoothstep(x,x+width,uv.y); } void main() { vec2 uv=gl_FragCoord.xy/u_resolution; vec3 color=vec3(line(uv,sin(uv.x),.1)); gl_FragColor=vec4(color,1.0); }
主函数代码
#include <stdio.h> #include <stdlib.h> #include <GL/glew.h> #include <GLFW/glfw3.h> GLFWwindow* window; #include <glm/glm.hpp> using namespace glm; #include "common/shader.hpp" int main( void ) { // Initialise GLFW 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_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Open a window and create its OpenGL context window = glfwCreateWindow( 1024, 768, "Tutorial 02 - Red triangle", 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); // Initialize GLEW glewExperimental = true; // Needed for core profile if (glewInit() != GLEW_OK) { fprintf(stderr, "Failed to initialize GLEW\n"); getchar(); glfwTerminate(); return -1; } // Ensure we can capture the escape key being pressed below glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); // Dark blue background glClearColor(0.0f, 0.0f, 0.4f, 0.0f); GLuint VertexArrayID; glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); // Create and compile our GLSL program from the shaders GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" ); static const GLfloat g_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, }; GLuint vertexbuffer; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); glUniform2f(glGetUniformLocation(programID,"u_resolution"),1024, 768); do{ // Clear the screen glClear( GL_COLOR_BUFFER_BIT ); // Use our shader glUseProgram(programID); // 1rst attribute buffer : vertices glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // attribute 0. No particular reason for 0, but must match the layout in the shader. 3, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); // Draw the triangle ! glDrawArrays(GL_TRIANGLE_STRIP, 0, 5); // 3 indices starting at 0 -> 1 triangle glDisableVertexAttribArray(0); // Swap buffers 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 ); // Cleanup VBO // glDeleteBuffers(1, &vertexbuffer); glDeleteVertexArrays(1, &VertexArrayID); glDeleteProgram(programID); // Close OpenGL window and terminate GLFW glfwTerminate(); return 0; }
shader.cpp代码
#include <stdio.h> #include <string> #include <vector> #include <iostream> #include <fstream> #include <algorithm> #include <sstream> using namespace std; #include <stdlib.h> #include <string.h> #include <GL/glew.h> #include "shader.hpp" GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ // Create the shaders GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); // Read the Vertex Shader code from the file std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if(VertexShaderStream.is_open()){ std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); }else{ printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path); getchar(); return 0; } // Read the Fragment Shader code from the file std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if(FragmentShaderStream.is_open()){ std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } GLint Result = GL_FALSE; int InfoLogLength; // Compile Vertex Shader printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); glCompileShader(VertexShaderID); // Check Vertex Shader glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if ( InfoLogLength > 0 ){ std::vector<char> VertexShaderErrorMessage(InfoLogLength+1); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); printf("%s\n", &VertexShaderErrorMessage[0]); } // Compile Fragment Shader printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); glCompileShader(FragmentShaderID); // Check Fragment Shader glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if ( InfoLogLength > 0 ){ std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); printf("%s\n", &FragmentShaderErrorMessage[0]); } // Link the program printf("Linking program\n"); GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); // Check the program glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); if ( InfoLogLength > 0 ){ std::vector<char> ProgramErrorMessage(InfoLogLength+1); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); printf("%s\n", &ProgramErrorMessage[0]); } glDetachShader(ProgramID, VertexShaderID); glDetachShader(ProgramID, FragmentShaderID); glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); return ProgramID; }
内容的提问来源于stack exchange,提问作者justashaderboy
相关产品推荐
相关产品推荐

