Skip to content

Commit ab0b91d

Browse files
committed
Support multiple light sources and update fragment cache for light directions and states
Signed-off-by: ZhouFANG <indevn@outlook.com>
1 parent 415aaea commit ab0b91d

3 files changed

Lines changed: 117 additions & 55 deletions

File tree

src/include/shader.hpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <shared_mutex>
77
#include <unordered_map>
88
#include <variant>
9+
#include <vector>
910

1011
#include "light.h"
1112
#include "material.hpp"
@@ -14,7 +15,8 @@
1415
namespace simple_renderer {
1516

1617
using UniformValue = std::variant<int, float, Vector2f, Vector3f, Vector4f,
17-
Matrix3f, Matrix4f, Material, Light>;
18+
Matrix3f, Matrix4f, Material, Light,
19+
std::vector<Light>>;
1820

1921
inline constexpr size_t kSpecularLutResolution = 256;
2022

@@ -27,7 +29,7 @@ class UniformBuffer {
2729
std::is_same_v<T, Vector2f> || std::is_same_v<T, Vector3f> ||
2830
std::is_same_v<T, Vector4f> || std::is_same_v<T, Matrix3f> ||
2931
std::is_same_v<T, Matrix4f> || std::is_same_v<T, Material> ||
30-
std::is_same_v<T, Light>,
32+
std::is_same_v<T, Light> || std::is_same_v<T, std::vector<Light>>,
3133
"Type not supported by UniformValue");
3234
uniforms_[name] = value;
3335
}
@@ -83,10 +85,10 @@ struct VertexUniformCache {
8385
};
8486

8587
struct FragmentUniformCache {
86-
Light light{};
88+
std::vector<Light> lights{}; // 支持多光源
8789
Vector3f camera_pos = Vector3f(0.0f);
88-
Vector3f light_dir_normalized = Vector3f(0.0f);
89-
bool has_light = false;
90+
std::vector<Vector3f> light_dirs_normalized{};
91+
bool has_lights = false;
9092
bool has_camera = false;
9193
bool derived_valid = false;
9294
};
@@ -142,6 +144,7 @@ class Shader {
142144

143145
void UpdateMatrixCache(const std::string &name, const Matrix4f &value);
144146
void UpdateFragmentCache(const std::string &name, const Light &value);
147+
void UpdateFragmentCache(const std::string &name, const std::vector<Light> &value);
145148
void UpdateFragmentCache(const std::string &name, const Vector3f &value);
146149
void RecalculateDerivedMatrices();
147150
void RecalculateFragmentDerived();
@@ -155,6 +158,10 @@ class Shader {
155158

156159
Color SampleTexture(const Texture &texture, const Vector2f &uv) const;
157160
Color ClampColor(const Color color) const;
161+
162+
public:
163+
// 便捷接口:设置多光源
164+
void SetLights(const std::vector<Light>& lights) { SetUniform("lights", lights); }
158165
};
159166

160167
uint8_t FloatToUint8_t(float val);

src/shader.cpp

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,23 @@ void Shader::RecalculateDerivedMatrices() {
136136

137137
void Shader::UpdateFragmentCache(const std::string& name,
138138
const Light& value) {
139-
if (name != "light") {
140-
return;
139+
if (name != "light") { return; }
140+
fragment_uniform_cache_.lights.clear();
141+
fragment_uniform_cache_.lights.push_back(value);
142+
fragment_uniform_cache_.has_lights = true;
143+
fragment_uniform_cache_.derived_valid = false;
144+
if (fragment_uniform_cache_.has_lights && fragment_uniform_cache_.has_camera) {
145+
RecalculateFragmentDerived();
141146
}
142-
fragment_uniform_cache_.light = value;
143-
fragment_uniform_cache_.has_light = true;
147+
}
148+
149+
void Shader::UpdateFragmentCache(const std::string& name,
150+
const std::vector<Light>& value) {
151+
if (name != "lights") { return; }
152+
fragment_uniform_cache_.lights = value;
153+
fragment_uniform_cache_.has_lights = true;
144154
fragment_uniform_cache_.derived_valid = false;
145-
if (fragment_uniform_cache_.has_light && fragment_uniform_cache_.has_camera) {
155+
if (fragment_uniform_cache_.has_lights && fragment_uniform_cache_.has_camera) {
146156
RecalculateFragmentDerived();
147157
}
148158
}
@@ -155,14 +165,18 @@ void Shader::UpdateFragmentCache(const std::string& name,
155165
fragment_uniform_cache_.camera_pos = value;
156166
fragment_uniform_cache_.has_camera = true;
157167
fragment_uniform_cache_.derived_valid = false;
158-
if (fragment_uniform_cache_.has_light && fragment_uniform_cache_.has_camera) {
168+
if (fragment_uniform_cache_.has_lights && fragment_uniform_cache_.has_camera) {
159169
RecalculateFragmentDerived();
160170
}
161171
}
162172

163173
void Shader::RecalculateFragmentDerived() {
164-
fragment_uniform_cache_.light_dir_normalized =
165-
glm::normalize(fragment_uniform_cache_.light.dir);
174+
fragment_uniform_cache_.light_dirs_normalized.clear();
175+
fragment_uniform_cache_.light_dirs_normalized.reserve(
176+
fragment_uniform_cache_.lights.size());
177+
for (const auto& l : fragment_uniform_cache_.lights) {
178+
fragment_uniform_cache_.light_dirs_normalized.push_back(glm::normalize(l.dir));
179+
}
166180
fragment_uniform_cache_.derived_valid = true;
167181
}
168182

@@ -196,13 +210,27 @@ void Shader::PrepareFragmentUniformCache() {
196210
if (fragment_uniform_cache_.derived_valid) {
197211
return;
198212
}
213+
// 优先多光源
214+
if (uniformbuffer_.HasUniform<std::vector<Light>>("lights") &&
215+
uniformbuffer_.HasUniform<Vector3f>("cameraPos")) {
216+
fragment_uniform_cache_.lights =
217+
uniformbuffer_.GetUniform<std::vector<Light>>("lights");
218+
fragment_uniform_cache_.has_lights = true;
219+
fragment_uniform_cache_.camera_pos =
220+
uniformbuffer_.GetUniform<Vector3f>("cameraPos");
221+
fragment_uniform_cache_.has_camera = true;
222+
RecalculateFragmentDerived();
223+
return;
224+
}
225+
// 兼容单光源
199226
if (uniformbuffer_.HasUniform<Light>("light") &&
200227
uniformbuffer_.HasUniform<Vector3f>("cameraPos")) {
201-
fragment_uniform_cache_.light =
202-
uniformbuffer_.GetUniform<Light>("light");
228+
fragment_uniform_cache_.lights.clear();
229+
fragment_uniform_cache_.lights.push_back(
230+
uniformbuffer_.GetUniform<Light>("light"));
203231
fragment_uniform_cache_.camera_pos =
204232
uniformbuffer_.GetUniform<Vector3f>("cameraPos");
205-
fragment_uniform_cache_.has_light = true;
233+
fragment_uniform_cache_.has_lights = true;
206234
fragment_uniform_cache_.has_camera = true;
207235
RecalculateFragmentDerived();
208236
}
@@ -259,59 +287,81 @@ auto Shader::EvaluateSpecular(float cos_theta, float shininess) const -> float {
259287
}
260288

261289
Color Shader::FragmentShader(const Fragment& fragment) const {
262-
// interpolate Normal, Color and UV
263-
Color interpolateColor = fragment.color;
290+
// Helper: 将 Color 转为 [0,1] 归一化向量
291+
auto color_to_vec = [](const Color& c) -> Vector3f {
292+
constexpr float inv255 = 1.0f / 255.0f;
293+
return Vector3f(static_cast<float>(c[Color::kColorIndexRed]) * inv255,
294+
static_cast<float>(c[Color::kColorIndexGreen]) * inv255,
295+
static_cast<float>(c[Color::kColorIndexBlue]) * inv255);
296+
};
297+
298+
// 输入插值属性
299+
Vector3f base_color = color_to_vec(fragment.color);
264300
Vector3f normal = glm::normalize(fragment.normal);
265301
Vector2f uv = fragment.uv;
266302

267-
// uniform
268-
Light light;
269-
Vector3f light_dir;
303+
// uniform(优先缓存)
304+
std::vector<Light> lights;
305+
std::vector<Vector3f> light_dirs;
270306
Vector3f camera_pos;
271307
if (fragment_uniform_cache_.derived_valid) {
272-
light = fragment_uniform_cache_.light;
273-
light_dir = fragment_uniform_cache_.light_dir_normalized;
308+
lights = fragment_uniform_cache_.lights;
309+
light_dirs = fragment_uniform_cache_.light_dirs_normalized;
274310
camera_pos = fragment_uniform_cache_.camera_pos;
275311
} else {
276-
light = uniformbuffer_.GetUniform<Light>("light");
312+
if (uniformbuffer_.HasUniform<std::vector<Light>>("lights")) {
313+
lights = uniformbuffer_.GetUniform<std::vector<Light>>("lights");
314+
light_dirs.reserve(lights.size());
315+
for (const auto& l : lights) light_dirs.push_back(glm::normalize(l.dir));
316+
} else if (uniformbuffer_.HasUniform<Light>("light")) {
317+
lights = {uniformbuffer_.GetUniform<Light>("light")};
318+
light_dirs = {glm::normalize(lights[0].dir)};
319+
}
277320
camera_pos = uniformbuffer_.GetUniform<Vector3f>("cameraPos");
278-
light_dir = glm::normalize(light.dir);
279321
}
322+
280323
Material material = *fragment.material;
281324

282-
// view direction
283-
Vector3f view_dir =
284-
glm::normalize(sharedDataInShader_.fragPos_varying - camera_pos);
325+
// 视线方向
326+
Vector3f view_dir = glm::normalize(sharedDataInShader_.fragPos_varying - camera_pos);
285327

286-
auto intensity = std::max(glm::dot(normal, light_dir), 0.0f);
287-
// texture color
288-
Color ambient_color, diffuse_color, specular_color;
328+
// ambient(只计算一次,使用纹理或顶点颜色)
329+
Vector3f ambient_rgb;
289330
if (material.has_ambient_texture) {
290-
Color texture_color = SampleTexture(material.ambient_texture, uv);
291-
ambient_color = texture_color;
331+
ambient_rgb = color_to_vec(SampleTexture(material.ambient_texture, uv));
292332
} else {
293-
ambient_color = interpolateColor;
333+
ambient_rgb = base_color;
294334
}
295335

296-
if (material.has_diffuse_texture) {
297-
Color texture_color = SampleTexture(material.diffuse_texture, uv);
298-
diffuse_color = texture_color * intensity;
299-
} else {
300-
diffuse_color = interpolateColor * intensity;
301-
}
302-
303-
Vector3f halfVector = glm::normalize(light_dir + view_dir);
304-
float cos_theta = std::max(glm::dot(normal, halfVector), 0.0f);
305-
float spec = EvaluateSpecular(cos_theta, material.shininess);
306-
if (material.has_specular_texture) {
307-
Color texture_color = SampleTexture(material.specular_texture, uv);
308-
specular_color = texture_color * spec;
309-
} else {
310-
specular_color = Color(1.0f, 1.0f, 1.0f) * spec;
336+
// diffuse/specular 累加(float 归一化空间,避免 8bit 溢出与截断)
337+
Vector3f diffuse_accum(0.0f);
338+
Vector3f specular_accum(0.0f);
339+
for (size_t i = 0; i < light_dirs.size(); ++i) {
340+
const Vector3f& ldir = light_dirs[i];
341+
float intensity = std::max(glm::dot(normal, ldir), 0.0f);
342+
343+
// diffuse
344+
Vector3f kd = material.has_diffuse_texture
345+
? color_to_vec(SampleTexture(material.diffuse_texture, uv))
346+
: base_color;
347+
diffuse_accum += kd * intensity;
348+
349+
// specular
350+
Vector3f halfVector = glm::normalize(ldir + view_dir);
351+
float cos_theta = std::max(glm::dot(normal, halfVector), 0.0f);
352+
float spec = EvaluateSpecular(cos_theta, material.shininess);
353+
Vector3f ks = material.has_specular_texture
354+
? color_to_vec(SampleTexture(material.specular_texture, uv))
355+
: Vector3f(1.0f);
356+
specular_accum += ks * spec;
311357
}
312358

313-
return ClampColor(ambient_color * 0.1f + diffuse_color +
314-
specular_color * 0.2f);
359+
Vector3f out_rgb = ambient_rgb * 0.1f + diffuse_accum + specular_accum * 0.2f;
360+
// clamp 到 [0,1]
361+
out_rgb.x = std::clamp(out_rgb.x, 0.0f, 1.0f);
362+
out_rgb.y = std::clamp(out_rgb.y, 0.0f, 1.0f);
363+
out_rgb.z = std::clamp(out_rgb.z, 0.0f, 1.0f);
364+
return Color(out_rgb.x, out_rgb.y, out_rgb.z, 1.0f);
315365
}
316366

317367
// 将浮点数转换为 uint8_t

test/system_test/main.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,19 @@ int main(int argc, char **argv) {
7474
simple_renderer::Shader shader;
7575
shader.SetUniform("modelMatrix", modelMatrix);
7676

77-
simple_renderer::Light light;
78-
light.dir = simple_renderer::Vector3f(1.0f, 5.0f, 1.0f);
79-
shader.SetUniform("light", light);
77+
// 多光源
78+
std::vector<simple_renderer::Light> lights;
79+
{
80+
simple_renderer::Light l0; l0.dir = simple_renderer::Vector3f( 1.0f, 5.0f, 1.0f); lights.push_back(l0);
81+
simple_renderer::Light l1; l1.dir = simple_renderer::Vector3f(-3.0f, -2.0f, 2.0f); lights.push_back(l1);
82+
simple_renderer::Light l2; l2.dir = simple_renderer::Vector3f( 2.0f, 1.0f, -1.0f); lights.push_back(l2);
83+
}
84+
shader.SetLights(lights);
8085

8186
simple_renderer::Camera camera(simple_renderer::Vector3f(0.0f, 0.0f, 1.0f));
8287

8388
// 设置渲染模式(可选:PER_TRIANGLE、TILE_BASED 或 DEFERRED)
84-
simple_renderer.SetRenderingMode(simple_renderer::RenderingMode::TILE_BASED_DEFERRED);
89+
simple_renderer.SetRenderingMode(simple_renderer::RenderingMode::TILE_BASED);
8590

8691
// 输出当前渲染模式
8792
std::string current_mode_name = simple_renderer::RenderingModeToString(

0 commit comments

Comments
 (0)