bevy_mod_outline/src/outline.wgsl

111 lines
2.8 KiB
WebGPU Shading Language

#import bevy_render::view::View
#import bevy_render::maths
#import bevy_pbr::mesh_types::Mesh
#import bevy_pbr::mesh_types::SkinnedMesh
#import bevy_pbr::mesh_functions
struct Vertex {
#ifdef VERTEX_POSITIONS
@location(0) position: vec3<f32>,
@builtin(instance_index) instance_index: u32,
#endif
#ifndef OFFSET_ZERO
@location(1) outline_normal: vec3<f32>,
#endif
#ifdef SKINNED
@location(5) joint_indices: vec4<u32>,
@location(6) joint_weights: vec4<f32>,
#endif
#ifdef MORPH_TARGETS
@builtin(vertex_index) index: u32,
#endif
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
#ifdef FLAT_DEPTH
@location(0) @interpolate(flat) flat_depth: f32,
#endif
};
struct OutlineViewUniform {
@align(16)
scale: vec2<f32>,
};
struct OutlineVertexUniform {
@align(16)
origin: vec3<f32>,
offset: f32,
};
@group(0) @binding(0)
var<uniform> view: View;
#import bevy_pbr::mesh_bindings
#import bevy_pbr::skinning
#import bevy_pbr::morph
@group(2) @binding(0)
var<uniform> view_uniform: OutlineViewUniform;
@group(3) @binding(0)
var<uniform> vstage: OutlineVertexUniform;
#ifdef MORPH_TARGETS
fn morph_vertex(vertex_in: Vertex) -> Vertex {
var vertex = vertex_in;
let weight_count = bevy_pbr::morph::layer_count();
for (var i: u32 = 0u; i < weight_count; i ++) {
let weight = bevy_pbr::morph::weight_at(i);
if weight == 0.0 {
continue;
}
vertex.position += weight * bevy_pbr::morph::morph(vertex.index, bevy_pbr::morph::position_offset, i);
}
return vertex;
}
#endif
fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> {
return mat3x3<f32>(
m[0].xyz, m[1].xyz, m[2].xyz
);
}
fn model_origin_z(plane: vec3<f32>, view_proj: mat4x4<f32>) -> f32 {
var proj_zw = mat4x2<f32>(
view_proj[0].zw, view_proj[1].zw,
view_proj[2].zw, view_proj[3].zw);
var zw = proj_zw * vec4<f32>(plane, 1.0);
return zw.x / zw.y;
}
@vertex
fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
#ifdef MORPH_TARGETS
var vertex = morph_vertex(vertex_no_morph);
#else
var vertex = vertex_no_morph;
#endif
#ifdef SKINNED
let model = bevy_pbr::skinning::skin_model(vertex.joint_indices, vertex.joint_weights);
#else
let model = bevy_pbr::mesh_functions::get_model_matrix(vertex_no_morph.instance_index);
#endif
let clip_pos = view.view_proj * (model * vec4<f32>(vertex.position, 1.0));
#ifdef OFFSET_ZERO
let out_xy = clip_pos.xy;
#else
let clip_norm = mat4to3(view.view_proj) * (mat4to3(model) * vertex.outline_normal);
let ndc_delta = vstage.offset * normalize(clip_norm.xy) * view_uniform.scale * clip_pos.w;
let out_xy = clip_pos.xy + ndc_delta;
#endif
var out: VertexOutput;
out.position = vec4<f32>(out_xy, clip_pos.zw);
#ifdef FLAT_DEPTH
out.flat_depth = model_origin_z(vstage.origin, view.view_proj);
#endif
return out;
}