struct VertexShaderInput { // Per Vertex @builtin(vertex_index) vertex_index: u32, @location(0) pos: vec3, // Per Instance @location(1) pos_size: vec4, @location(2) uv0uv1: vec4, @location(3) uv2uv3: vec4, }; struct VertexShaderOutput { @builtin(position) pos: vec4, @location(0) uv: vec2, }; struct FragmentShaderOutput { @location(0) color: vec4, }; @group(0) @binding(0) var view_projection_matrix: mat4x4; @vertex fn main_vertex(input: VertexShaderInput) -> VertexShaderOutput { var output: VertexShaderOutput; output.pos = vec4(input.pos_size.xy + input.pos.xy, 0, 1) * view_projection_matrix; switch (input.vertex_index) { case 0: { output.uv = input.uv0uv1.xy; } case 1: { output.uv = input.uv2uv3.zw; } case 2: { output.uv = input.uv2uv3.xy; } case 3: { output.uv = input.uv0uv1.zw; } default: {} } return output; } @group(1) @binding(0) var texture1: texture_2d; @group(1) @binding(1) var sampler1: sampler; @group(1) @binding(2) var tint: vec3; @fragment fn main_fragment(input: VertexShaderOutput) -> FragmentShaderOutput { var output: FragmentShaderOutput; output.color = pixel_art_sample(texture1, sampler1, input.uv); output.color = vec4(output.color.rgb * tint.rgb, output.color.a); return output; } fn pixel_art_sample(input_texture: texture_2d, input_sampler: sampler, input_uv: vec2) -> vec4 { let dimensions = vec2(textureDimensions(input_texture)); let texture_uv = input_uv * dimensions.xy; let sample_uv = (floor(texture_uv) + min(fract(texture_uv) / fwidth(texture_uv), vec2(1.0, 1.0)) - 0.5) / dimensions.xy; return textureSample(input_texture, input_sampler, sample_uv); }