From 1e08193a1678675ac5869b76e8a2339f6de5b773 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 26 Feb 2026 18:04:06 +0000 Subject: Support for the BillboardPainter Based on the ShadowStenciller, creates flattened images of a model for simplified mass use in a scene. --- gfx/gl/billboardPainter.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 gfx/gl/billboardPainter.cpp (limited to 'gfx/gl/billboardPainter.cpp') diff --git a/gfx/gl/billboardPainter.cpp b/gfx/gl/billboardPainter.cpp new file mode 100644 index 0000000..e72e72d --- /dev/null +++ b/gfx/gl/billboardPainter.cpp @@ -0,0 +1,92 @@ +#include "billboardPainter.h" +#include "gfx/models/mesh.h" +#include "glArrays.h" +#include "gl_traits.h" +#include "gldebug.h" +#include "maths.h" +#include +#include +#include +#include + +const auto VIEWS = [](std::integer_sequence) { + constexpr float STEP = two_pi / BillboardPainter::VIEW_ANGLES; + return std::array {rotate_yaw<4>(Ep * STEP)...}; +}(std::make_integer_sequence>()); + +BillboardPainter::BillboardPainter() : + program {billboardPainter_vert, billboardPainter_geom, billboardPainter_frag}, view {} +{ + glDebugScope _ {fbo}; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + static constexpr std::array ATTACHMENTS {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; + glDrawBuffers(ATTACHMENTS.size(), ATTACHMENTS.data()); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glUseProgram(program); + glUniform(viewLoc, std::span {VIEWS}); +} + +void +BillboardPainter::setView(const glm::mat4 & newView) +{ + view = newView; +} + +glTextures<3> +BillboardPainter::createBillBoardTextures(GLsizei width, GLsizei height) +{ + glDebugScope _ {0}; + glTextures<3> textures; + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + const auto configuregdata = [width, height](const GLuint texture, const GLint iformat, const GLenum format) { + glBindTexture(GL_TEXTURE_2D_ARRAY, texture); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameter(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, iformat, width, height, VIEW_ANGLES, 0, format, GL_BYTE, nullptr); + }; + configuregdata(textures[0], GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT); + configuregdata(textures[1], GL_RGB8_SNORM, GL_RGB); + configuregdata(textures[2], GL_RGB5_A1, GL_RGBA); + + return textures; +} + +void +BillboardPainter::renderBillBoard( + const glTextures<3> & billboard, const MeshBase & mesh, const Texture::AnyPtr texture) const +{ + glDebugScope _ {fbo}; + glEnable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glCullFace(GL_BACK); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glClearColor(0, 0, 0, 0); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, billboard[0], 0); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, billboard[1], 0); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, billboard[2], 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + throw std::runtime_error("Billboard framebuffer not complete!"); + } + if (texture) { + texture->bind(); + } + glUseProgram(program); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + const TextureDimensions billboardSize = {256, 256, 8}; // Texture::getSize(billboard[0]); + glViewport(0, 0, billboardSize.x, billboardSize.y); + const auto & centre = mesh.getDimensions().centre; + const auto & size = mesh.getDimensions().size; + glUniform(viewProjectionLoc, + std::span {VIEWS * + [extentsMat = glm::translate(glm::ortho(-size, size, -size, size, -size, size), -centre), this]( + const auto & view) { + return this->view * view * extentsMat; + }}); + mesh.Draw(); +} -- cgit v1.3