diff options
Diffstat (limited to 'src/3d')
| -rw-r--r-- | src/3d/renderer.cc | 277 | ||||
| -rw-r--r-- | src/3d/visual_debug.cc | 41 |
2 files changed, 19 insertions, 299 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc index abd98b6..cbc3cfa 100644 --- a/src/3d/renderer.cc +++ b/src/3d/renderer.cc @@ -2,6 +2,9 @@ // It implements the Renderer3D class. #include "3d/renderer.h" +#include "generated/assets.h" +#include "gpu/effects/shader_composer.h" +#include "util/asset_manager.h" #include <algorithm> #include <cassert> #include <cstring> @@ -11,269 +14,6 @@ bool Renderer3D::s_debug_enabled_ = false; #endif -static const char* kShaderCode = R"( -struct GlobalUniforms { - view_proj: mat4x4<f32>, - camera_pos_time: vec4<f32>, - params: vec4<f32>, -}; - -struct ObjectData { - model: mat4x4<f32>, - inv_model: mat4x4<f32>, - color: vec4<f32>, - params: vec4<f32>, -}; - -struct ObjectsBuffer { - objects: array<ObjectData>, -}; - -@group(0) @binding(0) var<uniform> globals: GlobalUniforms; -@group(0) @binding(1) var<storage, read> object_data: ObjectsBuffer; -@group(0) @binding(2) var noise_tex: texture_2d<f32>; -@group(0) @binding(3) var noise_sampler: sampler; - -struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) local_pos: vec3<f32>, - @location(1) color: vec4<f32>, - @location(2) @interpolate(flat) instance_index: u32, - @location(3) world_pos: vec3<f32>, -}; - -@vertex -fn vs_main(@builtin(vertex_index) vertex_index: u32, - @builtin(instance_index) instance_index: u32) -> VertexOutput { - - var pos = array<vec3<f32>, 36>( - vec3(-1.0, -1.0, 1.0), vec3( 1.0, -1.0, 1.0), vec3( 1.0, 1.0, 1.0), - vec3(-1.0, -1.0, 1.0), vec3( 1.0, 1.0, 1.0), vec3(-1.0, 1.0, 1.0), - vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, -1.0), vec3( 1.0, 1.0, -1.0), - vec3(-1.0, -1.0, -1.0), vec3( 1.0, 1.0, -1.0), vec3( 1.0, -1.0, -1.0), - vec3(-1.0, 1.0, -1.0), vec3(-1.0, 1.0, 1.0), vec3( 1.0, 1.0, 1.0), - vec3(-1.0, 1.0, -1.0), vec3( 1.0, 1.0, 1.0), vec3( 1.0, 1.0, -1.0), - vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0, -1.0), vec3( 1.0, -1.0, 1.0), - vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0, 1.0), vec3(-1.0, -1.0, 1.0), - vec3( 1.0, -1.0, -1.0), vec3( 1.0, 1.0, -1.0), vec3( 1.0, 1.0, 1.0), - vec3( 1.0, -1.0, -1.0), vec3( 1.0, 1.0, 1.0), vec3( 1.0, -1.0, 1.0), - vec3(-1.0, -1.0, -1.0), vec3(-1.0, -1.0, 1.0), vec3(-1.0, 1.0, 1.0), - vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, 1.0), vec3(-1.0, 1.0, -1.0) - ); - - var p = pos[vertex_index]; - let obj = object_data.objects[instance_index]; - let obj_type = obj.params.x; - - // Tight fit for Torus proxy hull (major radius 1.0, minor 0.4) - if (obj_type == 3.0) { - p.x = p.x * 1.5; - p.z = p.z * 1.5; - p.y = p.y * 0.5; - } - - let world_pos = obj.model * vec4<f32>(p, 1.0); - let clip_pos = globals.view_proj * world_pos; - - var out: VertexOutput; - out.position = clip_pos; - out.local_pos = p; - out.color = obj.color; - out.instance_index = instance_index; - out.world_pos = world_pos.xyz; - return out; -} - -fn sdSphere(p: vec3<f32>, r: f32) -> f32 { - return length(p) - r; -} - -fn sdBox(p: vec3<f32>, b: vec3<f32>) -> f32 { - let q = abs(p) - b; - return length(max(q, vec3<f32>(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0); -} - -fn sdTorus(p: vec3<f32>, t: vec2<f32>) -> f32 { - let q = vec2<f32>(length(p.xz) - t.x, p.y); - return length(q) - t.y; -} - -fn sdPlane(p: vec3<f32>, n: vec3<f32>, h: f32) -> f32 { - return dot(p, n) + h; -} - -fn get_dist(p: vec3<f32>, obj_type: f32) -> f32 { - if (obj_type == 1.0) { return length(p) - 1.0; } // Unit Sphere - if (obj_type == 2.0) { return sdBox(p, vec3<f32>(1.0)); } // Unit Box - if (obj_type == 3.0) { return sdTorus(p, vec2<f32>(1.0, 0.4)); } // Unit Torus - if (obj_type == 4.0) { return sdPlane(p, vec3<f32>(0.0, 1.0, 0.0), 0.0); } - return 100.0; -} - -fn map_scene(p: vec3<f32>, skip_idx: u32) -> f32 { - var d = 1000.0; - let count = u32(globals.params.x); - - for (var i = 0u; i < count; i = i + 1u) { - if (i == skip_idx) { continue; } - let obj = object_data.objects[i]; - let obj_type = obj.params.x; - // Skip rasterized objects (like the floor) in the SDF map - if (obj_type <= 0.0) { continue; } - - let q = (obj.inv_model * vec4<f32>(p, 1.0)).xyz; - - let scale_x = length(obj.model[0].xyz); - let scale_y = length(obj.model[1].xyz); - let scale_z = length(obj.model[2].xyz); - // Use conservative minimum scale to avoid overstepping the distance field - let s = min(scale_x, min(scale_y, scale_z)); - - d = min(d, get_dist(q, obj_type) * s); - } - return d; -} - -fn calc_shadow(ro: vec3<f32>, rd: vec3<f32>, tmin: f32, tmax: f32, skip_idx: u32) -> f32 { - var res = 1.0; - var t = tmin; - if (t < 0.05) { t = 0.05; } - for (var i = 0; i < 32; i = i + 1) { - let h = map_scene(ro + rd * t, skip_idx); - if (h < 0.001) { return 0.0; } - res = min(res, 16.0 * h / t); // Standard k=16 - t = t + clamp(h, 0.02, 0.4); - if (t > tmax) { break; } - } - return clamp(res, 0.0, 1.0); -} - -fn get_normal(p: vec3<f32>, obj_type: f32) -> vec3<f32> { - if (obj_type == 1.0) { return normalize(p); } - let e = vec2<f32>(0.001, 0.0); - return normalize(vec3<f32>( - get_dist(p + e.xyy, obj_type) - get_dist(p - e.xyy, obj_type), - get_dist(p + e.yxy, obj_type) - get_dist(p - e.yxy, obj_type), - get_dist(p + e.yyx, obj_type) - get_dist(p - e.yyx, obj_type) - )); -} - -@fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { - let obj = object_data.objects[in.instance_index]; - let obj_type = obj.params.x; - - var p: vec3<f32>; - var normal: vec3<f32>; - var base_color = in.color.rgb; - let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0)); - - if (obj_type <= 0.0) { // Raster path - p = in.world_pos; - let local_normal = normalize(cross(dpdx(in.local_pos), dpdy(in.local_pos))); - let normal_matrix = mat3x3<f32>(obj.inv_model[0].xyz, obj.inv_model[1].xyz, obj.inv_model[2].xyz); - normal = normalize(transpose(normal_matrix) * local_normal); - - // Apply grid pattern to floor - let uv = p.xz * 0.5; - let grid = 0.5 + 0.5 * sin(uv.x * 3.14) * sin(uv.y * 3.14); - let grid_val = smoothstep(0.45, 0.55, grid); - base_color = base_color * (0.5 + 0.5 * grid_val); - } else { // SDF path - let ro_world = globals.camera_pos_time.xyz; - let rd_world = normalize(in.world_pos - ro_world); - - // Ray-Box Intersection in local space to find tight bounds - let ro_local = (obj.inv_model * vec4<f32>(ro_world, 1.0)).xyz; - let rd_local = normalize((obj.inv_model * vec4<f32>(rd_world, 0.0)).xyz); - - // Proxy box extent (matches vs_main) - var extent = vec3<f32>(1.0); - if (obj_type == 3.0) { extent = vec3<f32>(1.5, 0.5, 1.5); } - - let inv_rd = 1.0 / rd_local; - let t0 = (-extent - ro_local) * inv_rd; - let t1 = (extent - ro_local) * inv_rd; - let tmin_vec = min(t0, t1); - let tmax_vec = max(t0, t1); - let t_entry = max(0.0, max(tmin_vec.x, max(tmin_vec.y, tmin_vec.z))); - let t_exit = min(tmax_vec.x, min(tmax_vec.y, tmax_vec.z)); - - if (t_entry > t_exit) { discard; } - - var t = t_entry; - var hit = false; - for (var i = 0; i < 64; i = i + 1) { - let q = ro_local + rd_local * t; - let d_local = get_dist(q, obj_type); - if (d_local < 0.0005) { hit = true; break; } - t = t + d_local; - if (t > t_exit) { break; } - } - if (!hit) { discard; } - - let q_hit = ro_local + rd_local * t; - p = (obj.model * vec4<f32>(q_hit, 1.0)).xyz; // Correct world position - - // Calculate normal with bump mapping - let e = vec2<f32>(0.005, 0.0); - let disp_strength = 0.05; - - let q_x1 = q_hit + e.xyy; - let uv_x1 = vec2<f32>(atan2(q_x1.x, q_x1.z) / 6.28 + 0.5, acos(clamp(q_x1.y / length(q_x1), -1.0, 1.0)) / 3.14); - let h_x1 = textureSample(noise_tex, noise_sampler, uv_x1).r; - let d_x1 = get_dist(q_x1, obj_type) - disp_strength * h_x1; - - let q_x2 = q_hit - e.xyy; - let uv_x2 = vec2<f32>(atan2(q_x2.x, q_x2.z) / 6.28 + 0.5, acos(clamp(q_x2.y / length(q_x2), -1.0, 1.0)) / 3.14); - let h_x2 = textureSample(noise_tex, noise_sampler, uv_x2).r; - let d_x2 = get_dist(q_x2, obj_type) - disp_strength * h_x2; - - let q_y1 = q_hit + e.yxy; - let uv_y1 = vec2<f32>(atan2(q_y1.x, q_y1.z) / 6.28 + 0.5, acos(clamp(q_y1.y / length(q_y1), -1.0, 1.0)) / 3.14); - let h_y1 = textureSample(noise_tex, noise_sampler, uv_y1).r; - let d_y1 = get_dist(q_y1, obj_type) - disp_strength * h_y1; - - let q_y2 = q_hit - e.yxy; - let uv_y2 = vec2<f32>(atan2(q_y2.x, q_y2.z) / 6.28 + 0.5, acos(clamp(q_y2.y / length(q_y2), -1.0, 1.0)) / 3.14); - let h_y2 = textureSample(noise_tex, noise_sampler, uv_y2).r; - let d_y2 = get_dist(q_y2, obj_type) - disp_strength * h_y2; - - let q_z1 = q_hit + e.yyx; - let uv_z1 = vec2<f32>(atan2(q_z1.x, q_z1.z) / 6.28 + 0.5, acos(clamp(q_z1.y / length(q_z1), -1.0, 1.0)) / 3.14); - let h_z1 = textureSample(noise_tex, noise_sampler, uv_z1).r; - let d_z1 = get_dist(q_z1, obj_type) - disp_strength * h_z1; - - let q_z2 = q_hit - e.yyx; - let uv_z2 = vec2<f32>(atan2(q_z2.x, q_z2.z) / 6.28 + 0.5, acos(clamp(q_z2.y / length(q_z2), -1.0, 1.0)) / 3.14); - let h_z2 = textureSample(noise_tex, noise_sampler, uv_z2).r; - let d_z2 = get_dist(q_z2, obj_type) - disp_strength * h_z2; - - let n_local = normalize(vec3<f32>(d_x1 - d_x2, d_y1 - d_y2, d_z1 - d_z2)); - let normal_matrix = mat3x3<f32>(obj.inv_model[0].xyz, obj.inv_model[1].xyz, obj.inv_model[2].xyz); - normal = normalize(transpose(normal_matrix) * n_local); - - // Apply texture to SDF color - if (in.instance_index == 0u || obj_type == 4.0) { // Floor (index 0) or PLANE - let uv_grid = p.xz * 0.5; - let grid = 0.5 + 0.5 * sin(uv_grid.x * 3.14) * sin(uv_grid.y * 3.14); - let grid_val = smoothstep(0.45, 0.55, grid); - base_color = base_color * (0.5 + 0.5 * grid_val); - } else { - let uv_hit = vec2<f32>(atan2(q_hit.x, q_hit.z) / 6.28 + 0.5, acos(clamp(q_hit.y / length(q_hit), -1.0, 1.0)) / 3.14); - let tex_val = textureSample(noise_tex, noise_sampler, uv_hit).r; - base_color = base_color * (0.7 + 0.3 * tex_val); - } - } - - let shadow = calc_shadow(p, light_dir, 0.05, 20.0, in.instance_index); - let diffuse = max(dot(normal, light_dir), 0.0); - let lighting = diffuse * (0.1 + 0.9 * shadow) + 0.1; // Ambient + Shadowed Diffuse - return vec4<f32>(base_color * lighting, 1.0); -} - -)"; - void Renderer3D::init(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format) { device_ = device; @@ -398,16 +138,21 @@ void Renderer3D::create_pipeline() { WGPUPipelineLayout pipeline_layout = wgpuDeviceCreatePipelineLayout(device_, &pl_desc); + std::string main_code = + (const char*)GetAsset(AssetId::ASSET_SHADER_RENDERER_3D); + std::string shader_source = ShaderComposer::Get().Compose( + {"common_uniforms", "sdf_primitives", "lighting", "ray_box"}, main_code); + #if defined(DEMO_CROSS_COMPILE_WIN32) WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgsl_desc.code = kShaderCode; + wgsl_desc.code = shader_source.c_str(); WGPUShaderModuleDescriptor shader_desc = {}; shader_desc.nextInChain = (const WGPUChainedStruct*)&wgsl_desc.chain; #else WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_desc.code = {kShaderCode, strlen(kShaderCode)}; + wgsl_desc.code = {shader_source.c_str(), shader_source.length()}; WGPUShaderModuleDescriptor shader_desc = {}; shader_desc.nextInChain = (const WGPUChainedStruct*)&wgsl_desc.chain; #endif @@ -621,4 +366,4 @@ void Renderer3D::render(const Scene& scene, const Camera& camera, float time, wgpuCommandBufferRelease(commands); wgpuCommandEncoderRelease(encoder); -}
\ No newline at end of file +} diff --git a/src/3d/visual_debug.cc b/src/3d/visual_debug.cc index 51ccc39..f8d9bed 100644 --- a/src/3d/visual_debug.cc +++ b/src/3d/visual_debug.cc @@ -5,40 +5,11 @@ #if !defined(STRIP_ALL) +#include "generated/assets.h" +#include "util/asset_manager.h" #include <cstdio> #include <cstring> -// Simple shader for drawing colored lines -static const char* kDebugShaderCode = R"( -struct Uniforms { - viewProj : mat4x4<f32>, -} -@group(0) @binding(0) var<uniform> uniforms : Uniforms; - -struct VertexInput { - @location(0) position : vec3<f32>, - @location(1) color : vec3<f32>, -} - -struct VertexOutput { - @builtin(position) position : vec4<f32>, - @location(0) color : vec3<f32>, -} - -@vertex -fn vs_main(in : VertexInput) -> VertexOutput { - var out : VertexOutput; - out.position = uniforms.viewProj * vec4<f32>(in.position, 1.0); - out.color = in.color; - return out; -} - -@fragment -fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> { - return vec4<f32>(in.color, 1.0); -} -)"; - void VisualDebug::init(WGPUDevice device, WGPUTextureFormat format) { device_ = device; create_pipeline(format); @@ -92,16 +63,20 @@ void VisualDebug::create_pipeline(WGPUTextureFormat format) { wgpuDeviceCreatePipelineLayout(device_, &pl_desc); // Shader + size_t shader_len = 0; + const char* shader_code = + (const char*)GetAsset(AssetId::ASSET_SHADER_VISUAL_DEBUG, &shader_len); + #if defined(DEMO_CROSS_COMPILE_WIN32) WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgsl_desc.code = kDebugShaderCode; + wgsl_desc.code = shader_code; WGPUShaderModuleDescriptor shader_desc = {}; shader_desc.nextInChain = (const WGPUChainedStruct*)&wgsl_desc.chain; #else WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_desc.code = {kDebugShaderCode, strlen(kDebugShaderCode)}; + wgsl_desc.code = {shader_code, shader_len}; WGPUShaderModuleDescriptor shader_desc = {}; shader_desc.nextInChain = (const WGPUChainedStruct*)&wgsl_desc.chain; #endif |
