|
1 | 1 | #include "shader.hpp" |
2 | 2 |
|
| 3 | +#include <algorithm> |
| 4 | +#include <cmath> |
| 5 | +#include <mutex> |
| 6 | +#include <shared_mutex> |
| 7 | + |
3 | 8 | namespace simple_renderer { |
4 | 9 |
|
| 10 | +Shader::Shader(const Shader& shader) { |
| 11 | + std::shared_lock lock(shader.specular_cache_mutex_); |
| 12 | + uniformbuffer_ = shader.uniformbuffer_; |
| 13 | + sharedDataInShader_ = shader.sharedDataInShader_; |
| 14 | + vertex_uniform_cache_ = shader.vertex_uniform_cache_; |
| 15 | + fragment_uniform_cache_ = shader.fragment_uniform_cache_; |
| 16 | + specular_lut_cache_ = shader.specular_lut_cache_; |
| 17 | +} |
| 18 | + |
| 19 | +Shader::Shader(Shader&& shader) noexcept { |
| 20 | + std::unique_lock lock(shader.specular_cache_mutex_); |
| 21 | + uniformbuffer_ = std::move(shader.uniformbuffer_); |
| 22 | + sharedDataInShader_ = shader.sharedDataInShader_; |
| 23 | + vertex_uniform_cache_ = shader.vertex_uniform_cache_; |
| 24 | + fragment_uniform_cache_ = shader.fragment_uniform_cache_; |
| 25 | + specular_lut_cache_ = std::move(shader.specular_lut_cache_); |
| 26 | +} |
| 27 | + |
| 28 | +auto Shader::operator=(const Shader& shader) -> Shader& { |
| 29 | + if (this == &shader) { |
| 30 | + return *this; |
| 31 | + } |
| 32 | + std::shared_lock lock(shader.specular_cache_mutex_); |
| 33 | + uniformbuffer_ = shader.uniformbuffer_; |
| 34 | + sharedDataInShader_ = shader.sharedDataInShader_; |
| 35 | + vertex_uniform_cache_ = shader.vertex_uniform_cache_; |
| 36 | + fragment_uniform_cache_ = shader.fragment_uniform_cache_; |
| 37 | + specular_lut_cache_ = shader.specular_lut_cache_; |
| 38 | + return *this; |
| 39 | +} |
| 40 | + |
| 41 | +auto Shader::operator=(Shader&& shader) noexcept -> Shader& { |
| 42 | + if (this == &shader) { |
| 43 | + return *this; |
| 44 | + } |
| 45 | + std::unique_lock lock(shader.specular_cache_mutex_); |
| 46 | + uniformbuffer_ = std::move(shader.uniformbuffer_); |
| 47 | + sharedDataInShader_ = shader.sharedDataInShader_; |
| 48 | + vertex_uniform_cache_ = shader.vertex_uniform_cache_; |
| 49 | + fragment_uniform_cache_ = shader.fragment_uniform_cache_; |
| 50 | + specular_lut_cache_ = std::move(shader.specular_lut_cache_); |
| 51 | + return *this; |
| 52 | +} |
| 53 | + |
5 | 54 | Vertex Shader::VertexShader(const Vertex& vertex) { |
6 | 55 | const bool cache_ready = vertex_uniform_cache_.derived_valid; |
7 | 56 |
|
@@ -159,6 +208,56 @@ void Shader::PrepareFragmentUniformCache() { |
159 | 208 | } |
160 | 209 | } |
161 | 210 |
|
| 211 | +auto Shader::BuildSpecularLUT(float shininess) const -> SpecularLUT { |
| 212 | + SpecularLUT lut; |
| 213 | + if (shininess <= 0.0f) { |
| 214 | + lut.values.fill(1.0f); |
| 215 | + return lut; |
| 216 | + } |
| 217 | + |
| 218 | + for (size_t i = 0; i < kSpecularLutResolution; ++i) { |
| 219 | + float cos_theta = static_cast<float>(i) / |
| 220 | + static_cast<float>(kSpecularLutResolution - 1); |
| 221 | + lut.values[i] = cos_theta <= 0.0f ? 0.0f : std::pow(cos_theta, shininess); |
| 222 | + } |
| 223 | + return lut; |
| 224 | +} |
| 225 | + |
| 226 | +auto Shader::GetSpecularLUT(float shininess) const -> const SpecularLUT& { |
| 227 | + uint32_t key = std::bit_cast<uint32_t>(shininess); |
| 228 | + { |
| 229 | + std::shared_lock lock(specular_cache_mutex_); |
| 230 | + auto it = specular_lut_cache_.find(key); |
| 231 | + if (it != specular_lut_cache_.end()) { |
| 232 | + return it->second; |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + SpecularLUT lut = BuildSpecularLUT(shininess); |
| 237 | + std::unique_lock lock(specular_cache_mutex_); |
| 238 | + auto [it, inserted] = specular_lut_cache_.emplace(key, std::move(lut)); |
| 239 | + return it->second; |
| 240 | +} |
| 241 | + |
| 242 | +auto Shader::EvaluateSpecular(float cos_theta, float shininess) const -> float { |
| 243 | + cos_theta = std::clamp(cos_theta, 0.0f, 1.0f); |
| 244 | + if (shininess <= 0.0f) { |
| 245 | + return 1.0f; |
| 246 | + } |
| 247 | + if (cos_theta <= 0.0f) { |
| 248 | + return 0.0f; |
| 249 | + } |
| 250 | + |
| 251 | + const auto& lut = GetSpecularLUT(shininess); |
| 252 | + float scaled = cos_theta * static_cast<float>(kSpecularLutResolution - 1); |
| 253 | + size_t index = static_cast<size_t>(scaled); |
| 254 | + float frac = scaled - static_cast<float>(index); |
| 255 | + |
| 256 | + const float v0 = lut.values[index]; |
| 257 | + const float v1 = lut.values[std::min(index + 1, kSpecularLutResolution - 1)]; |
| 258 | + return v0 + (v1 - v0) * frac; |
| 259 | +} |
| 260 | + |
162 | 261 | Color Shader::FragmentShader(const Fragment& fragment) const { |
163 | 262 | // interpolate Normal, Color and UV |
164 | 263 | Color interpolateColor = fragment.color; |
@@ -202,8 +301,8 @@ Color Shader::FragmentShader(const Fragment& fragment) const { |
202 | 301 | } |
203 | 302 |
|
204 | 303 | Vector3f halfVector = glm::normalize(light_dir + view_dir); |
205 | | - float spec = std::pow(std::max(glm::dot(normal, halfVector), 0.0f), |
206 | | - material.shininess); |
| 304 | + float cos_theta = std::max(glm::dot(normal, halfVector), 0.0f); |
| 305 | + float spec = EvaluateSpecular(cos_theta, material.shininess); |
207 | 306 | if (material.has_specular_texture) { |
208 | 307 | Color texture_color = SampleTexture(material.specular_texture, uv); |
209 | 308 | specular_color = texture_color * spec; |
|
0 commit comments