我正在尝试使用点精灵来使用OpenGL 3做粒子系统。在OpenGL中使用点精灵进行深度测试
我使用了一个带GL_STREAM_DRAW的VBO,我在其中放置了每个粒子的坐标。 在每个帧中,我用新的粒子坐标更新VBO。使用GL_VERTEX_PROGRAM_POINT_SIZE简单地使用GL_POINTS呈现粒子。
我注意到有些颗粒被其他颗粒覆盖,尽管事实上它们应该更接近相机。
点精灵实际上是由绘制调用的顺序而不是深度绘制,这创造这样的情况:
这里最远的颗粒在第一次绘制时,关闭粒子被吸入第二。正如所料,壁橱里的微粒完全覆盖了它后面的一个。
这里,绘制顺序被反转,导致最远颗粒是可见的。
我请尝试使用
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.f, 1.f);
glEnable(GL_DEPTH_CLAMP);
OpenGL的深度测试,但它只是导致没有被绘制。
据我所知,解决这个问题的一种方法是按照深度对粒子进行重新排序,但这种解决方案对于许多粒子来说CPU会非常昂贵,所以有办法对点精灵进行适当的深度测试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
你最近怎么画?你的矩阵是如何设置的?任何着色器?或者你在使用固定功能流水线吗? –