> shadow casting lights

This commit is contained in:
Peter Li 2025-04-27 12:58:06 -07:00
parent ccab1182e1
commit f74c50e493
21 changed files with 368 additions and 68 deletions

View File

@ -77,6 +77,8 @@ pub const Impl = struct {
if (ig.begin("renderer debug", &self.rendererDebug, .{})) {
_ = ig.sliderFloat("directional light yaw", &rend.context().directionalLightYaw, 0, 360, null, .{});
_ = ig.sliderFloat("ortho near", &rend.context().shadowOrthoNear, 0, 200, null, .{});
_ = ig.sliderFloat("ortho far", &rend.context().shadowOrthoFar, 0, 6000, null, .{});
ig.end();
}
}

View File

@ -39,6 +39,8 @@ pub fn build(b: *std.Build) void {
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "debug.frag", b.path("shaders/debug.frag.json"));
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "debug.vert", b.path("shaders/debug.vert.json"));
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "depthOnly.frag", b.path("shaders/depthOnly.frag.json"));
// ========== tests ==========
const tests = b.addTest(.{
.target = target,

View File

@ -0,0 +1,10 @@
float4 main(
float2 UV : TEXCOORD0,
float3 WorldPos: TEXCOORD1,
float3 Normal: TEXCOORD2,
float4 DirectionalShadowFragPos: TEXCOORD3
) : SV_Target0
{
return float4(1.0, 1.0, 1.0, 1.0);
}

View File

@ -0,0 +1,15 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "out.var.SV_Target0",
"location" : 0
}
]
}

View File

@ -1,12 +1,16 @@
Texture2D<float4> Texture : register(t0, space2);
SamplerState Sampler : register(s0, space2);
Texture2D<float> DirectionalShadowDepthMap : register(t1, space2);
SamplerState DirectionalShadowSampler : register(s1, space2);
cbuffer Uniforms : register(b0, space3)
{
float4 viewPos;
float4 lightPosition;
float4 directionalLight;
float4 directionalLightColor;
float2 screenSize;
float time;
};
@ -68,8 +72,26 @@ float3 BlinnPhong(float3 normal, float3 fragPos, float3 lightPos, float3 lightCo
}
float3 DirectionalLight(float3 normal, float3 fragPos)
float shadowCalculation(float3 fragPos, float4 DirectionalShadowFragPos)
{
float3 shadowProjection = DirectionalShadowFragPos.xyz / DirectionalShadowFragPos.w;
shadowProjection = shadowProjection * 0.5 + 0.5 ;
shadowProjection.x = shadowProjection.x;
float2 uv = shadowProjection.xy;
uv.y = -uv.y;
float depthSample = DirectionalShadowDepthMap.Sample(DirectionalShadowSampler, uv);
float fragDepth = DirectionalShadowFragPos.z;
float bias = 0.005;
float shadow = fragDepth - bias > depthSample ? 1.0 : 0.0;
return shadow;
}
float3 DirectionalLight(float3 normal, float3 fragPos, float4 DirectionalShadowFragPos)
{
float3 lightDir = directionalLight.xyz;
float diff = max(dot(lightDir, normal), 0.0);
float3 diffuse = diff * directionalLightColor.xyz;
@ -82,13 +104,21 @@ float3 DirectionalLight(float3 normal, float3 fragPos)
spec = pow(max(dot(normal, halfwayDir), 0.0), 30.0);
float3 specular = spec * directionalLightColor.xyz * 2;
// shadow mapping
diffuse = diffuse * (1.0 - shadowCalculation(fragPos, DirectionalShadowFragPos));
return diffuse;
}
float4 main(
float4 ScreenPosition: SV_POSITION,
float2 UV : TEXCOORD0,
float3 WorldPos: TEXCOORD1,
float3 Normal: TEXCOORD2
float3 Normal: TEXCOORD2,
float4 DirectionalShadowFragPos: TEXCOORD3
) : SV_Target0
{
float4 s = Texture.Sample(Sampler, UV);
@ -102,14 +132,33 @@ float4 main(
float3 lightPos = lightPosition.xyz; //+ float3(0, 20, 0);
float3 lightColor = float3(0.8, 0.8, 0.5);
float3 ambient = lerp(float3(0.01, 0.01, 0.003), float3(0.004, 0.004, 0.06), dot(Normal, float3(0.0,1.0,0.0)) ) * 5;
float3 ambient = float3(0.1,0.1,0.1);
float3 col = s.xyz;
float3 c2 = col * ambient + col * BlinnPhong(Normal, WorldPos, lightPos, lightColor) + col * DirectionalLight(Normal, WorldPos);
float3 c2 = col * ambient
+ col * BlinnPhong(Normal, WorldPos, lightPos, lightColor)
+ col * DirectionalLight(Normal, WorldPos, DirectionalShadowFragPos);
float4 rv = float4(pow(c2, 1.0 / 2.2), alpha);
// === debug bone zone
// float3 shadowProjection = DirectionalShadowFragPos.xyz / DirectionalShadowFragPos.w;
// shadowProjection = shadowProjection * 0.5 + 0.5 ;
// shadowProjection.x = shadowProjection.x;
// float2 uv = shadowProjection.xy;
// uv.y = -uv.y;
// float depthSample = DirectionalShadowDepthMap.Sample(DirectionalShadowSampler, uv);
// float fragDepth = shadowProjection.z;
// float t = DirectionalShadowFragPos.z;
// t = depthSample;
// rv = float4(t, t, t, 1.0);
// rv.x = rv.x + lightPos.x * 0.0001;
return rv;
}

View File

@ -6,7 +6,7 @@
}
],
"types" : {
"_11" : {
"_14" : {
"name" : "type.Uniforms",
"members" : [
{
@ -29,10 +29,15 @@
"type" : "vec4",
"offset" : 48
},
{
"name" : "screenSize",
"type" : "vec2",
"offset" : 64
},
{
"name" : "time",
"type" : "float",
"offset" : 64
"offset" : 72
}
]
}
@ -52,6 +57,11 @@
"type" : "vec3",
"name" : "in.var.TEXCOORD2",
"location" : 2
},
{
"type" : "vec4",
"name" : "in.var.TEXCOORD3",
"location" : 3
}
],
"outputs" : [
@ -67,6 +77,12 @@
"name" : "Texture",
"set" : 2,
"binding" : 0
},
{
"type" : "texture2D",
"name" : "DirectionalShadowDepthMap",
"set" : 2,
"binding" : 1
}
],
"separate_samplers" : [
@ -75,13 +91,19 @@
"name" : "Sampler",
"set" : 2,
"binding" : 0
},
{
"type" : "sampler",
"name" : "DirectionalShadowSampler",
"set" : 2,
"binding" : 1
}
],
"ubos" : [
{
"type" : "_11",
"type" : "_14",
"name" : "type.Uniforms",
"block_size" : 68,
"block_size" : 76,
"set" : 3,
"binding" : 0
}

View File

@ -1,3 +1,5 @@
// I just reuse this one for the shadow mapping right?
struct Input
{
float3 Position : TEXCOORD0;
@ -15,6 +17,7 @@ struct Output
float2 TexCoord : TEXCOORD0;
float3 WorldPos : TEXCOORD1;
float3 Normal: TEXCOORD2;
float4 DirectionalShadowFragPos: TEXCOORD3;
float4 Position : SV_Position;
};
@ -29,6 +32,7 @@ StructuredBuffer<Scene> scene: register(t0, space0);
cbuffer Uniforms : register(b0, space1)
{
float4x4 ViewProjection;
float4x4 ShadowMapProjection;
float time;
};
@ -46,6 +50,7 @@ Output main(Input input)
output.Position = mul(ViewProjection, mul(scene[input.Instance].Model, pos));
output.WorldPos = WorldPos.xyz;
output.Normal = input.Normal;
output.DirectionalShadowFragPos = mul(ShadowMapProjection, WorldPos);
return output;
}

View File

@ -6,7 +6,7 @@
}
],
"types" : {
"_11" : {
"_12" : {
"name" : "Scene",
"members" : [
{
@ -18,12 +18,12 @@
}
]
},
"_10" : {
"_11" : {
"name" : "type.StructuredBuffer.Scene",
"members" : [
{
"name" : "_m0",
"type" : "_11",
"type" : "_12",
"array" : [
0
],
@ -35,7 +35,7 @@
}
]
},
"_13" : {
"_14" : {
"name" : "type.Uniforms",
"members" : [
{
@ -45,10 +45,17 @@
"matrix_stride" : 16,
"row_major" : true
},
{
"name" : "ShadowMapProjection",
"type" : "mat4",
"offset" : 64,
"matrix_stride" : 16,
"row_major" : true
},
{
"name" : "time",
"type" : "float",
"offset" : 64
"offset" : 128
}
]
}
@ -85,11 +92,16 @@
"type" : "vec3",
"name" : "out.var.TEXCOORD2",
"location" : 2
},
{
"type" : "vec4",
"name" : "out.var.TEXCOORD3",
"location" : 3
}
],
"ssbos" : [
{
"type" : "_10",
"type" : "_11",
"name" : "scene",
"readonly" : true,
"block_size" : 0,
@ -99,9 +111,9 @@
],
"ubos" : [
{
"type" : "_13",
"type" : "_14",
"name" : "type.Uniforms",
"block_size" : 68,
"block_size" : 132,
"set" : 1,
"binding" : 0
}

View File

@ -193,7 +193,7 @@ pub fn createPipeline(self: *@This()) !*gpu.GPUGraphicsPipeline {
pci.depth_stencil_state.write_mask = 0xff;
pci.target_info.has_depth_stencil_target = true;
pci.target_info.depth_stencil_format = .textureformatD32Float;
pci.target_info.depth_stencil_format = rend.context().depthFormat;
pci.target_info.num_color_targets = 1;
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
.{

View File

@ -37,9 +37,12 @@ pub const Renderer = struct {
preDraws: std.ArrayListUnmanaged(struct { ptr: *anyopaque, func: *const fn (*anyopaque, *gpu.GPUCommandBuffer) void }) = .{},
depthTexture: *gpu.GPUTexture = undefined,
depthFormat: gpu.GPUTextureFormat = .textureformatD16Unorm,
textureList: *TextureList = undefined,
shadowMapProjection: core.Transform = core.zm.identity(),
blockySampler: *gpu.GPUSampler = undefined,
defaultTexture: *rend.Texture = undefined,
@ -47,9 +50,17 @@ pub const Renderer = struct {
debugDrawSys: *DebugDrawSystem = undefined,
shadowOrthoNear: f32 = -150,
shadowOrthoFar: f32 = 150,
directionalLightYaw: f32 = 0.0,
directionalLightColor: core.colors.Color = .{ .r = 0.8, .g = 0.8, .b = 0.9 },
directionalLightDir: core.Vectorf = core.Vectorf.new(0.5, 0.25, -1).normalize(),
directionalLightDir: core.Vectorf = core.Vectorf.new(0.5, -0.5, 0.0).normalize(),
shadowDepthFormat: gpu.GPUTextureFormat = .textureformatD16Unorm,
shadowDepthTexture: *gpu.GPUTexture = undefined,
shadowDepthDebugOutput: *gpu.GPUTexture = undefined,
shadowCastingPipeline: *gpu.GPUGraphicsPipeline = undefined,
// transients DO NOT TOUCH
swapchainTexture: ?*gpu.GPUTexture = undefined,
@ -118,6 +129,13 @@ pub const Renderer = struct {
self.defaultTexture = getTexture(&defaultTextureName).?;
self.debugDrawSys = try self.createRendererEngineObject(DebugDrawSystem);
try self.createDirectionalShadowsPipeline();
}
pub fn createDirectionalShadowsPipeline(self: *@This()) !void {
try self.createShadowDepthTexture();
try self.createShadowCastingPipeline();
}
pub fn createSamplers(self: *@This()) !void {
@ -174,11 +192,27 @@ pub const Renderer = struct {
return object;
}
fn createShadowDepthTexture(self: *@This()) !void {
var gci = std.mem.zeroes(gpu.GPUTextureCreateInfo);
const shadowMapRes = core.configVar(u32, "renderer.shadowmap.resolution", 2048);
gci.type = .texturetype2d;
gci.format = self.shadowDepthFormat;
gci.width = shadowMapRes;
gci.height = shadowMapRes;
gci.layer_count_or_depth = 1;
gci.num_levels = 1;
gci.sample_count = .samplecount1;
gci.usage = .{ .textureusageDepthStencilTarget = true, .textureusageSampler = true };
self.shadowDepthTexture = self.device.createGPUTexture(&gci);
}
fn createDepthTexture(self: *@This()) !void {
var gci = std.mem.zeroes(gpu.GPUTextureCreateInfo);
gci.type = .texturetype2d;
gci.format = .textureformatD32Float;
gci.format = self.depthFormat;
gci.width = @intCast(self.scissor.w);
gci.height = @intCast(self.scissor.h);
gci.layer_count_or_depth = 1;
@ -212,26 +246,31 @@ pub const Renderer = struct {
offset.* = offset.* + size;
}
pub fn createMeshPipeline(self: *@This()) !void {
pub fn generateVertexAttributeList(self: *@This()) !std.ArrayList(gpu.GPUVertexAttribute) {
var list = std.ArrayList(gpu.GPUVertexAttribute).init(self.allocator);
var offset: u32 = 0;
{
try addAttribute(&list, &offset, @sizeOf(f32) * 3, .vertexelementformatFloat3);
try addAttribute(&list, &offset, @sizeOf(f32) * 3, .vertexelementformatFloat3);
try addAttribute(&list, &offset, @sizeOf(f32) * 4, .vertexelementformatFloat4);
try addAttribute(&list, &offset, @sizeOf(f32) * 2, .vertexelementformatFloat2);
try addAttribute(&list, &offset, @sizeOf(u32), .vertexelementformatUint);
}
return list;
}
pub fn createShadowCastingPipeline(self: *@This()) !void {
const vertex = try self.loadShader("meshes.vert", meshes_vert.LoadArgs);
const fragment = try self.loadShader("lit_mesh.frag", lit_mesh_frag.LoadArgs);
const fragment = try self.loadShader("depthOnly.frag", depthOnly.LoadArgs);
var pci = std.mem.zeroes(gpu.GPUGraphicsPipelineCreateInfo);
pci.vertex_shader = vertex;
pci.fragment_shader = fragment;
var attributes = std.ArrayList(gpu.GPUVertexAttribute).init(self.allocator);
var attributes = try self.generateVertexAttributeList();
defer attributes.deinit();
var offset: u32 = 0;
{
try addAttribute(&attributes, &offset, @sizeOf(f32) * 3, .vertexelementformatFloat3);
try addAttribute(&attributes, &offset, @sizeOf(f32) * 3, .vertexelementformatFloat3);
try addAttribute(&attributes, &offset, @sizeOf(f32) * 4, .vertexelementformatFloat4);
try addAttribute(&attributes, &offset, @sizeOf(f32) * 2, .vertexelementformatFloat2);
try addAttribute(&attributes, &offset, @sizeOf(u32), .vertexelementformatUint);
}
pci.vertex_input_state = .{
.num_vertex_buffers = 1,
.vertex_buffer_descriptions = &[_]gpu.GPUVertexBufferDescription{
@ -247,7 +286,45 @@ pub const Renderer = struct {
pci.depth_stencil_state.write_mask = 0xff;
pci.target_info.has_depth_stencil_target = true;
pci.target_info.depth_stencil_format = .textureformatD32Float;
pci.target_info.depth_stencil_format = self.shadowDepthFormat;
pci.target_info.num_color_targets = 0;
// no color targets
pci.rasterizer_state.cull_mode = .cullmodeNone;
pci.rasterizer_state.fill_mode = .fillmodeFill;
pci.rasterizer_state.enable_depth_bias = true;
self.shadowCastingPipeline = self.device.createGPUGraphicsPipeline(&pci);
}
pub fn createMeshPipeline(self: *@This()) !void {
const vertex = try self.loadShader("meshes.vert", meshes_vert.LoadArgs);
const fragment = try self.loadShader("lit_mesh.frag", lit_mesh_frag.LoadArgs);
var pci = std.mem.zeroes(gpu.GPUGraphicsPipelineCreateInfo);
pci.vertex_shader = vertex;
pci.fragment_shader = fragment;
var attributes = try self.generateVertexAttributeList();
defer attributes.deinit();
pci.vertex_input_state = .{
.num_vertex_buffers = 1,
.vertex_buffer_descriptions = &[_]gpu.GPUVertexBufferDescription{
.{ .slot = 0, .pitch = @sizeOf(rend.MeshVertex), .input_rate = .vertexinputrateVertex, .instance_step_rate = 0 },
},
.num_vertex_attributes = @intCast(attributes.items.len),
.vertex_attributes = @ptrCast(attributes.items.ptr),
};
pci.depth_stencil_state.compare_op = .compareopLess;
pci.depth_stencil_state.enable_depth_test = true;
pci.depth_stencil_state.enable_depth_write = true;
pci.depth_stencil_state.write_mask = 0xff;
pci.target_info.has_depth_stencil_target = true;
pci.target_info.depth_stencil_format = self.depthFormat;
pci.target_info.num_color_targets = 1;
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
.{
@ -357,6 +434,8 @@ pub const Renderer = struct {
if (self.activeCamera) |camera| {
ptr.ViewProjection = @bitCast(camera.final);
}
ptr.ShadowMapProjection = @bitCast(self.shadowMapProjection);
// ptr.ViewProjection = @bitCast(self.shadowMapProjection);
ptr.time = @floatCast(self.totalTime);
@ -371,8 +450,9 @@ pub const Renderer = struct {
if (self.activeCamera) |cam| {
position = cam.finalPos;
}
const resolved = core.Rotation.eulerY(core.radians(self.directionalLightYaw)).rotateVector(self.directionalLightDir);
const resolved = core.Rotation.eulerY(core.radians(self.directionalLightYaw)).rotateVector(self.directionalLightDir.fmul(-1));
ptr.screenSize = @bitCast(platform.context().extent);
ptr.viewPos = @bitCast(position.toZm());
ptr.lightPosition = @bitCast(self.lightPosition.toZm());
ptr.directionalLight = @bitCast(resolved.toZm());
@ -425,32 +505,109 @@ pub const Renderer = struct {
const cmd = self.device.acquireGPUCommandBuffer();
self.frameUploads();
try self.uploadUniforms(cmd);
for (self.preDraws.items) |interface| {
interface.func(interface.ptr, cmd);
}
// mesh pre-iteration
const container = rend.MeshComponent.BaseContainer;
const uploadCount: usize = @min(container.dense.items.len, MaxObjectCount);
for (0..uploadCount) |i| {
const component = &container.dense.items[i].value;
if (component.mesh == null) {
component.updateMesh();
}
if (component.texture == null) {
component.updateTexture();
}
}
self.drawDirectionalShadowMap(cmd);
self.draw(cmd);
}
// orthographic view projection from the sun towards the center of the thing
pub fn shadowMapOrtho(self: *@This()) core.Transform {
const ortho = core.zm.orthographicLh(200, 200, self.shadowOrthoNear, self.shadowOrthoFar);
var rotation = core.zm.lookAtLh(
.{ 0, 0, 0, 1 },
self.directionalLightDir.toZm(),
.{ 0, 1, 0, 1 },
);
rotation = core.zm.mul(core.zm.rotationY(core.radians(self.directionalLightYaw)), rotation);
return core.zm.mul(rotation, ortho);
}
pub fn drawDirectionalShadowMap(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
{
var data = std.mem.zeroes([@sizeOf(meshes_vert.Uniforms) / 8 + 1]usize);
const ptr: *meshes_vert.Uniforms = @ptrCast(@alignCast(&data));
self.shadowMapProjection = self.shadowMapOrtho();
ptr.ViewProjection = @bitCast(self.shadowMapProjection);
cmd.pushGPUVertexUniformData(0, &data, @sizeOf(meshes_vert.Uniforms));
}
// can cache this
const depthTarget = std.mem.zeroInit(gpu.GPUDepthStencilTargetInfo, .{
.texture = self.shadowDepthTexture,
.load_op = .loadopClear,
.store_op = .storeopStore,
.stencil_load_op = .loadopDontCare,
.stencil_store_op = .storeopDontCare,
.clear_depth = 1.0,
.clear_stencil = 0,
});
const renderpass = cmd.beginGPURenderPass(null, 0, &depthTarget);
renderpass.bindGPUGraphicsPipeline(self.shadowCastingPipeline);
renderpass.bindGPUVertexStorageBuffers(0, &self.ssboScene, 1);
renderpass.bindGPUVertexBuffers(0, &.{ .buffer = self.meshPool.vertexBuffer, .offset = 0 }, 1);
renderpass.bindGPUIndexBuffer(&.{ .buffer = self.meshPool.indexBuffer, .offset = 0 }, .indexelementsize32bit);
const container = rend.MeshComponent.BaseContainer;
const uploadCount: usize = @min(container.dense.items.len, MaxObjectCount);
for (0..uploadCount) |i| {
const component = &container.dense.items[i].value;
if (component.mesh) |mesh| {
renderpass.drawGPUIndexedPrimitives(mesh.index.size, 1, mesh.index.start, @intCast(mesh.vertex.start), @intCast(i));
}
}
renderpass.endGPURenderPass();
}
pub fn draw(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
if (cmd.waitAndAcquireGPUSwapchainTexture(self.window, @ptrCast(&self.swapchainTexture), null, null)) {
if (self.swapchainTexture == null) {
_ = cmd.submitGPUCommandBuffer();
return;
}
try self.uploadUniforms(cmd);
var targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroes(gpu.GPUColorTargetInfo);
targetInfo.texture = self.swapchainTexture.?;
targetInfo.clear_color = .{ .r = 0.1, .g = 0.1, .b = 0.1, .a = 1.0 };
targetInfo.load_op = .loadopClear;
targetInfo.store_op = .storeopStore;
// can cache this
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
.texture = self.swapchainTexture.?,
.clear_color = .{ .r = 0.1, .g = 0.1, .b = 0.1, .a = 1.0 },
.load_op = .loadopClear,
.store_op = .storeopStore,
});
var depthTarget = std.mem.zeroes(gpu.GPUDepthStencilTargetInfo);
depthTarget.texture = self.depthTexture;
depthTarget.load_op = .loadopClear;
depthTarget.store_op = .storeopDontCare;
depthTarget.stencil_load_op = .loadopDontCare;
depthTarget.stencil_store_op = .storeopDontCare;
depthTarget.clear_depth = 1.0;
depthTarget.clear_stencil = 0;
const depthTarget = std.mem.zeroInit(gpu.GPUDepthStencilTargetInfo, .{
.texture = self.depthTexture,
.load_op = .loadopClear,
.store_op = .storeopDontCare,
.stencil_load_op = .loadopDontCare,
.stencil_store_op = .storeopDontCare,
.clear_depth = 1.0,
.clear_stencil = 0,
});
const renderpass = cmd.beginGPURenderPass(&targetInfo, 1, &depthTarget);
//renderpass.bindGPUGraphicsPipeline(self.testPipeline);
@ -460,36 +617,26 @@ pub const Renderer = struct {
renderpass.bindGPUVertexStorageBuffers(0, &self.ssboScene, 1);
renderpass.bindGPUVertexBuffers(0, &.{ .buffer = self.meshPool.vertexBuffer, .offset = 0 }, 1);
renderpass.bindGPUIndexBuffer(&.{ .buffer = self.meshPool.indexBuffer, .offset = 0 }, .indexelementsize32bit);
renderpass.bindGPUFragmentSamplers(1, &.{ .texture = self.shadowDepthTexture, .sampler = self.blockySampler }, 1);
// todo move into materials system
renderpass.setGPUScissor(&self.scissor);
//SDL_BindGPUFragmentSamplers(renderPass, 0, &(SDL_GPUTextureSamplerBinding){ .texture = Texture, .sampler = Samplers[CurrentSamplerIndex] }, 1);
//rendering each mesh
{
const container = rend.MeshComponent.BaseContainer;
const uploadCount: usize = @min(container.dense.items.len, MaxObjectCount);
for (0..uploadCount) |i| {
// core.engine_log("pushing draw {d}", .{i});
const component = &container.dense.items[i].value;
// todo move this to slow tick? only update once every 1 second or so?
if (component.mesh == null) {
component.updateMesh();
}
if (component.texture == null) {
component.updateTexture();
}
var t = component.texture;
if (t == null) {
t = self.defaultTexture;
}
renderpass.bindGPUFragmentSamplers(0, &.{ .texture = t.?.texture, .sampler = self.blockySampler }, 1);
if (component.mesh) |mesh| {
// core.engine_log("pushing draw for instance {d}", .{i});
renderpass.drawGPUIndexedPrimitives(mesh.index.size, 1, mesh.index.start, @intCast(mesh.vertex.start), @intCast(i));
}
}
@ -543,6 +690,7 @@ const gpu = sdl3.gpu;
const meshes_vert = @import("meshes.vert");
const lit_mesh_frag = @import("lit_mesh.frag");
const depthOnly = @import("depthOnly.frag");
const sample_vert = @import("sample.vert");
const MeshVertices = meshes_vert.Scene;

View File

@ -0,0 +1,5 @@
extras are like engine plugins
they have access to all engine modules without having to be upstreamed as part of the engine
and they don't have to be linked into your project unless you want them to be.

View File

@ -620,7 +620,7 @@ pub const GPUColorTargetInfo = extern struct {
clear_color: FColor, // The color to clear the color target to at the start of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used.
load_op: GPULoadOp, // What is done with the contents of the color target at the beginning of the render pass.
store_op: GPUStoreOp, // What is done with the results of the render pass.
resolve_texture: *GPUTexture, // The texture that will receive the results of a multisample resolve operation. Ignored if a RESOLVE* store_op is not used.
resolve_texture: ?*GPUTexture, // The texture that will receive the results of a multisample resolve operation. Ignored if a RESOLVE* store_op is not used.
resolve_mip_level: u32, // The mip level of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used.
resolve_layer: u32, // The layer index of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used.
cycle: bool, // true cycles the texture if the texture is bound and load_op is not LOAD

Binary file not shown.

View File

@ -0,0 +1,17 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 out_var_SV_Target0 [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.out_var_SV_Target0 = float4(1.0);
return out;
}

View File

@ -9,9 +9,12 @@ struct type_Uniforms
float4 lightPosition;
float4 directionalLight;
float4 directionalLightColor;
float2 screenSize;
float time;
};
constant float3 _56 = {};
struct main0_out
{
float4 out_var_SV_Target0 [[color(0)]];
@ -22,14 +25,15 @@ struct main0_in
float2 in_var_TEXCOORD0 [[user(locn0)]];
float3 in_var_TEXCOORD1 [[user(locn1)]];
float3 in_var_TEXCOORD2 [[user(locn2)]];
float4 in_var_TEXCOORD3 [[user(locn3)]];
};
fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], texture2d<float> Texture [[texture(0)]], sampler Sampler [[sampler(0)]])
fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], texture2d<float> Texture [[texture(0)]], texture2d<float> DirectionalShadowDepthMap [[texture(1)]], sampler Sampler [[sampler(0)]], sampler DirectionalShadowSampler [[sampler(1)]])
{
main0_out out = {};
float4 _61 = Texture.sample(Sampler, in.in_var_TEXCOORD0);
float _62 = _61.w;
if (_62 < 0.00999999977648258209228515625)
float4 _65 = Texture.sample(Sampler, in.in_var_TEXCOORD0);
float _66 = _65.w;
if (_66 < 0.00999999977648258209228515625)
{
discard_fragment();
}
@ -68,7 +72,12 @@ fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Unifo
_119 = ((float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * precise::max(dot(_100, in.in_var_TEXCOORD2), 0.0)) * _93) + (((float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * powr(precise::max(dot(in.in_var_TEXCOORD2, fast::normalize(_100 + fast::normalize(in.in_var_TEXCOORD1 - Uniforms.viewPos.xyz))), 0.0), 30.0)) * 2.0) * _93);
break;
} while(false);
out.out_var_SV_Target0 = float4(powr(_61.xyz * (((mix(float3(0.00999999977648258209228515625, 0.00999999977648258209228515625, 0.0030000000260770320892333984375), float3(0.0040000001899898052215576171875, 0.0040000001899898052215576171875, 0.0599999986588954925537109375), float3(in.in_var_TEXCOORD2.y)) * 5.0) + _119) + (Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0))), float3(0.4545454680919647216796875)), _62);
float3 _136 = ((in.in_var_TEXCOORD3.xyz / float3(in.in_var_TEXCOORD3.w)) * 0.5) + float3(0.5);
float3 _138;
_138.x = _136.x;
float2 _139 = _138.xy;
_139.y = -_136.y;
out.out_var_SV_Target0 = float4(powr(_65.xyz * ((float3(0.100000001490116119384765625) + _119) + ((Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0)) * (1.0 - float((in.in_var_TEXCOORD3.z - 0.004999999888241291046142578125) > DirectionalShadowDepthMap.sample(DirectionalShadowSampler, _139).x)))), float3(0.4545454680919647216796875)), _66);
return out;
}

View File

@ -16,6 +16,7 @@ struct type_StructuredBuffer_Scene
struct type_Uniforms
{
float4x4 ViewProjection;
float4x4 ShadowMapProjection;
float time;
};
@ -24,6 +25,7 @@ struct main0_out
float2 out_var_TEXCOORD0 [[user(locn0)]];
float3 out_var_TEXCOORD1 [[user(locn1)]];
float3 out_var_TEXCOORD2 [[user(locn2)]];
float4 out_var_TEXCOORD3 [[user(locn3)]];
float4 gl_Position [[position]];
};
@ -37,11 +39,13 @@ struct main0_in
vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], uint gl_InstanceIndex [[instance_id]])
{
main0_out out = {};
float4 _44 = float4(in.in_var_TEXCOORD0, 1.0);
float4 _46 = float4(in.in_var_TEXCOORD0, 1.0);
float4 _49 = scene._m0[gl_InstanceIndex].Model * _46;
out.out_var_TEXCOORD0 = in.in_var_TEXCOORD3;
out.out_var_TEXCOORD1 = (scene._m0[gl_InstanceIndex].Model * _44).xyz;
out.out_var_TEXCOORD1 = _49.xyz;
out.out_var_TEXCOORD2 = in.in_var_TEXCOORD1;
out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _44);
out.out_var_TEXCOORD3 = Uniforms.ShadowMapProjection * _49;
out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _46);
return out;
}

Binary file not shown.