Я пытаюсь сделать систему частиц с помощью OpenGL 3 с помощью точечного спрайта.Тест глубины с точным спрайтом в OpenGL
Я использую VBO с GL_STREAM_DRAW, где я помещаю координату каждой частицы. Во время каждого кадра я обновляю VBO с новой координатой частиц. Частица просто отображается GL_POINTS, используя GL_VERTEX_PROGRAM_POINT_SIZE.
Я заметил, что некоторые частицы, наложенные другим, несмотря на то, что они должны были быть ближе к камере.
Точка спрайт фактически обращается порядка вызова отрисовки и не глубиной, которые создают ситуацию так:
Здесь дальняя частица рисуется первым, частица закрывается рисуется второй. Как и ожидалось, частицы шкафа полностью покрывают ту, которая находится за ней.
Здесь порядок дро восстанавливается в результате самой дальней частицы будут видимы.
Я пытаюсь с помощью тестирования глубины OpenGL с использованием
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.f, 1.f);
glEnable(GL_DEPTH_CLAMP);
Но это только в результате ничего не втягиваются.
Как я понимаю, одним из способов решения этой проблемы является переупорядочивание частиц по глубине, но это решение было бы очень дорогостоящим для процессора для многих частиц, поэтому есть способ провести надлежащее тестирование глубины для точечного спрайта на GPU?
Использование шейдера вершин для рисования частицы состоит в следующем:
#version 330
layout(location = 0) in vec4 position;
uniform float time;
uniform mat4 camera;
smooth out float dist;
void main()
{
vec4 cameraPos = position + vec4(0.0, 0.0, -1.0, 0.0);
gl_Position = camera * cameraPos;
dist = sqrt(dot(camera * cameraPos, position));
gl_PointSize = 15.0/dist;
}
фрагмент шейдера:
#version 330
out vec4 colour;
uniform float time;
smooth in float dist;
float map(float value, float inMin, float inMax, float outMin, float outMax) {
return outMin + (outMax - outMin) * (value - inMin)/(inMax - inMin);
}
void main()
{
// colour = vec4(pos.x, pos.y, 1.0, 1.0);
if(dot(gl_PointCoord-0.5,gl_PointCoord-0.5)>0.25)
discard;
else {
float g = (dot(gl_PointCoord-0.5,gl_PointCoord-0.5) > 0.22 ? 0.6 : map(dot(gl_PointCoord-0.5,gl_PointCoord-0.5), 0.0, 0.21, 0.0, 0.6));
colour = vec4(g, g*sin(time)*sin(time)*cos(time), sin(dist), 1.0);
}
}
Полный код (минус некоторые шаблонный код):
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/trigonometric.hpp>
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
#include <random>
#include <cmath>
#include "tools.h"
#include "shader.h"
#include "data.h"
#define BENCHMARK 230000
#define MAX_POINT 2
#define TTL 100
void init_program(GLuint* program)
{
std::vector<GLuint> shaders;
shaders.push_back(create_shader(GL_VERTEX_SHADER, read_file("data/particle.vs")));
shaders.push_back(create_shader(GL_FRAGMENT_SHADER, read_file("data/particle.fs")));
*program = create_program(shaders);
std::for_each(shaders.begin(), shaders.end(), glDeleteShader);
}
bool first=true;
void create_new_point(Point* p)
{
// Testing draw order
if(first)
p->pos = glm::vec4(0.f, 0.f, 0.f, 1.f);
else
p->pos = glm::vec4(0.f, 0.f, 0.8, 1.f);
p->dir = glm::vec4(0.f, 0.f, 0.f, 0.f);
p->ttl = TTL+(TTL*(distrib(gen)/2.0));
first = false;
}
void update_point(Point* p, double dt)
{
if((p->ttl - dt) <= 0)
create_new_point(p);
else
{
glm::vec4 speed(dt/2.0);
p->pos += (p->dir*speed);
p->ttl = p->ttl - dt;
}
}
void vbo_point(std::vector<Point>& points, float* data, GLuint* vbo, bool update)
{
for(size_t n=0; n<points.size(); ++n)
{
if(update)
{
data[n*4] = points[n].pos.x;
data[n*4+1] = points[n].pos.y;
data[n*4+2] = points[n].pos.z;
data[n*4+3] = points[n].pos.w;
}
else
{
data[n*4] = 0;
data[n*4+1] = 0;
data[n*4+2] = 0;
data[n*4+3] = 0;
}
}
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
if(update)
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*points.size(), data);
else
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*points.size(), data, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
int main(void)
{
GLFWwindow* window;
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
window = glfwCreateWindow(1280, 768, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
// Init data
GLuint vbo, vao, program;
glGenBuffers(1, &vbo);
init_program(&program);
// VAO
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
/*
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.f, 1.f);
glEnable(GL_DEPTH_CLAMP);
glEnable(GL_BLEND) ;
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
*/
// Time data
double prev = 0.0;
double curr = 0.0;
double frameTime = 0.0;
// Init Points
std::vector<Point> points;
for(size_t n=0; n<MAX_POINT; ++n)
{
Point tmp = {glm::vec4(0), glm::vec4(0), 0};
points.push_back(tmp);
}
float* data = new float[4*points.size()];
for(size_t n=0; n<points.size(); ++n)
update_point(&points[n], 0);
vbo_point(points, data, &vbo, false);
glfwSwapInterval(1);
GLint time = glGetUniformLocation(program, "time");
GLint camera_location = glGetUniformLocation(program, "camera");
glm::mat4 camera_matrix = glm::perspective(glm::radians(45.f), 1.33f, 0.1f, 10.f);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
curr = glfwGetTime();
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.f, 1.f, 1.f, 0.f);
glUseProgram(program);
glUniform1f(time, glfwGetTime());
glUniformMatrix4fv(camera_location, 1, GL_FALSE, glm::value_ptr(camera_matrix));
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_POINTS, 0, points.size());
glDisableVertexAttribArray(0);
glUseProgram(0);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
for(size_t n=0; n<points.size(); ++n)
update_point(&points[n], frameTime);
vbo_point(points, data, &vbo, true);
std::cout << std::fixed;
std::cout.precision(8);
std::cout << "\rfps: " << 1.f/frameTime << " | Point drawed :" << points.size()
<< " | TTL1: " << points[0].ttl;
prev = glfwGetTime();
frameTime = prev-curr;
}
delete[] data;
glfwTerminate();
return 0;
}
Просьба указать код –
Извините, я нажимаю tab + введите ошибку, прежде чем оставлять полный вопрос. Вы можете увидеть обновление сейчас. – Maeln
Как вы рисуете? Как настроена ваша матрица? Любые шейдеры? Или вы используете конвейер с фиксированной функцией? –