OpenGL 中的镜面闪电伪影问题

问题描述 投票:0回答:1

问题出在我观察房间的角落时。 当我这样做时,镜面闪电会变得更亮:

looking to a corner

...当我看到平坦的墙壁时却没有:

looking straight to a wall

我在这里发布完整的代码:

#include <windows.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>

#define GLEW_STATIC
#include <glew.h>
#include <GL/glfw.h>

template <typename T>
T clamp(T value, T min, T max) {
    if (value < min) return min;
    if (value > max) return max;
    return value;
}

// CAMERA PROPERTIES
float posX = 0.0f, posY = 0.0f, posZ = 5.0f; // position
float rotX = 0.0f, rotY = 3.0f;              // rotation

// movement speed and mouse sensitivity
float speed = 0.05f;
const float mouseSensitivity = 0.005f;

// MOUSE INPUT TRACKING
double lastMouseX, lastMouseY;

// ROOM BOUNDARIES
float x_min = -5.0f, x_max = 5.0f;
float z_min = -5.0f, z_max = 5.0f;
float collision = 0.2f;

void checkCollision(float &posX, float &posZ) {
    if (posX < x_min + collision) posX = x_min + collision; // left
    if (posX > x_max - collision) posX = x_max - collision; // right
    if (posZ < z_min + collision) posZ = z_min + collision; // back
    if (posZ > z_max - collision) posZ = z_max - collision; // front
}

void drawLightMarker() {
    glDisable(GL_LIGHTING);
    glColor3f(1.0f, 1.0f, 0.0f);
    glPushMatrix();
    glTranslatef(0.0f, 0.5f, 0.0f);

    glBegin(GL_QUADS);

    // FRONT FACE
    glVertex3f(-0.1f, -0.1f, 0.1f);
    glVertex3f(0.1f, -0.1f, 0.1f);
    glVertex3f(0.1f, 0.1f, 0.1f);
    glVertex3f(-0.1f, 0.1f, 0.1f);

    // BACK FACE
    glVertex3f(-0.1f, -0.1f, -0.1f);
    glVertex3f(0.1f, -0.1f, -0.1f);
    glVertex3f(0.1f, 0.1f, -0.1f);
    glVertex3f(-0.1f, 0.1f, -0.1f);

    // LEFT FACE
    glVertex3f(-0.1f, -0.1f, -0.1f);
    glVertex3f(-0.1f, -0.1f, 0.1f);
    glVertex3f(-0.1f, 0.1f, 0.1f);
    glVertex3f(-0.1f, 0.1f, -0.1f);

    // RIGHT FACE
    glVertex3f(0.1f, -0.1f, -0.1f);
    glVertex3f(0.1f, -0.1f, 0.1f);
    glVertex3f(0.1f, 0.1f, 0.1f);
    glVertex3f(0.1f, 0.1f, -0.1f);

    // TOP FACE
    glVertex3f(-0.1f, 0.1f, 0.1f);
    glVertex3f(0.1f, 0.1f, 0.1f);
    glVertex3f(0.1f, 0.1f, 0.1f);
    glVertex3f(-0.1f, 0.1f, 0.1f);

    // BOTTOM FACE
    glVertex3f(-0.1f, -0.1f, -0.1f);
    glVertex3f(0.1f, -0.1f, -0.1f);
    glVertex3f(0.1f, -0.1f, 0.1f);
    glVertex3f(-0.1f, -0.1f, 0.1f);

    glEnd();
    glPopMatrix();
    glEnable(GL_LIGHTING);
}

// ********TO FIX********
void setupLightning() {
    // PROPERTIES
    GLfloat ambient[] = {0.0f, 0.0f, 0.0f, 1.0f};
    GLfloat diffuse[] = {2.0f, 2.0f, 2.0f, 1.0f};
    GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat mat_specular[] = {0.5f, 0.5f, 0.5f, 1.0f};
    GLfloat shininess[] = {20.0f};

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);

    glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, shininess);

    // ATTENUATION
    glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.5f);
    glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.1f);
    glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.01f);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_NORMALIZE);
}

void processInput(GLFWwindow *window) {
    // FORWARD/BACKWARD MOVEMENT
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
        posX += speed * sin(rotY);
        posZ += speed * cos(rotY);
    }

    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
        posX -= speed * sin(rotY);
        posZ -= speed * cos(rotY);
    }

    // LEFT/RIGHT STRAFING
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
        posX += speed * cos(rotY);
        posZ -= speed * sin(rotY);
    }

    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
        posX -= speed * cos(rotY);
        posZ += speed * sin(rotY);
    }

    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwDestroyWindow(window);
        glfwTerminate();
    }

    if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) speed = 0.5f;

    if (glfwGetKey(window, GLFW_KEY_BACKSPACE) == GLFW_PRESS) speed = 0.05f;
    //checkCollision(posX, posZ);
}

void mouseCallback(GLFWwindow* window, double xpos, double ypos) {
    // calculate mouse delta
    double deltaX = xpos - lastMouseX;
    double deltaY = ypos - lastMouseY;
    lastMouseX = xpos;
    lastMouseY = ypos;

    // UPDATE ROTATION
    rotY -= deltaX * mouseSensitivity; // Horizontal rotation
    rotX -= deltaY * mouseSensitivity; // Vertical rotation

    rotX = clamp(rotX, -1.5f, 1.5f);
}

void renderRoom() {
    glBegin(GL_QUADS);

    // FLOOR
    glColor3f(0.5f, 0.5f, 0.5f);
    glNormal3f(0.0f, 1.0f, 0.0f);

    glVertex3f(-5.0f, -1.0f, -5.0f);
    glVertex3f(5.0f, -1.0f, -5.0f);
    glVertex3f(5.0f, -1.0f, 5.0f);
    glVertex3f(-5.0f, -1.0f, 5.0f);

    // CEILING
    glColor3f(0.3f, 0.3f, 0.3f);
    glNormal3f(0.0f, -1.0f, 0.0f);

    glVertex3f(-5.0f, 1.0f, -5.0f);
    glVertex3f(5.0f, 1.0f, -5.0f);
    glVertex3f(5.0f, 1.0f, 5.0f);
    glVertex3f(-5.0f, 1.0f, 5.0f);

    // WALLS

    // back wall
    glColor3f(0.8f, 0.2f, 0.2f);
    glNormal3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-5.0f, -1.0f, -5.0f);
    glVertex3f(5.0f, -1.0f, -5.0f);
    glVertex3f(5.0f, 1.0f, -5.0f);
    glVertex3f(-5.0f, 1.0f, -5.0f);

    // front wall
    glNormal3f(0.0f, 0.0f, -1.0f);
    glVertex3f(-5.0f, -1.0f, 5.0f);
    glVertex3f(5.0f, -1.0f, 5.0f);
    glVertex3f(5.0f, 1.0f, 5.0f);
    glVertex3f(-5.0f, 1.0f, 5.0f);

    // left wall
    glNormal3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-5.0f, -1.0f, -5.0f);
    glVertex3f(-5.0f, -1.0f, 5.0f);
    glVertex3f(-5.0f, 1.0f, 5.0f);
    glVertex3f(-5.0f, 1.0f, -5.0f);

    // right wall
    glNormal3f(-1.0f, 0.0f, 0.0f);
    glVertex3f(5.0f, -1.0f, -5.0f);
    glVertex3f(5.0f, -1.0f, 5.0f);
    glVertex3f(5.0f, 1.0f, 5.0f);
    glVertex3f(5.0f, 1.0f, -5.0f);

    glEnd();
}

GLFWwindow* initWindowFullScreen() {
    // INITIALIZE GLFW
    if (!glfwInit()) std::cerr << "Failed to initialize GLFW" << std::endl;

    GLFWmonitor* monitor = glfwGetPrimaryMonitor();
    if (!monitor) {
        glfwTerminate();
        std::cerr << "Failed to get primary monitor" << std::endl;
    }

    const GLFWvidmode* mode = glfwGetVideoMode(monitor);

    GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "3D Room full-screen", monitor, NULL);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window);

    return window;
}

int main() {
    GLFWwindow* window = initWindowFullScreen();

    // MOUSE CALLBACK
    glfwSetCursorPosCallback(window, mouseCallback);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    glfwGetCursorPos(window, &lastMouseX, &lastMouseY);

    setupLightning();

    // MAIN LOOP
    while (!glfwWindowShouldClose(window)) {
        processInput(window);

        // RENDERING
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(70.0, 800.0 / 600.0, 0.1, 100.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // APPLY CAMERA TRANSFORMATIONS
        float lookX = posX + sin(rotY) * cos(rotX);
        float lookY = posY + sin(rotX);
        float lookZ = posZ + cos(rotY) * cos(rotX);
        gluLookAt(posX, posY, posZ, lookX, lookY, lookZ, 0.0f, 1.0f, 0.0f);

        GLfloat lightPos[] = {0.0f, 0.5f, 0.0f, 1.0f};
        glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

        renderRoom();
        drawLightMarker();

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

我尝试修改镜面反射、环境光、漫反射闪电,但没有任何效果。

c++ windows opengl glfw lighting
1个回答
0
投票

在您使用的平滑着色模式中,三角形的片段是根据顶点的属性进行插值的。

所以,假设你有一个三角形:

v0 --- v1
|   /
v2

现在照明效果的镜面反射贡献是根据

v0
v1
v2
计算的。当渲染三角形时,所有填充三角形的区域都会被插值。要查看镜面反射贡献,光线需要击中某些顶点 v0、v1、v2。在你的场景中很难满足,因为光的位置是(0,0,0),盒子的每个面都有4个顶点,边长是10。

-------------
|
|
|     (L)        -> L is position of light
|
|
(Y)------------

Y 是相机的位置。镜面效果基于光线照射到盒子表面时视图方向和反射矢量之间的角度。如上所示,以盒子的左面为例,沿着 L 和 Y 之间的距离,您需要更多顶点。

Fixed

上面的视图是在 X 轴和 Z 轴上将地板渲染为 [-5,5] 范围内的 100 个四边形时创建的。因此 dx 和 dy 偏移量为 1。左脸以 dz = 1 和 dy = 0.2 偏移量渲染(也是 100 个四边形)。

因此,作为结论,您需要使几何体更密集,才能看到光照效果。在地板上可以看到镜面效果。在左脸上我们看到漫反射效果。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.