hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src/rendering/black_hole_renderer.cpp
blob: 2534b1d2262f342063db5dfa8cafd772a2ca3d6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "black_hole_renderer.h"

#include "core/log.h"
#include "core/settings_manager.h"

#include <algorithm>
#include <cstdint>
#include <cstring>

namespace Donut
{
    using namespace RHI;

    namespace
    {
        constexpr float SagA_rs = 1.269e10f;

        struct CamUBO {
            glm::vec3 pos;  float p0; glm::vec3 right; float p1;
            glm::vec3 up;   float p2; glm::vec3 fwd;   float p3;
            float tan_half_fov; float aspect; uint32_t moving; int p4;
        };
        struct SimUBO { int steps_moving; int steps_static; float early_exit; float time; };
    }

    auto BlackHoleRenderer::init(RHI::Device& device) -> bool
    {
        m_device = &device;

        m_geo_lo = device.create_render_target(GEO_LO_W, GEO_LO_H, Format::RGBA8, false, Filter::Linear);
        m_geo_hi = device.create_render_target(GEO_HI_W, GEO_HI_H, Format::RGBA8, false, Filter::Linear);

        const float quad[] = {
            -1.f,  1.f, 0.f, 1.f,  -1.f, -1.f, 0.f, 0.f,   1.f, -1.f, 1.f, 0.f,
            -1.f,  1.f, 0.f, 1.f,   1.f, -1.f, 1.f, 0.f,   1.f,  1.f, 1.f, 1.f,
        };
        m_quad_vb  = device.create_buffer(BufferType::Vertex, sizeof(quad), quad);

        m_cam_ubo  = device.create_buffer(BufferType::Uniform, 128);
        m_disk_ubo = device.create_buffer(BufferType::Uniform, 32);
        m_obj_ubo  = device.create_buffer(BufferType::Uniform, 800);
        m_sim_ubo  = device.create_buffer(BufferType::Uniform, 16);

        std::vector<uint8_t> obj(800, 0);
        int num_objects = 1;                          std::memcpy(obj.data() +   0, &num_objects, 4);
        float pos_radius[4] = { 0, 0, 0, SagA_rs };   std::memcpy(obj.data() +  16, pos_radius, 16);
        float color[4]      = { 0, 0, 0, 1 };         std::memcpy(obj.data() + 272, color, 16);
        m_obj_ubo->update(obj.data(), obj.size());

        {
            PipelineDesc d;
            d.shader = "geodesic";
            d.vertex_layout = { 16, { { 0, 2, 0 }, { 1, 2, 8 } } };
            d.resources = {
                { ResourceKind::UniformBuffer, 0, "Camera" },
                { ResourceKind::UniformBuffer, 1, "Disk" },
                { ResourceKind::UniformBuffer, 2, "Objects" },
                { ResourceKind::UniformBuffer, 3, "Simulation" },
                { ResourceKind::Texture,       4, "u_HDRIEnvironment" },
            };
            d.topology = Topology::Triangles;
            d.has_depth = false;
            m_geo_pipeline = device.create_pipeline(d);
        }
        {
            PipelineDesc d;
            d.shader = "textured_quad";
            d.vertex_layout = { 16, { { 0, 2, 0 }, { 1, 2, 8 } } };
            d.resources = { { ResourceKind::Texture, 0, "u_ScreenTexture" } };
            d.topology = Topology::Triangles;
            d.has_depth = true;
            m_present_pipeline = device.create_pipeline(d);
        }

        DONUT_INFO("BlackHoleRenderer ready ({}x{} moving / {}x{} settled)",
                   GEO_LO_W, GEO_LO_H, GEO_HI_W, GEO_HI_H);
        return true;
    }

    auto BlackHoleRenderer::render_geodesic(RHI::CommandList& cmd, const GeodesicView& view,
                                            const BlackHoleParams& params, RHI::Texture* cubemap) -> void
    {
        CamUBO cam{};
        cam.pos = view.position; cam.right = view.right; cam.up = view.up; cam.fwd = view.forward;
        cam.tan_half_fov = view.tan_half_fov;
        cam.aspect = view.aspect;
        cam.moving = view.moving ? 1u : 0u;
        m_cam_ubo->update(&cam, sizeof(cam));

        constexpr int kStepCeil = 15000;
        SimUBO sim{};
        sim.steps_static = std::clamp(params.quality_steps, 1000, kStepCeil);
        sim.steps_moving = sim.steps_static;
        sim.early_exit   = SettingsManager::get_early_exit_distance();
        sim.time         = view.time;
        m_sim_ubo->update(&sim, sizeof(sim));

        float disk[8] = {
            std::max(params.disk_inner_rs, 3.0f) * SagA_rs,
            std::max(params.disk_outer_rs, params.disk_inner_rs + 0.5f) * SagA_rs,
            std::max(params.turbulence, 0.0f),
            SagA_rs * 0.1f,
            std::max(params.brightness, 0.0f),
            std::max(params.temperature, 1000.0f),
            0.0f, 0.0f,
        };
        m_disk_ubo->update(disk, sizeof(disk));

        RenderTarget* target = view.moving ? m_geo_lo.get() : m_geo_hi.get();
        m_last_target = target;

        cmd.begin_render_pass(target, glm::vec4(0, 0, 0, 1));
        cmd.set_viewport(0, 0, target->width(), target->height(), false);
        cmd.bind_pipeline(m_geo_pipeline.get());
        cmd.bind_uniform(0, m_cam_ubo.get());
        cmd.bind_uniform(1, m_disk_ubo.get());
        cmd.bind_uniform(2, m_obj_ubo.get());
        cmd.bind_uniform(3, m_sim_ubo.get());
        cmd.bind_texture(4, cubemap);
        cmd.bind_vertex_buffer(m_quad_vb.get());
        cmd.draw(6);
        cmd.end_render_pass();
    }

    auto BlackHoleRenderer::blit(RHI::CommandList& cmd, int fb_width, int fb_height) -> void
    {
        if (!m_last_target) return;
        cmd.set_viewport(0, 0, fb_width, fb_height, true);
        cmd.bind_pipeline(m_present_pipeline.get());
        cmd.bind_texture(0, m_last_target->color_texture());
        cmd.bind_vertex_buffer(m_quad_vb.get());
        cmd.draw(6);
    }
}