OPENGL: Как реализовать единую переменную для достижения эффекта затухания?

Текущее состояние:

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);
}

0

Решение

Вы должны контролировать замирание в коде хоста и передавать состояние шейдерам во время выполнения. Поскольку вы используете 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*/
}

Еще одна вещь, которую я собираюсь порекомендовать, это то, что вы делаете смешивание вручную в шейдере [фрагмента], а не автоматически, используя смешивание 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 значение, чтобы выбрать, какой из цветов использовать. Используя эту функцию, вы можете установить цвет «исчезать», чтобы быть тем, что вы хотите.

#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);
}

Если вы действительно хотите, чтобы объект был прозрачным при замирании (как обычно используется альфа-параметр), то вы можете использовать тот же код хоста, который я предоставил, с дополнительным вызовом функции в коде установки:

glEnable(GL_BLEND);

И тогда вы можете использовать свой оригинальный код Fragment Shader. Единственное ограничение заключается в том, что если вы сделаете это (как и любой рендеринг с использованием прозрачности), упорядочивание вызовов отрисовки становится чрезвычайно важным. Я бы посоветовал вам поискать учебники о том, как сделать прозрачность с помощью альфа-смешивания, так как углубиться в этот вопрос выходит за рамки этого вопроса.

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector