为什么OpenGL中的3D投影可以工作,但会留下痕迹?

我刚刚从Wikipedia 中为 3D 投影做了一些数学运算,因为我注意到它们很简单,不需要库。它确实有效,但立方体在移动时会留下痕迹。请注意,立方体实际上并没有移动,我实际上是在改变相机位置,使立方体看起来像是在移动。

没有必要指出我正在做的 100 个坏习惯,我知道,这只是一个快速测试。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <glad/glad.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_opengl.h>
#include <math.h>
#include "utils.h"
#include "keys.h"

char p = 1;

typedef struct Vec3 {
float x;
float y;
float z;
} Vec3;

void Mat_iden(float *m, Uint32 s) {
Uint32 i = 0;
Uint32 unt = s + 1;
while (i < s) {
    m[unt * i] = 1;
    i++;
}
}

float one[3][3];
float two[3][3];
float three[3][3];

int main() {
SDL_Init(SDL_INIT_VIDEO);
IMG_Init(IMG_INIT_PNG);

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);

SDL_Window *w = SDL_CreateWindow("Snapdoop", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 500, 500, SDL_WINDOW_OPENGL);
SDL_GLContext c = SDL_GL_CreateContext(w);

gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress);

Mat_iden(one[0], 3);
Mat_iden(two[0], 3);
Mat_iden(three[0], 3);

Shader s[2];

s[0] = Shade("/home/shambhav/eclipse-workspace/Snadoop/src/vs.glsl");
s[1] = Shade("/home/shambhav/eclipse-workspace/Snadoop/src/fs.glsl");
Shade_comp(&s[0], GL_VERTEX_SHADER);
Shade_comp(&s[1], GL_FRAGMENT_SHADER);
Program sp;
Prog_attach(&sp, s, 2);
printf("VS: %sn", s[0].info);
printf("FS: %sn", s[1].info);
printf("SP: %sn", sp.info);
glDeleteShader(s[0].c);
glDeleteShader(s[1].c);

float v[48] = {
        //Front
        0.25, 0.25, 0.25, 1.0, 1.0, 0.0,
        -0.25, 0.25, 0.25, 1.0, 0.0, 0.0,
        -0.25, -0.25, 0.25, 0.0, 1.0, 1.0,
        0.25, -0.25, 0.25, 0.0, 1.0, 0.0,
        //Back
        0.25, 0.25, -0.25, 0.0, 0.0, 1.0,
        -0.25, 0.25, -0.25, 1.0, 0.0, 1.0,
        -0.25, -0.25, -0.25, 1.0, 1.0, 1.0,
        0.25, -0.25, -0.25, 0.0, 0.0, 0.0
};
unsigned int i[36] = {
        //Front
        0, 1, 2,
        2, 3, 0,
        //Right
        0, 3, 7,
        7, 4, 0,
        //Left
        1, 2, 6,
        6, 5, 2,
        //Back
        4, 5, 6,
        6, 7, 4,
        //Up
        0, 1, 5,
        5, 4, 0,
        //Down
        3, 7, 2,
        2, 6, 7
};

GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);

glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(i), i, GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void *)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void *)(sizeof(float) * 3));
glEnableVertexAttribArray(1);

Vec3 cam = {1.0, 1.0, 1.0};
Vec3 theta = {0, 0, 0};

Key k = (const Key){ 0 };
printf("%dn", k.alpha[9]);

SDL_Event e;
while (p) {
    while (SDL_PollEvent(&e)) {
        switch (e.type) {
        case SDL_QUIT:
            p = 0;
            break;

        case SDL_KEYDOWN:
            *key(&k, e.key.keysym.sym) = 1;
            break;

        case SDL_KEYUP:
            *key(&k, e.key.keysym.sym) = 0;
            break;
        }
    }

    if (*key(&k, SDLK_RIGHT)) {
        cam.x += 0.01;
    }
    if (*key(&k, SDLK_LEFT)) {
        cam.x -= 0.01;
    }
    if (*key(&k, SDLK_UP)) {
        cam.y += 0.01;
    }
    if (*key(&k, SDLK_DOWN)) {
        cam.y -= 0.01;
    }

    if (*key(&k, 'w')) {
        theta.y += 0.01;
    }
    if (*key(&k, 's')) {
        theta.y -= 0.01;
    }
    if (*key(&k, 'a')) {
        theta.x -= 0.01;
    }
    if  (*key(&k, 'd')) {
        theta.x += 0.01;
    }
    if (*key(&k, 'z')) {
        theta.z -= 0.01;
    }
    if (*key(&k, 'x')) {
        theta.z += 0.01;
    }
    if (*key(&k, 'n')) {
        cam.z += 0.01;
    }
    if (*key(&k, 'm')) {
        cam.z -= 0.01;
    }

    one[1][1] = cos(theta.x);
    one[1][2] = sin(theta.x);
    one[2][1] = -sin(theta.x);
    one[2][2] = cos(theta.x);

    two[0][0] = cos(theta.y);
    two[0][2] = -sin(theta.y);
    two[2][0] = sin(theta.y);
    two[2][2] = cos(theta.y);

    three[0][0] = cos(theta.z);
    three[0][1] = sin(theta.z);
    three[1][0] = -sin(theta.z);
    three[1][1] = cos(theta.z);

    glUseProgram(sp.p);
    glUniformMatrix3fv(2, 1, GL_FALSE, one[0]);
    glUniformMatrix3fv(3, 1, GL_FALSE, two[0]);
    glUniformMatrix3fv(4, 1, GL_FALSE, three[0]);
    glUniform3f(5, cam.x, cam.y, cam.z);
    glClear(GL_DEPTH_BUFFER_BIT);

    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
    SDL_GL_SwapWindow(w);
}

glDeleteProgram(sp.p);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);

SDL_GL_DeleteContext(c);
SDL_DestroyWindow(w);
SDL_Quit();
return 0;
}

顶点着色器(vs.glsl):

#version 450 core

layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 tcol;
layout (location = 2) uniform mat3 x;
layout (location = 3) uniform mat3 y;
layout (location = 4) uniform mat3 z;
layout (location = 5) uniform vec3 c;

out vec3 col;

void main() {
vec3 d = x * y * z * (pos - c);
gl_Position.x = d.x / d.z;
gl_Position.y = d.y / d.z;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
col = tcol;
}

片段着色器:

#version 450 core

out vec4 color;

in vec3 col;

void main() {
color = vec4(col, 1.0);
}

我认为 keys.h 和 utils.h 不应该在这里,因为它们与 OpenGL 无关。这是一个最小可重现示例,因为管理关键数据和加载着色器分别需要额外的部分(keys.h 和 utils.h)。

我的代码中的某些键可能被反转,这在所有方面都是糟糕的代码......抱歉。

这是我在移动立方体(或准确的相机视角)后拍摄的图像。需要注意的一件主要事情是,除了轨迹之外,它似乎工作得很好。

回答

您还需要清除颜色缓冲区:

glClear(GL_DEPTH_BUFFER_BIT);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glClear清除指定的缓冲区。缓冲区用位掩码指定。GL_COLOR_BUFFER_BIT表示清除当前启用的彩色写入缓冲区。


以上是为什么OpenGL中的3D投影可以工作,但会留下痕迹?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>