我正在试图找出如何使用着色器。
下面的代码只是在方形图像的中心绘制一个圆圈。要验证输出,像素正在复制到.ppm图像。
main.cpp中:
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <Math.h>
GLuint fbo, texture;
const int CHANNEL_COUNT = 4;
const GLenum PIXEL_FORMAT = GL_RGBA;
void init_gl(int width, int height);
void generate_fbo(int width, int height);
void draw_circle(float x, float y, float r = 0.5f);
void save_img(int w, int h, int data_size);
GLuint load_shaders(const char * v_s_path, const char * f_s_path);
GLuint init_simple_shader();
GLuint init_shader();
// -*- -*- -*- -*- -*- //
int main(int argc, char** argv)
{
int w = 512, h = 512;
init_gl(w, h); // initialize GL resources
// create frame buffer obeject and texture
generate_fbo(w, h);
//load shaders
GLuint shader init_simple_shader(); // init_shader(); doesn't work
// draw a circle
draw_circle(0, 0);
save_img(w, h, w * h * CHANNEL_COUNT);
// delete resources
glDeleteProgram(shader);
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &texture);
return 0;
}
// -*- -*- -*- -*- -*- //
void init_gl(int width, int height)
{
glutInitWindowSize(width, height);
glutCreateWindow("OpenGL");
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
float ar = (float)width / height;
gluOrtho2D(-1*ar, ar, -1, 1);
glShadeModel(GL_SMOOTH);
glClearColor(0.0, 0.0, 0.0, 1.0);
}
GLuint init_simple_shader()
{
//change texture color to red
GLuint shader = load_shaders("./v_shader_simple.txt", "./f_shader_simple.txt");
glUseProgram(shader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
const float color[4] = {1.0f, 0.0f, 0.0f, 1.0f}; // red color
glUniform4fv(glGetUniformLocation(shader, "color"), 1, color);
return shader;
}
GLuint init_shader()
{
//blur image
GLuint shader = load_shaders("./v_shader.txt", "./f_shader.txt");
glUseProgram(shader);
glActiveTexture(GL_TEXTURE0 );
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(shader, "texture"), 0);
const float dir[2] = {1.0f, 0.0f};
glUniform1f(glGetUniformLocation(shader, "radius"), 0.1f);
glUniform2fv(glGetUniformLocation(shader, "direction"), 2, dir);
return shader;
}
void generate_fbo(int width, int height)
{
// fbo
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, PIXEL_FORMAT, width, height, 0, PIXEL_FORMAT, GL_UNSIGNED_BYTE, 0);
//bind the texture to fbo
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
//Check for FBO completeness
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
std::cout << "Error!" << std::endl;
std::cin.get();
std::terminate();
}
}
void draw_circle(float x, float y, float r)
{
// just draw a circle with radial gradient brightness
GLfloat angle;
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0f ,1.0f,1.0f);
glVertex2f(x, y);
glColor3f(0,0,0);
for (int i = 0; i <= 100; i++)
{
angle = i * 2.0f * M_PI / 100;
glVertex2f(x + cos(angle) * r, y + sin(angle) * r);
}
glEnd();
}
void save_img(int w, int h, int data_size)
{
// get data from the frame buffer and save it like .ppm image
std::vector<uint8_t> pixels(data_size);
glReadPixels(0, 0, w, h, PIXEL_FORMAT, GL_UNSIGNED_BYTE, &pixels[0]);
FILE *f = fopen("./test_image.ppm", "wb");
fprintf(f, "P6\n%i %i 255\n", w, h);
for (int y=0; y< h; y++)
{
for (int x=0; x< w; x++)
{
int start_idx = (y * w + x) * CHANNEL_COUNT;
fputc((int)pixels[start_idx], f);
fputc((int)pixels[start_idx + 1], f);
fputc((int)pixels[start_idx + 2], f);
}
}
fclose(f);
}
GLuint load_shaders(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::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
}else{
printf("Impossible to open %s!\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::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
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;
}
着色器(在.txt文件中) V.simple:
attribute vec2 coord;
void main()
{
gl_Position = vec4(coord, 0.0, 1.0);
}
F.simple:
uniform vec4 color;
void main()
{
gl_FragColor = color; // change the color
}
N:
attribute vec2 TexCoord;
attribute vec4 Color;
attribute vec2 coord;
varying vec4 vColor;
varying vec2 vTexCoord;
void main()
{
vColor = Color;
vTexCoord = TexCoord;
gl_Position = vec4(coord, 0.0, 1.0);
}
F。 (模糊效果):
varying vec4 vColor;
varying vec2 vTexCoord;
uniform sampler2D texture;
uniform float radius;
uniform vec2 dir;
void main() {
vec4 sum = vec4(0.0);
vec2 tc = vTexCoord;
float hstep = dir.x;
float vstep = dir.y;
sum += texture2D(texture, vec2(tc.x - 4.0*radius*hstep, tc.y - 4.0*radius*vstep)) * 0.0162162162;
sum += texture2D(texture, vec2(tc.x - 3.0*radius*hstep, tc.y - 3.0*radius*vstep)) * 0.0540540541;
sum += texture2D(texture, vec2(tc.x - 2.0*radius*hstep, tc.y - 2.0*radius*vstep)) * 0.1216216216;
sum += texture2D(texture, vec2(tc.x - 1.0*radius*hstep, tc.y - 1.0*radius*vstep)) * 0.1945945946;
sum += texture2D(texture, vec2(tc.x, tc.y)) * 0.2270270270;
sum += texture2D(texture, vec2(tc.x + 1.0*radius*hstep, tc.y + 1.0*radius*vstep)) * 0.1945945946;
sum += texture2D(texture, vec2(tc.x + 2.0*radius*hstep, tc.y + 2.0*radius*vstep)) * 0.1216216216;
sum += texture2D(texture, vec2(tc.x + 3.0*radius*hstep, tc.y + 3.0*radius*vstep)) * 0.0540540541;
sum += texture2D(texture, vec2(tc.x + 4.0*radius*hstep, tc.y + 4.0*radius*vstep)) * 0.0162162162;
gl_FragColor = vColor * vec4(sum.rgb, 1.0);
}
如何在MacOS上编译:
c++ -std=c++11 -O3 -Wall -Wdeprecated-declarations -framework GLUT -framework OpenGL -framework Cocoa -o test main.cpp
第一个简单着色器效果很好:它只是将纹理颜色更改为红色。 但第二个 - 不幸的是,没有。 我不知道为什么。
我有三个假设,其中袋子位于。
无着色器渲染:
使用简单着色器渲染:
使用“模糊效果”渲染着色器显示黑屏...
有人能说出我做错了吗?