lightpreview: preliminary vis culling

- q2 only
- not handling bmodels properly
This commit is contained in:
Eric Wasylishen 2023-07-24 00:50:46 -06:00
parent 07020ceeae
commit edb664f200
2 changed files with 220 additions and 4 deletions

View File

@ -79,6 +79,7 @@ GLView::~GLView()
placeholder_texture.reset();
lightmap_texture.reset();
face_visibility_texture.reset();
m_drawcalls.clear();
doneCurrent();
@ -121,10 +122,24 @@ static const char *s_vertShader_Wireframe = R"(
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 6) in int face_index;
uniform mat4 MVP;
uniform usampler1D face_visibility_sampler;
bool is_culled() {
int byte_index = face_index;
uint sampled = texelFetch(face_visibility_sampler, byte_index, 0).r;
return sampled != 16u;
}
void main() {
if (is_culled()) {
gl_Position = vec4(0.0);
return;
}
gl_Position = MVP * vec4(position, 1.0);
}
)";
@ -193,6 +208,7 @@ layout (location = 2) in vec2 vertex_lightmap_uv;
layout (location = 3) in vec3 vertex_normal;
layout (location = 4) in vec3 vertex_flat_color;
layout (location = 5) in uint vertex_styles;
layout (location = 6) in int face_index;
out vec2 uv;
out vec2 lightmap_uv;
@ -201,8 +217,22 @@ flat out vec3 flat_color;
flat out uint styles;
uniform mat4 MVP;
uniform usampler1D face_visibility_sampler;
bool is_culled() {
int byte_index = face_index;
uint sampled = texelFetch(face_visibility_sampler, byte_index, 0).r;
return sampled != 16u;
}
void main() {
if (is_culled()) {
gl_Position = vec4(0.0);
return;
}
gl_Position = MVP * vec4(position.x, position.y, position.z, 1.0);
uv = vertex_uv;
@ -277,6 +307,7 @@ layout (location = 2) in vec2 vertex_lightmap_uv;
layout (location = 3) in vec3 vertex_normal;
layout (location = 4) in vec3 vertex_flat_color;
layout (location = 5) in uint vertex_styles;
layout (location = 6) in int face_index;
out vec3 fragment_world_pos;
out vec2 lightmap_uv;
@ -286,8 +317,22 @@ flat out uint styles;
uniform mat4 MVP;
uniform vec3 eye_origin;
uniform usampler1D face_visibility_sampler;
bool is_culled() {
int byte_index = face_index;
uint sampled = texelFetch(face_visibility_sampler, byte_index, 0).r;
return sampled != 16u;
}
void main() {
if (is_culled()) {
gl_Position = vec4(0.0);
return;
}
gl_Position = MVP * vec4(position, 1.0);
fragment_world_pos = position;
@ -298,6 +343,72 @@ void main() {
}
)";
void GLView::updateFaceVisibility()
{
if (!m_bsp)
return;
const mbsp_t &bsp = *m_bsp;
const auto &world = bsp.dmodels.at(0);
auto *leaf = BSP_FindLeafAtPoint(&bsp, &world, qvec3d{m_cameraOrigin.x(), m_cameraOrigin.y(), m_cameraOrigin.z()});
int leafnum = leaf - bsp.dleafs.data();
int clusternum = leaf->cluster;
if (m_lastLeaf == clusternum) {
qDebug() << "reusing last frame visdata for leaf " << leafnum << " cluster " << clusternum;
return;
}
qDebug() << "looking up pvs for clusternum " << clusternum;
auto it = m_decompressedVis.find(clusternum);
if (it == m_decompressedVis.end()) {
qDebug() << "no visdata, must be in void";
m_lastLeaf = clusternum;
setFaceVisibilityToAllVisible();
return;
}
Q_assert(it != m_decompressedVis.end());
const auto &pvs = it->second;
qDebug() << "found bitvec of size " << pvs.size();
// check leaf visibility
auto leaf_sees = [&](const mleaf_t *b) -> bool {
if (b->cluster < 0)
return true;
return !!(pvs[b->cluster >> 3] & (1 << (b->cluster & 7)));
};
const int face_visibility_width = m_bsp->dfaces.size();
std::vector<uint8_t> face_flags;
face_flags.resize(face_visibility_width, 0);
// check all leafs
// FIXME: only world?
for (auto &leaf : bsp.dleafs) {
if (leaf_sees(&leaf)) {
for (int ms = 0; ms < leaf.nummarksurfaces; ++ms) {
int fnum = bsp.dleaffaces[leaf.firstmarksurface + ms];
face_flags[fnum] = 16;
}
}
}
setFaceVisibilityArray(face_flags.data());
m_lastLeaf = clusternum;
}
bool GLView::shouldLiveUpdate() const
{
if (m_keysPressed)
@ -357,6 +468,7 @@ void GLView::initializeGL()
m_program_mvp_location = m_program->uniformLocation("MVP");
m_program_texture_sampler_location = m_program->uniformLocation("texture_sampler");
m_program_lightmap_sampler_location = m_program->uniformLocation("lightmap_sampler");
m_program_face_visibility_sampler_location = m_program->uniformLocation("face_visibility_sampler");
m_program_opacity_location = m_program->uniformLocation("opacity");
m_program_alpha_test_location = m_program->uniformLocation("alpha_test");
m_program_lightmap_only_location = m_program->uniformLocation("lightmap_only");
@ -371,6 +483,7 @@ void GLView::initializeGL()
m_skybox_program_eye_direction_location = m_skybox_program->uniformLocation("eye_origin");
m_skybox_program_texture_sampler_location = m_skybox_program->uniformLocation("texture_sampler");
m_skybox_program_lightmap_sampler_location = m_skybox_program->uniformLocation("lightmap_sampler");
m_skybox_program_face_visibility_sampler_location = m_skybox_program->uniformLocation("face_visibility_sampler");
m_skybox_program_opacity_location = m_skybox_program->uniformLocation("opacity");
m_skybox_program_lightmap_only_location = m_skybox_program->uniformLocation("lightmap_only");
m_skybox_program_fullbright_location = m_skybox_program->uniformLocation("fullbright");
@ -381,6 +494,8 @@ void GLView::initializeGL()
m_program_wireframe->bind();
m_program_wireframe_mvp_location = m_program_wireframe->uniformLocation("MVP");
m_program_wireframe_face_visibility_sampler_location =
m_program_wireframe->uniformLocation("face_visibility_sampler");
m_program_wireframe->release();
m_program_simple->bind();
@ -415,6 +530,9 @@ void GLView::paintGL()
applyMouseMotion();
applyFlyMovement(duration_seconds);
// update vis culling if needed
updateFaceVisibility();
// draw
glClearColor(0.1, 0.1, 0.1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -433,6 +551,7 @@ void GLView::paintGL()
m_program->setUniformValue(m_program_mvp_location, MVP);
m_program->setUniformValue(m_program_texture_sampler_location, 0 /* texture unit */);
m_program->setUniformValue(m_program_lightmap_sampler_location, 1 /* texture unit */);
m_program->setUniformValue(m_program_face_visibility_sampler_location, 2 /* texture unit */);
m_program->setUniformValue(m_program_opacity_location, 1.0f);
m_program->setUniformValue(m_program_alpha_test_location, false);
m_program->setUniformValue(m_program_lightmap_only_location, m_lighmapOnly);
@ -445,6 +564,7 @@ void GLView::paintGL()
m_skybox_program->setUniformValue(m_skybox_program_eye_direction_location, m_cameraOrigin);
m_skybox_program->setUniformValue(m_skybox_program_texture_sampler_location, 0 /* texture unit */);
m_skybox_program->setUniformValue(m_skybox_program_lightmap_sampler_location, 1 /* texture unit */);
m_skybox_program->setUniformValue(m_skybox_program_face_visibility_sampler_location, 2 /* texture unit */);
m_skybox_program->setUniformValue(m_skybox_program_opacity_location, 1.0f);
m_skybox_program->setUniformValue(m_skybox_program_lightmap_only_location, m_lighmapOnly);
m_skybox_program->setUniformValue(m_skybox_program_fullbright_location, m_fullbright);
@ -469,6 +589,9 @@ void GLView::paintGL()
draw.texture->bind(0 /* texture unit */);
lightmap_texture->bind(1 /* texture unit */);
if (face_visibility_texture) {
face_visibility_texture->bind(2 /* texture unit */);
}
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
@ -498,6 +621,9 @@ void GLView::paintGL()
draw.texture->bind(0 /* texture unit */);
lightmap_texture->bind(1 /* texture unit */);
if (face_visibility_texture) {
face_visibility_texture->bind(2 /* texture unit */);
}
if (active_program == m_program) {
m_program->setUniformValue(m_program_opacity_location, draw.key.opacity);
@ -520,6 +646,12 @@ void GLView::paintGL()
if (m_showTris || m_showTrisSeeThrough) {
m_program_wireframe->bind();
m_program_wireframe->setUniformValue(m_program_wireframe_mvp_location, MVP);
m_program_wireframe->setUniformValue(
m_program_wireframe_face_visibility_sampler_location, 2 /* texture unit */);
if (face_visibility_texture) {
face_visibility_texture->bind(2 /* texture unit */);
}
if (m_showTrisSeeThrough)
glDisable(GL_DEPTH_TEST);
@ -705,10 +837,55 @@ void GLView::takeScreenshot(QString destPath, int w, int h)
update();
}
void GLView::setFaceVisibilityArray(uint8_t *data)
{
// one byte per face
int face_visibility_width = m_bsp->dfaces.size();
face_visibility_texture.reset();
face_visibility_texture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::Target1D);
face_visibility_texture->setSize(face_visibility_width);
face_visibility_texture->setFormat(QOpenGLTexture::R8U);
face_visibility_texture->setMagnificationFilter(QOpenGLTexture::Nearest);
face_visibility_texture->setMinificationFilter(QOpenGLTexture::Nearest);
face_visibility_texture->allocateStorage();
face_visibility_texture->setData(
0, QOpenGLTexture::Red_Integer, QOpenGLTexture::UInt8, reinterpret_cast<const void *>(data));
logging::print("uploaded {} bytes face visibility texture", face_visibility_width);
}
void GLView::setFaceVisibilityToAllVisible()
{
// one byte per face
int face_visibility_width = m_bsp->dfaces.size();
uint8_t *data = new uint8_t[face_visibility_width];
for (int x = 0; x < face_visibility_width; ++x) {
data[x] = 16;
}
setFaceVisibilityArray(data);
delete[] data;
}
void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries_t &bspx,
const std::vector<entdict_t> &entities, const full_atlas_t &lightmap, const settings::common_settings &settings,
bool use_bspx_normals)
{
// copy the bsp for later use (FIXME: just store a pointer to MainWindow's?)
m_bsp = bsp;
if (bsp.dvis.bits.empty()) {
logging::print("no visdata\n");
m_decompressedVis.clear();
} else {
logging::print("decompressing visdata...\n");
m_decompressedVis = DecompressAllVis(&bsp, true);
}
img::load_textures(&bsp, settings);
std::optional<bspxfacenormals> facenormals;
@ -723,6 +900,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
// clear old data
placeholder_texture.reset();
lightmap_texture.reset();
face_visibility_texture.reset();
m_drawcalls.clear();
m_vbo.bind();
m_vbo.allocate(0);
@ -736,6 +914,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
m_portalIndexBuffer.allocate(0);
num_leak_points = 0;
num_portal_indices = 0;
m_lastLeaf = -1;
int32_t highest_depth = 0;
@ -795,6 +974,11 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
delete[] data;
}
// upload face visibility
if (!bsp.dfaces.empty()) {
setFaceVisibilityToAllVisible();
}
struct face_payload
{
const mface_t *face;
@ -983,6 +1167,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
qvec3f normal;
qvec3f flat_color;
uint32_t styles;
int32_t face_index;
};
std::vector<vertex_t> verts;
std::vector<uint32_t> indexBuffer;
@ -1047,7 +1232,8 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
.normal = vertex_normal,
.flat_color = flat_color,
.styles = (uint32_t)(f->styles[0]) | (uint32_t)(f->styles[1] << 8) |
(uint32_t)(f->styles[2] << 16) | (uint32_t)(f->styles[3] << 24)});
(uint32_t)(f->styles[2] << 16) | (uint32_t)(f->styles[3] << 24),
.face_index = fnum});
}
// output the vertex indices for this face
@ -1123,6 +1309,10 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
glEnableVertexAttribArray(5 /* attrib */);
glVertexAttribIPointer(
5 /* attrib */, 1, GL_UNSIGNED_INT, sizeof(vertex_t), (void *)offsetof(vertex_t, styles));
// face indices
glEnableVertexAttribArray(6 /* attrib */);
glVertexAttribIPointer(6 /* attrib */, 1, GL_INT, sizeof(vertex_t), (void *)offsetof(vertex_t, face_index));
}
// initialize style values

View File

@ -56,6 +56,9 @@ class GLView : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
Q_OBJECT
private:
std::optional<mbsp_t> m_bsp;
std::unordered_map<int, std::vector<uint8_t>> m_decompressedVis;
uint32_t m_keysPressed;
std::optional<time_point> m_lastFrame;
std::optional<QPoint> m_lastMouseDownPos;
@ -64,6 +67,12 @@ private:
*/
float m_moveSpeed;
// vis culling stuff
/**
* -1 indicates solid leaf or no visdata (render all)
*/
int m_lastLeaf = -1;
// camera stuff
float m_displayAspect;
QVector3D m_cameraOrigin;
@ -113,6 +122,14 @@ private:
std::shared_ptr<QOpenGLTexture> placeholder_texture;
std::shared_ptr<QOpenGLTexture> lightmap_texture;
/**
* 1D texture, one uint8 per face.
*
* 0 = render normally
* 1 = skip face
*/
std::shared_ptr<QOpenGLTexture> face_visibility_texture;
struct drawcall_t
{
material_key key;
@ -128,10 +145,11 @@ private:
QOpenGLShaderProgram *m_program_wireframe = nullptr;
QOpenGLShaderProgram *m_program_simple = nullptr;
// uniform locations
// uniform locations (default program)
int m_program_mvp_location = 0;
int m_program_texture_sampler_location = 0;
int m_program_lightmap_sampler_location = 0;
int m_program_face_visibility_sampler_location = 0;
int m_program_opacity_location = 0;
int m_program_alpha_test_location = 0;
int m_program_lightmap_only_location = 0;
@ -140,11 +158,12 @@ private:
int m_program_drawflat_location = 0;
int m_program_style_scalars_location = 0;
// uniform locations
// uniform locations (skybox program)
int m_skybox_program_mvp_location = 0;
int m_skybox_program_eye_direction_location = 0;
int m_skybox_program_texture_sampler_location = 0;
int m_skybox_program_lightmap_sampler_location = 0;
int m_skybox_program_face_visibility_sampler_location = 0;
int m_skybox_program_opacity_location = 0;
int m_skybox_program_lightmap_only_location = 0;
int m_skybox_program_fullbright_location = 0;
@ -154,8 +173,9 @@ private:
// uniform locations (wireframe program)
int m_program_wireframe_mvp_location = 0;
int m_program_wireframe_face_visibility_sampler_location = 0;
// uniform locations
// uniform locations (simple program)
int m_program_simple_mvp_location = 0;
int m_program_simple_color_location = 0;
@ -163,6 +183,11 @@ public:
GLView(QWidget *parent = nullptr);
~GLView();
private:
void setFaceVisibilityArray(uint8_t *data);
void setFaceVisibilityToAllVisible();
public:
void renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries_t &bspx,
const std::vector<entdict_t> &entities, const full_atlas_t &lightmap, const settings::common_settings &settings,
bool use_bspx_normals);
@ -189,6 +214,7 @@ protected:
void resizeGL(int width, int height) override;
private:
void updateFaceVisibility();
bool shouldLiveUpdate() const;
void handleLoggedMessage(const QOpenGLDebugMessage &debugMessage);