VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
envLighting.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// CPU-based environment lighting atlas generation.
5//
6// DEVIATION: upstream performs reprojection on GPU via fragment shaders.
7// This port performs all convolution work on CPU (importance sampling + RGBP encoding)
8// and uploads the final atlas as an RGBA8 texture. This is acceptable because atlas
9// generation is a one-time offline operation at load time.
10//
11#pragma once
12
13#include <array>
14#include <cstdint>
15#include <vector>
16
17namespace visutwin::canvas
18{
19 class GraphicsDevice;
20 class Texture;
21
49 {
50 public:
61 static Texture* generateAtlas(GraphicsDevice* device, Texture* source,
62 int size = 512,
63 int numReflectionSamples = 1024,
64 int numAmbientSamples = 2048);
65
78 static std::vector<uint8_t> generateAtlasRaw(const float* srcData, int srcW, int srcH,
79 int size = 512,
80 int numReflectionSamples = 1024,
81 int numAmbientSamples = 2048);
82
95 static Texture* generateSkyboxCubemap(GraphicsDevice* device, Texture* source, int size = 0);
96
97 private:
98 // Internal HDR cubemap representation (float RGBA, 6 faces, with mipmaps)
99 struct HdrCubemap
100 {
101 int size = 0;
102 int numLevels = 0;
103 // data[mipLevel][face] = vector of float4 pixels (r,g,b,a interleaved)
104 std::vector<std::vector<std::vector<float>>> data;
105 };
106
107 // Convert equirectangular RGBA32F texture to HDR cubemap
108 static HdrCubemap equirectToCubemap(Texture* source, int size);
109 static HdrCubemap equirectToCubemap(const float* srcData, int srcW, int srcH, int size);
110
111 // Generate box-filter mipmaps for all cubemap faces
112 static void generateMipmaps(HdrCubemap& cubemap);
113
114 // Trilinear sample from HDR cubemap at a given direction and mip level
115 struct Color3 { float r, g, b; };
116 static Color3 sampleCubemap(const HdrCubemap& cubemap, float dirX, float dirY, float dirZ, float mipLevel);
117
118 // Bilinear sample from a single cubemap face at a given mip level
119 static Color3 sampleFace(const std::vector<float>& faceData, int faceSize, float u, float v);
120
121 // Direction -> cubemap face + UV
122 static void dirToFaceUv(float x, float y, float z, int& face, float& u, float& v);
123
124 // Direction <-> equirectangular UV conversion
125 static void dirToEquirectUv(float x, float y, float z, float& u, float& v);
126 static void equirectUvToDir(float u, float v, float& x, float& y, float& z);
127
128 // Hemisphere sampling for importance sampling
129 static void hemisphereSampleGGX(float& hx, float& hy, float& hz, float xi1, float xi2, float a);
130 static void hemisphereSampleLambert(float& hx, float& hy, float& hz, float xi1, float xi2);
131
132 // GGX normal distribution function
133 static float D_GGX(float NoH, float linearRoughness);
134
135 // RGBP encoding: linear HDR float3 -> RGBA8
136 static std::array<uint8_t, 4> encodeRGBP(float r, float g, float b);
137
138 // Write a convolved equirectangular region into the atlas buffer (from cubemap)
139 static void writeEquirectRegion(uint8_t* atlas, int atlasSize,
140 int rx, int ry, int rw, int rh,
141 const HdrCubemap& cubemap, float mipLevel);
142
143 // Write an equirectangular region sampling directly from source equirect texture.
144 // reprojectTexture with numSamples=1 samples the source directly
145 // without going through a cubemap, preserving full source resolution.
146 static void writeEquirectFromSource(uint8_t* atlas, int atlasSize,
147 int rx, int ry, int rw, int rh,
148 const float* srcData, int srcW, int srcH);
149
150 // Write a GGX-prefiltered equirectangular region into the atlas
151 static void writeGGXRegion(uint8_t* atlas, int atlasSize,
152 int rx, int ry, int rw, int rh,
153 const HdrCubemap& cubemap,
154 int specularPower, int numSamples);
155
156 // Write a Lambert-convolved equirectangular region into the atlas
157 static void writeLambertRegion(uint8_t* atlas, int atlasSize,
158 int rx, int ry, int rw, int rh,
159 const HdrCubemap& cubemap, int numSamples);
160
161 // Required samples table for GGX (accounts for invalid below-hemisphere samples)
162 static int getRequiredSamplesGGX(int numSamples, int specularPower);
163 };
164}
static Texture * generateAtlas(GraphicsDevice *device, Texture *source, int size=512, int numReflectionSamples=1024, int numAmbientSamples=2048)
static std::vector< uint8_t > generateAtlasRaw(const float *srcData, int srcW, int srcH, int size=512, int numReflectionSamples=1024, int numAmbientSamples=2048)
static Texture * generateSkyboxCubemap(GraphicsDevice *device, Texture *source, int size=0)
Abstract GPU interface for resource creation, state management, and draw submission.
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
Definition texture.h:57