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
|
#pragma once
#include "rhi.h"
#include "scene/scene_types.h" // BlackHoleParams, SceneObject
#include <glm/glm.hpp>
#include <vector>
namespace Donut
{
// the black-hole view, written ONCE against the RHI. each frame it ray-traces
// the geodesic shader into an off-screen target (progressive resolution: a
// small target while the camera moves, a larger one once it settles) and then
// upscales that target onto the swapchain. the Application owns the camera and
// the HDRI cubemap and passes them in.
struct GeodesicView
{
glm::vec3 position, right, up, forward;
float tan_half_fov = 1.0f;
float aspect = 16.0f / 9.0f;
bool moving = false;
float time = 0.0f;
};
class BlackHoleRenderer
{
public:
static constexpr int GEO_LO_W = 480, GEO_LO_H = 270;
static constexpr int GEO_HI_W = 960, GEO_HI_H = 540;
auto init(RHI::Device& device) -> bool;
// off-screen geodesic pass (opens/closes its own render pass). call before
// the swapchain pass; `cubemap` is the shared HDRI environment. `objects`
// are the Scene's spheres — ray-traced as lensed spheres around the hole
// (1 scene unit = 1 Schwarzschild radius). grid units == r_s.
auto render_geodesic(RHI::CommandList& cmd, const GeodesicView& view,
const BlackHoleParams& params,
const std::vector<SceneObject>& objects, RHI::Texture* cubemap) -> void;
// upscales the geodesic target onto the swapchain (call inside the open
// swapchain render pass, before ImGui).
auto blit(RHI::CommandList& cmd, int fb_width, int fb_height) -> void;
// renders one channel (0 colour, 1 redshift g, 2 emission T, 3 impact
// parameter) into an arbitrary RGBA8 target — for high-res export.
auto render_export(RHI::CommandList& cmd, RHI::RenderTarget* target,
const GeodesicView& view, const BlackHoleParams& params,
const std::vector<SceneObject>& objects, RHI::Texture* cubemap,
int channel, bool raw) -> void;
private:
auto fill_uniforms(const GeodesicView& view, const BlackHoleParams& params,
const std::vector<SceneObject>& objects, int channel, bool raw) -> void;
auto draw_geodesic(RHI::CommandList& cmd, RHI::RenderTarget* target,
RHI::Texture* cubemap, RHI::Pipeline* pipeline) -> void;
RHI::Device* m_device = nullptr;
Ref<RHI::Pipeline> m_geo_pipeline;
Ref<RHI::Pipeline> m_geo_pipeline_hdr; // RGBA32F variant for raw export
Ref<RHI::RenderTarget> m_geo_lo;
Ref<RHI::RenderTarget> m_geo_hi;
Ref<RHI::Buffer> m_quad_vb;
Ref<RHI::Buffer> m_cam_ubo;
Ref<RHI::Buffer> m_disk_ubo;
Ref<RHI::Buffer> m_obj_ubo;
Ref<RHI::Buffer> m_sim_ubo;
Ref<RHI::Pipeline> m_present_pipeline;
RHI::RenderTarget* m_last_target = nullptr; // target chosen this frame
};
}
|