OPENGL:如何实现均匀变量以实现淡入淡出效果?

时间:2017-08-01 15:56:27

标签: c++ opengl glsl fragment-shader fading

当前状态:

img

我想要实现的是在第二个立方体/模型矩阵上创建一个渐变效果(周期性的黑色到全彩色),而不会改变任何全局顶点。到目前为止我收集的是需要在片段着色器中声明一个统一变量并使用浮点值。我已经添加到片段着色器:

uniform float uAlpha;

void main()
{
    // set output color
    fColor = vec4(vColor, uAlpha);
}

我不知道我的源代码下一步该做什么。添加一些内容吗?

GLuint g_uAlpha = glGetUniformLocation(g_shaderProgramID, "uAlpha");
vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
GLfloat alpha = color.a;
glUniform1fv(g_uAlpha, 1, &alpha);

它确实没有做我知道的任何事情。我真的对如何实现这一点毫无头绪,我希望有人可以解决这个问题,谢谢。

源代码:

#include <cstdio>
#include <iostream>
#include <cstddef>
#include <Windows.h>
#include <time.h>
using namespace std;

#define GLEW_STATIC
#include <GLEW/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>

#include "shader.h"
#include "Camera.h"

struct Vertex
{
    GLfloat position[3];
    GLfloat color[3];
};

Vertex g_vertices[] = {
// vertex 1
-0.2f, 0.2f, 0.2f,
1.0f, 0.0f, 1.0f,

// vertex 2
-0.2f, -0.2f, 0.2f,
1.0f, 0.0f, 0.0f,

// vertex 3
0.2f, 0.2f, 0.2f,
1.0f, 1.0f, 1.0f,

// vertex 4
0.2f, -0.2f, 0.2f,
1.0f, 1.0f, 0.0f,

// vertex 5
-0.2f, 0.2f, -0.2f,
0.0f, 0.0f, 1.0f,

// vertex 6
-0.2f, -0.2f, -0.2f,
0.0f, 0.0f, 0.0f,

// vertex 7
0.2f, 0.2f, -0.2f,
0.0f, 1.0f, 1.0f,

// vertex 8
0.2f, -0.2f, -0.2f,
0.0f, 1.0f, 0.0f,
};

GLuint g_indices[] = {
    0, 1, 2,
    2, 1, 3,
    4, 5, 0,
    0, 5, 1,
    2, 3, 6,
    6, 3, 7,
    4, 0, 6,
    6, 0, 2,
    1, 5, 3,
    3, 5, 7,
    5, 4, 7,
    7, 4, 6,
};

GLuint g_IBO[1];
GLuint g_VBO[1];
GLuint g_VAO[1];
GLuint g_shaderProgramID = 0;
GLuint g_MVP_Index = 0;
mat4 g_modelMatrix[2];
mat4 g_viewMatrix;
mat4 g_projectionMatrix;
Camera g_camera;

static void init(GLFWwindow* window)
{
    srand(time(NULL));

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glEnable(GL_DEPTH_TEST);
    g_shaderProgramID = loadShaders("Vertex_Shader.vert", "Fragment_Shader.frag");
    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);

    // find the location of shader variables
    GLuint positionIndex = glGetAttribLocation(g_shaderProgramID, "aPosition");
    GLuint colorIndex = glGetAttribLocation(g_shaderProgramID, "aColor");
    g_MVP_Index = glGetUniformLocation(g_shaderProgramID, "uModelViewProjectionMatrix");

    // initialise model matrix to the identity matrix
    g_modelMatrix[0] = mat4(1.0f);
    g_modelMatrix[1] = mat4(1.0f);

    // set camera's view matrix
    g_camera.setViewMatrix(vec3(0, 1, 5), vec3(0, 0, 2), vec3(0, 1, 0));

    // get the framebuffer width and height in order to calculate the aspect ratio
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    float aspectRatio = static_cast<float>(width) / height;

    // initialise the projection matrix
    g_camera.setProjectionMatrix(perspective(45.0f, aspectRatio, 0.1f, 100.0f));

    glGenBuffers(1, g_VBO);
    glGenVertexArrays(1, g_VAO);
    glGenBuffers(1, g_IBO);

    // draw cubes
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);

    glBindVertexArray(g_VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_IBO[0]);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(colorIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, color)));

    glEnableVertexAttribArray(positionIndex);
    glEnableVertexAttribArray(colorIndex);
}

static void render_scene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glUseProgram(g_shaderProgramID);

    glBindVertexArray(g_VAO[0]);
    mat4 MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[0];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

    mat4 MVP1 = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_modelMatrix[1];
    glUniformMatrix4fv(g_MVP_Index, 1, GL_FALSE, &MVP1[0][0]);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

    glFlush();
}

static void update_scene(GLFWwindow* window)
{
    g_modelMatrix[1] = glm::translate(glm::vec3(1.0f, 0.0f, 0.0f));
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, GL_TRUE);
        return;
    }
}

int main(void)
{
    GLFWwindow* window = NULL;

    if (!glfwInit())
    {
        exit(EXIT_FAILURE);
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

    window = glfwCreateWindow(1028, 768, "Test", NULL, NULL);

    if (window == NULL)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    if (glewInit() != GLEW_OK)
    {
        cerr << "GLEW initialisation failed" << endl;
        exit(EXIT_FAILURE);
    }

    glfwSetKeyCallback(window, key_callback);
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
    init(window);

    float lastUpdateTime = glfwGetTime();
    float currentTime = lastUpdateTime;

    // rendering loop
    while (!glfwWindowShouldClose(window))
    {
        currentTime = glfwGetTime();

        if (currentTime - lastUpdateTime > 0.02)
        {
            g_camera.update(window);
            update_scene(window);
            render_scene();

            glfwSwapBuffers(window);
            glfwPollEvents();
            lastUpdateTime = currentTime;
        }
    }

    // clean up
    glDeleteProgram(g_shaderProgramID);
    glDeleteBuffers(1, g_IBO);
    glDeleteBuffers(1, g_VBO);
    glDeleteVertexArrays(1, g_VAO);

    // close the window and terminate GLFW
    glfwDestroyWindow(window);
    glfwTerminate();

    exit(EXIT_SUCCESS);
}

Camera.h

#ifndef __CAMERA_H
#define __CAMERA_H

#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp>  // include GLM (ideally should only use the GLM headers that are actually used)
#include <glm/gtx/transform.hpp>
#include <glm/gtx/rotate_vector.hpp>
using namespace glm;    // to avoid having to use glm::

#define MOVEMENT_SENSITIVITY 0.05f      // camera movement sensitivity
#define ROTATION_SENSITIVITY 0.05f      // camera rotation sensitivity

class Camera {
public:
    Camera();
    ~Camera();

    void update(GLFWwindow* window);
    void updateYaw(float yaw);
    void updatePitch(float pitch);
    void setViewMatrix(glm::vec3 position, glm::vec3 lookAt, glm::vec3 up);
    void setProjectionMatrix(glm::mat4& matrix);
    glm::mat4 getViewMatrix();
    glm::mat4 getProjectionMatrix();

private:
    float mYaw;
    float mPitch;
    glm::vec3 mPosition;
    glm::vec3 mLookAt;
    glm::vec3 mUp;
    glm::mat4 mViewMatrix;
    glm::mat4 mProjectionMatrix;
};

#endif

Camera.cpp

#include "Camera.h"

Camera::Camera()
{
    // initialise camera member variables
    mPosition = glm::vec3(0.0f, 0.0f, 1.0f);
    mLookAt = glm::vec3(0.0f, 0.0f, 0.0f);
    mUp = glm::vec3(0.0f, 1.0f, 0.0f);

    mYaw = 0.0f;
    mPitch = 0.0f;

    mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
    mProjectionMatrix = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f);
}

Camera::~Camera()
{}

void Camera::update(GLFWwindow* window)
{
    // variables to store forward/back and strafe movement
    float moveForward = 0;
    float strafeRight = 0;

    // update variables based on keyboard input
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        moveForward += MOVEMENT_SENSITIVITY;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        moveForward -= MOVEMENT_SENSITIVITY;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        strafeRight -= MOVEMENT_SENSITIVITY;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        strafeRight += MOVEMENT_SENSITIVITY;

    // rotate the respective unit vectors about the y-axis
    glm::vec3 rotatedForwardVec = glm::rotateY(glm::vec3(0.0f, 0.0f, -1.0f), mYaw);
    glm::vec3 rotatedRightVec = glm::rotateY(glm::vec3(1.0f, 0.0f, 0.0f), mYaw);
    // rotate the rotated forward vector about the rotated right vector
    rotatedForwardVec = glm::vec3(glm::rotate(mPitch, rotatedRightVec)*glm::vec4(rotatedForwardVec, 0.0f));

    // update position, look-at and up vectors
    mPosition += rotatedForwardVec * moveForward + rotatedRightVec * strafeRight;
    mLookAt = mPosition + rotatedForwardVec;
    mUp = glm::cross(rotatedRightVec, rotatedForwardVec);   // cross product

    // compute the new view matrix
    mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
}

void Camera::updateYaw(float yaw)
{
    mYaw -= yaw * ROTATION_SENSITIVITY;
}

void Camera::updatePitch(float pitch)
{
    mPitch -= pitch * ROTATION_SENSITIVITY;
}

void Camera::setViewMatrix(glm::vec3 position, glm::vec3 lookAt, glm::vec3 up)
{
    mPosition = position;
    mLookAt = lookAt;
    mUp = up;

    mViewMatrix = glm::lookAt(mPosition, mLookAt, mUp);
}

void Camera::setProjectionMatrix(glm::mat4& matrix)
{
    mProjectionMatrix = matrix;
}

glm::mat4 Camera::getViewMatrix()
{
    return mViewMatrix;
}

glm::mat4 Camera::getProjectionMatrix()
{
    return mProjectionMatrix;
}

顶点着色器

#version 330 core

// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aColor;

// ModelViewProjection matrix
uniform mat4 uModelViewProjectionMatrix;

// output data (will be interpolated for each fragment)
out vec3 vColor;

void main()
{
    // set vertex position
    gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);

    // the color of each vertex will be interpolated
    // to produce the color of each fragment

    vColor = aColor;
}

片段着色器

#version 330 core

// interpolated values from the vertex shaders
in vec3 vColor;

// output data
out vec4 fColor;

uniform float uAlpha;

void main()
{
    // set output color
    fColor = vec4(vColor, uAlpha);
}

1 个答案:

答案 0 :(得分:2)

您需要控制主机代码中的淡入淡出,并在运行时将状态传递给着色器[s]。由于您使用GLFW作为窗口管理器,因此相对简单:

while(!glfwWindowShouldClose(window)) {
    glfwPollEvents();
    constexpr float factor = 30; //Higher == faster fade, lower == slower fade
    float alpha = (float(std::sin(glfwGetTime() * factor) + 1) / 2; //Generates a Sine Wave in range [0, 1].
    //float alpha = float(glfwGetTime() * factor - std::floor(glfwGetTime() * factor); //Sawtooth fade
    glUniform1f(glGetUniformLocation(g_shaderProgramID, "uAlpha"), alpha);
    update_scene(window);
    render_scene();
    /*Whatever else needs to happen*/
}

我要推荐的另一件事是你在[fragment]着色器中手动进行混合,而不是自动使用OpenGL混合。

#version 330 core

// interpolated values from the vertex shaders
in vec3 vColor;

// output data
out vec4 fColor;

uniform float uAlpha;

void main()
{
    // set output color
    vec4 fade_color = vec4(0,0,0,1); //Black fade
    fColor = mix(vec4(vcolor, 1), fade_color, uAlpha);
}

GLSL函数mix将使用float值将两个向量混合在一起,以选择要使用的颜色中的颜色。使用此功能,您可以设置&#34; fade&#34;颜色是你想要的任何东西。

#version 330 core

// interpolated values from the vertex shaders
in vec3 vColor;

// output data
out vec4 fColor;

uniform float uAlpha;
uniform vec4 fade_color;

void main()
{
    // set output color
    fColor = mix(vec4(vcolor, 1), fade_color, uAlpha);
}

如果你确实想要在淡入淡出时透明对象(通常使用alpha参数),那么你可以使用我提供的相同主机代码,并在设置代码中添加一个函数调用:

glEnable(GL_BLEND);

然后您可以使用原始的片段着色器代码。唯一的限制是,如果你这样做(就像任何涉及透明度的渲染一样),绘制调用的顺序变得非常重要。我建议你四处寻找有关如何使用alpha-blending进行透明度的教程,因为深入了解这个问题超出了这个问题的范围。