使用着色器

时间:2017-07-07 17:54:26

标签: c++ opengl textures shader

我正在试图找出如何使用着色器。

下面的代码只是在方形图像的中心绘制一个圆圈。要验证输出,像素正在复制到.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

第一个简单着色器效果很好:它只是将纹理颜色更改为红色。 但第二个 - 不幸的是,没有。 我不知道为什么。

我有三个假设,其中袋子位于。

  1. 在将纹理从着色器绑定到帧缓冲区对象中的纹理的代码中。
  2. 着色器的代码错误。
  3. 同时进行两项假设。
  4. 无着色器渲染:

    Render without shader

    使用简单着色器渲染:

    Render with the simple shader

    使用“模糊效果”渲染着色器显示黑屏...

    有人能说出我做错了吗?

0 个答案:

没有答案