Kết xuất họa tiết với OpenGL C ++

Aug 16 2020

Tôi đang cố gắng kết xuất một số đa giác thành một kết cấu, và sau đó kết xuất kết cấu đó ra màn hình. Tôi không chắc chắn về cách gỡ lỗi mã của mình vì điều đó sẽ yêu cầu thăm dò trạng thái bên trong của OpenGL, vì vậy tôi sẽ đánh giá cao các mẹo về cách tự gỡ lỗi hơn là chỉ ra lỗi mà tôi đã thực hiện. Dù sao, tôi đã nhận xét mã tôi đã viết giải thích những gì tôi mong đợi mỗi dòng sẽ làm.

Đây là mô tả về những gì mã phải làm. Về cơ bản, tôi đã tạo một bộ đổ bóng đỉnh cung cấp vị trí, tia UV và màu sắc cho bộ đổ bóng phân mảnh. Trình đổ bóng phân mảnh có một bộ đồng nhất để kích hoạt lấy mẫu kết cấu, nếu không, nó sẽ chỉ xuất ra màu đầu vào. Trong cả hai trường hợp, màu được nhân với một màu đồng nhất. Đầu tiên, tôi tạo một kết cấu và điền vào nó với dữ liệu pixel thô màu đỏ và xanh lá cây để kiểm tra. Kết cấu này được hiển thị tương ứng với màn hình (tôi nhìn thấy phần màu đỏ và xanh lá cây chính xác khi tôi khởi tạo nó). Sau đó, tôi cố gắng thực hiện kết xuất thực tế trên kết cấu. Tôi cố gắng kết xuất một hình vuông nhỏ màu xanh lam ở giữa nó (trình lấy mẫu bị vô hiệu hóa trên bộ đổ bóng phân mảnh, đồng nhất màu được đặt thành màu xanh lam) nhưng tôi không thể làm cho hình vuông màu xanh lam này xuất hiện trên kết cấu được kết xuất.

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "utils.h"

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include <iostream>

using namespace std;
#define numVAOs 1
#define numVBOs 1

GLuint shaderProgram;
GLuint unifUseTexture, unifInTexture, unifTMat, unifDrawColor;
GLuint texture;
GLuint textureFrameBuffer;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];

void drawRectangle() {

}
void init() {
    // Compile the shaderProgram
    shaderProgram = createShaderProgram("vertex.glsl","fragment.glsl");
    // Retrieve the uniform location
    unifUseTexture = glGetUniformLocation(shaderProgram,"useTexture");
    unifInTexture = glGetUniformLocation(shaderProgram,"inTexture");
    unifTMat = glGetUniformLocation(shaderProgram,"tMat");
    unifDrawColor = glGetUniformLocation(shaderProgram,"drawColor");
    // Create vertex array object and vertex buffer object
    glGenVertexArrays(numVAOs,vao);
    glBindVertexArray(vao[0]);
    float xyzuvrgbaSquare[54] = {
        /* C */ 1.0,-1.0,0.0, 1.0,0.0, 1.0,1.0,1.0,1.0,
        /* A */ -1.0,1.0,0.0, 0.0,1.0, 1.0,1.0,1.0,1.0,
        /* B */  1.0,1.0,0.0, 1.0,1.0, 1.0,1.0,1.0,1.0,
        /* A */ -1.0,1.0,0.0, 0.0,1.0, 1.0,1.0,1.0,1.0,
        /* C */ 1.0,-1.0,0.0, 1.0,0.0, 1.0,1.0,1.0,1.0,
        /* D */-1.0,-1.0,0.0, 0.0,0.0, 1.0,1.0,1.0,1.0
    };
    glGenBuffers(numVBOs,vbo);
    glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
    glBufferData(GL_ARRAY_BUFFER, 4*54,xyzuvrgbaSquare,GL_STATIC_DRAW);
    // Associate vbo with the correct vertex attribute to display the rectangle
    glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,36,0); // inPosition
    glVertexAttribPointer(1,4,GL_FLOAT,GL_FALSE,36,(void*)20); // inColor
    glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,36,(void*)12); // inUV
    glEnableVertexAttribArray(0); // location=0 in the shader
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    // Generate a small 128x128 texture. I followed the tutorial
    // over http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/

    // generate a frameBuffer to contain the texture
    glGenFramebuffers(1,&textureFrameBuffer);
    // Bind it, so when I will generate the texture it will be associated with it
    glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
    glGenTextures(1,&texture);
    glBindTexture(GL_TEXTURE_2D,texture);
    // Put some raw data inside of it for testing purposes. I will fill it
    // half with green, half with red
    unsigned char* imageRaw = new unsigned char[4*128*128];
    for(int i=0; i<4*128*64; i+=4) {
        imageRaw[i] = 255;
        imageRaw[i+1] = 0;
        imageRaw[i+2] = 0;
        imageRaw[i+3] = 255;
        imageRaw[4*128*64+i] = 0;
        imageRaw[4*128*64+i+1] = 255;
        imageRaw[4*128*64+i+2] = 0;
        imageRaw[4*128*64+i+3] = 255;
    }
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,128,128,0,GL_RGBA,GL_UNSIGNED_BYTE,imageRaw);
    // Setup some required parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    // Draw a small blue square on the texture
    // So, activate the previously compiled shader program and setup the uniforms
    glUseProgram(shaderProgram);
    // First, create a transform matrix to make the square smaller (20% of texture)
    glm::mat4 tMat = glm::scale(glm::mat4(1.0f),glm::vec3(0.2,0.2,0));
    glUniformMatrix4fv(unifTMat,1,GL_FALSE,glm::value_ptr(tMat));
    // do not use a texture (ignore sampler2D in fragment shader)
    glUniform1i(unifUseTexture,0);
    // use the color BLUE for the rectangle
    glUniform4f(unifDrawColor,0.0,0.0,1.0,1.0);
    // Bind the textureFrameBuffer to render on the texture instead of the screen
    glBindFramebuffer(GL_FRAMEBUFFER,textureFrameBuffer);
    glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,texture,0);
    GLenum drawBuffers[1] = {GL_COLOR_ATTACHMENT0};
    glDrawBuffers(1, drawBuffers);
    GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
    if( status != GL_FRAMEBUFFER_COMPLETE ) {
        cout << "framebuffer status: " << status << endl;
    }
    // the vertex framebuffer and vertex attribute pointer have already been
    // described, so I'll just do the draw call here
    glDrawArrays(GL_TRIANGLES,0,6);

    // Display the textore on screen
    // Bind the screen framebuffer (0) so the following rendering will occurr on screen
    glBindFramebuffer(GL_FRAMEBUFFER,0);
    // Put a white background color
    glClearColor(1.0,1.0,1.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    // Change properly the shader uniforms
    glUniform4f(unifDrawColor,1.0,1.0,1.0,1.0); // multiply by white, no changes
    glUniform1i(unifUseTexture,1); // set useTexture to True
    // Create a transform matrix to scale the rectangle so that it uses up only half screen
    tMat = glm::scale(glm::mat4(1.0f),glm::vec3(.5,.5,.0));
    glUniformMatrix4fv(unifTMat,1,GL_FALSE,glm::value_ptr(tMat));
    // Put the sampler2D 
    glActiveTexture(GL_TEXTURE0); // Work on texture0
    // 0 because of (binding = 0) on the fragment shader
    glBindTexture(GL_TEXTURE_2D,texture);
    

    glDrawArrays(GL_TRIANGLES,0,6); // 6 vertices
}


int main(int argc, char** argv) {
    // Build the window
    if (!glfwInit()) exit(EXIT_FAILURE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
    GLFWwindow* window = glfwCreateWindow(600,600,"Dashboard",NULL,NULL);
    glfwMakeContextCurrent(window);
    if(glewInit() != GLEW_OK) exit(EXIT_FAILURE);
    glfwSwapInterval(1);
    init();
    while(!glfwWindowShouldClose(window)) {
        //display(window,glfwGetTime());
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

chỉnh sửa: Tôi đã quên đặt mã bộ đổ bóng ở đây, mặc dù vấn đề không nằm trong bộ đổ bóng vì nó hoạt động khi được sử dụng để hiển thị kết cấu ra màn hình.

vertex.glsl:

#version 430
layout (location=0) in vec3 inPosition;
layout (location=1) in vec4 inColor;
layout (location=2) in vec2 inUV;

uniform mat4 tMat;
uniform vec4 drawColor;

out vec4 varyingColor;
out vec2 varyingUV;

void main(void) {
    gl_Position = tMat * vec4(inPosition,1.0);
    varyingColor = inColor*drawColor;
    varyingUV = inUV;
}

mảnh.glsl:

#version 430
in vec4 varyingColor;
in vec2 varyingUV;
layout(location = 0) out vec4 color;

layout (binding=0) uniform sampler2D inTexture;
uniform bool useTexture;

void main(void) {
    if( useTexture )
        color = vec4(texture(inTexture,varyingUV).rgb,1.0) * varyingColor;
    else
        color = varyingColor;
}

Trả lời

1 Rabbid76 Aug 16 2020 at 23:48

Kết cấu được gắn vào bộ đệm khung, có kích thước khác với cửa sổ. Do đó, bạn phải điều chỉnh hình chữ nhật khung nhìn ( glViewport) thành kích thước bằng kích thước của bộ đệm khung hiện bị ràng buộc, trước khi vẽ hình:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageRaw);

// [...]

glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture,0);
glViewport(0, 0, 128, 128);

// [...]

glDrawArrays(GL_TRIANGLES, 0, 6);

// [...]

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, WIDTH, HEIGHT);

// [...]

glDrawArrays(GL_TRIANGLES, 0, 6);