Make Outline a RenderAsset and pass parameters to shader.
This commit is contained in:
parent
399602e26a
commit
95d093220e
@ -17,6 +17,7 @@ bevy = { version = "0.7", default-features = false, features = [
|
|||||||
"render",
|
"render",
|
||||||
] }
|
] }
|
||||||
bevy_asset = { version = "0.7", default-features = false }
|
bevy_asset = { version = "0.7", default-features = false }
|
||||||
|
libm = "0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bevy = { version = "0.7", default-features = false, features = [
|
bevy = { version = "0.7", default-features = false, features = [
|
||||||
|
@ -22,6 +22,7 @@ struct TheCube();
|
|||||||
fn setup(
|
fn setup(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut outlines: ResMut<Assets<Outline>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
// Spawn cube et al.
|
// Spawn cube et al.
|
||||||
@ -35,16 +36,16 @@ fn setup(
|
|||||||
mesh: meshes.add(Mesh::from(RoundedBox {
|
mesh: meshes.add(Mesh::from(RoundedBox {
|
||||||
size: Vec3::new(1., 1., 1.),
|
size: Vec3::new(1., 1., 1.),
|
||||||
radius: 0.3,
|
radius: 0.3,
|
||||||
subdivisions: 3,
|
subdivisions: 5,
|
||||||
})),
|
})),
|
||||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||||
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(Outline {
|
.insert(outlines.add(Outline {
|
||||||
colour: Color::rgb(1.0, 0.0, 0.0),
|
colour: Color::rgba(0.0, 1.0, 0.0, 0.5),
|
||||||
offset: 1.0,
|
width: 50.0,
|
||||||
})
|
}))
|
||||||
.insert(TheCube());
|
.insert(TheCube());
|
||||||
commands.spawn_bundle(PointLightBundle {
|
commands.spawn_bundle(PointLightBundle {
|
||||||
point_light: PointLight {
|
point_light: PointLight {
|
||||||
|
247
src/lib.rs
247
src/lib.rs
@ -1,44 +1,116 @@
|
|||||||
use bevy::asset::load_internal_asset;
|
use bevy::asset::load_internal_asset;
|
||||||
use bevy::core_pipeline::Transparent3d;
|
use bevy::core_pipeline::{Opaque3d, Transparent3d};
|
||||||
|
use bevy::ecs::system::lifetimeless::{Read, SQuery, SRes};
|
||||||
|
use bevy::ecs::system::SystemParamItem;
|
||||||
use bevy::pbr::{
|
use bevy::pbr::{
|
||||||
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup,
|
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::reflect::TypeUuid;
|
use bevy::reflect::TypeUuid;
|
||||||
use bevy::render::mesh::{MeshVertexBufferLayout, PrimitiveTopology};
|
use bevy::render::mesh::{MeshVertexBufferLayout, PrimitiveTopology};
|
||||||
use bevy::render::render_asset::RenderAssets;
|
use bevy::render::render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets};
|
||||||
use bevy::render::render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline};
|
use bevy::render::render_component::ExtractComponentPlugin;
|
||||||
use bevy::render::render_resource::{
|
use bevy::render::render_phase::{
|
||||||
Face, PipelineCache, RenderPipelineDescriptor, SpecializedMeshPipeline,
|
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||||
SpecializedMeshPipelineError, SpecializedMeshPipelines,
|
SetItemPipeline, TrackedRenderPass,
|
||||||
};
|
};
|
||||||
|
use bevy::render::render_resource::std140::{AsStd140, Std140};
|
||||||
|
use bevy::render::render_resource::{
|
||||||
|
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor,
|
||||||
|
BindGroupLayoutEntry, BindingType, Buffer, BufferBindingType, BufferInitDescriptor, BufferSize,
|
||||||
|
BufferUsages, Face, PipelineCache, RenderPipelineDescriptor, ShaderStages,
|
||||||
|
SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines,
|
||||||
|
};
|
||||||
|
use bevy::render::renderer::RenderDevice;
|
||||||
use bevy::render::view::ExtractedView;
|
use bevy::render::view::ExtractedView;
|
||||||
use bevy::render::{RenderApp, RenderStage};
|
use bevy::render::{RenderApp, RenderStage};
|
||||||
|
use libm::nextafterf;
|
||||||
|
|
||||||
pub const OUTLINE_SHADER_HANDLE: HandleUntyped =
|
const OUTLINE_SHADER_HANDLE: HandleUntyped =
|
||||||
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2101625026478770097);
|
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2101625026478770097);
|
||||||
|
|
||||||
#[derive(Clone, Component)]
|
#[derive(Clone, TypeUuid)]
|
||||||
|
#[uuid = "552e416b-2766-4e6a-9ee5-9ebd0e8c0230"]
|
||||||
pub struct Outline {
|
pub struct Outline {
|
||||||
pub colour: Color,
|
pub colour: Color,
|
||||||
pub offset: f32,
|
pub width: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderAsset for Outline {
|
||||||
|
type ExtractedAsset = Outline;
|
||||||
|
|
||||||
|
type PreparedAsset = GpuOutline;
|
||||||
|
|
||||||
|
type Param = (SRes<RenderDevice>, SRes<OutlinePipeline>);
|
||||||
|
|
||||||
|
fn extract_asset(&self) -> Self::ExtractedAsset {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_asset(
|
||||||
|
outline: Self::ExtractedAsset,
|
||||||
|
(render_device, outline_pipeline): &mut bevy::ecs::system::SystemParamItem<Self::Param>,
|
||||||
|
) -> Result<
|
||||||
|
Self::PreparedAsset,
|
||||||
|
bevy::render::render_asset::PrepareAssetError<Self::ExtractedAsset>,
|
||||||
|
> {
|
||||||
|
let colour = outline.colour.as_linear_rgba_f32().into();
|
||||||
|
let vbuffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
||||||
|
label: Some("outline_vertex_stage_uniform_buffer"),
|
||||||
|
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
||||||
|
contents: VertexStageData {
|
||||||
|
width: outline.width,
|
||||||
|
}
|
||||||
|
.as_std140()
|
||||||
|
.as_bytes(),
|
||||||
|
});
|
||||||
|
let fbuffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
||||||
|
label: Some("outline_fragment_stage_uniform_buffer"),
|
||||||
|
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
||||||
|
contents: FragmentStageData { colour }.as_std140().as_bytes(),
|
||||||
|
});
|
||||||
|
let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
||||||
|
label: Some("outline_bind_group"),
|
||||||
|
layout: &outline_pipeline.bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: vbuffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: fbuffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
Ok(GpuOutline {
|
||||||
|
_vertex_stage_buffer: vbuffer,
|
||||||
|
_fragment_stage_buffer: fbuffer,
|
||||||
|
bind_group,
|
||||||
|
transparent: colour.w < 1.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, AsStd140)]
|
||||||
|
struct VertexStageData {
|
||||||
|
width: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, AsStd140)]
|
||||||
|
struct FragmentStageData {
|
||||||
|
colour: Vec4,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GpuOutline {
|
||||||
|
_vertex_stage_buffer: Buffer,
|
||||||
|
_fragment_stage_buffer: Buffer,
|
||||||
|
bind_group: BindGroup,
|
||||||
|
transparent: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutlinePlugin;
|
pub struct OutlinePlugin;
|
||||||
|
|
||||||
fn extract_outline(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut previous_len: Local<usize>,
|
|
||||||
mut query: Query<(Entity, &Outline)>,
|
|
||||||
) {
|
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
|
||||||
for (entity, outline) in query.iter_mut() {
|
|
||||||
values.push((entity, (outline.clone(),)));
|
|
||||||
}
|
|
||||||
*previous_len = values.len();
|
|
||||||
commands.insert_or_spawn_batch(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plugin for OutlinePlugin {
|
impl Plugin for OutlinePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
load_internal_asset!(
|
load_internal_asset!(
|
||||||
@ -47,11 +119,14 @@ impl Plugin for OutlinePlugin {
|
|||||||
"outline.wgsl",
|
"outline.wgsl",
|
||||||
Shader::from_wgsl
|
Shader::from_wgsl
|
||||||
);
|
);
|
||||||
app.sub_app_mut(RenderApp)
|
app.add_asset::<Outline>()
|
||||||
|
.add_plugin(ExtractComponentPlugin::<Handle<Outline>>::default())
|
||||||
|
.add_plugin(RenderAssetPlugin::<Outline>::default())
|
||||||
|
.sub_app_mut(RenderApp)
|
||||||
|
.add_render_command::<Opaque3d, DrawOutline>()
|
||||||
.add_render_command::<Transparent3d, DrawOutline>()
|
.add_render_command::<Transparent3d, DrawOutline>()
|
||||||
.init_resource::<OutlinePipeline>()
|
.init_resource::<OutlinePipeline>()
|
||||||
.init_resource::<SpecializedMeshPipelines<OutlinePipeline>>()
|
.init_resource::<SpecializedMeshPipelines<OutlinePipeline>>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_outline)
|
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_outline);
|
.add_system_to_stage(RenderStage::Queue, queue_outline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,56 +135,139 @@ type DrawOutline = (
|
|||||||
SetItemPipeline,
|
SetItemPipeline,
|
||||||
SetMeshViewBindGroup<0>,
|
SetMeshViewBindGroup<0>,
|
||||||
SetMeshBindGroup<1>,
|
SetMeshBindGroup<1>,
|
||||||
|
SetOutlineBindGroup<2>,
|
||||||
DrawMesh,
|
DrawMesh,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
struct SetOutlineBindGroup<const I: usize>();
|
||||||
|
|
||||||
|
impl<const I: usize> EntityRenderCommand for SetOutlineBindGroup<I> {
|
||||||
|
type Param = (SRes<RenderAssets<Outline>>, SQuery<Read<Handle<Outline>>>);
|
||||||
|
fn render<'w>(
|
||||||
|
_view: Entity,
|
||||||
|
item: Entity,
|
||||||
|
(outlines, query): SystemParamItem<'w, '_, Self::Param>,
|
||||||
|
pass: &mut TrackedRenderPass<'w>,
|
||||||
|
) -> RenderCommandResult {
|
||||||
|
let outline_handle = query.get(item).unwrap();
|
||||||
|
let outline = outlines.into_inner().get(outline_handle).unwrap();
|
||||||
|
pass.set_bind_group(I, &outline.bind_group, &[]);
|
||||||
|
RenderCommandResult::Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn queue_outline(
|
fn queue_outline(
|
||||||
|
opaque_3d_draw_functions: Res<DrawFunctions<Opaque3d>>,
|
||||||
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
|
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
|
||||||
outline_pipeline: Res<OutlinePipeline>,
|
outline_pipeline: Res<OutlinePipeline>,
|
||||||
msaa: Res<Msaa>,
|
msaa: Res<Msaa>,
|
||||||
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
|
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
|
||||||
mut pipeline_cache: ResMut<PipelineCache>,
|
mut pipeline_cache: ResMut<PipelineCache>,
|
||||||
render_meshes: Res<RenderAssets<Mesh>>,
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
material_meshes: Query<(Entity, &MeshUniform, &Handle<Mesh>, &Outline)>,
|
render_outlines: Res<RenderAssets<Outline>>,
|
||||||
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
|
material_meshes: Query<(Entity, &MeshUniform, &Handle<Mesh>, &Handle<Outline>)>,
|
||||||
|
mut views: Query<(
|
||||||
|
&ExtractedView,
|
||||||
|
&mut RenderPhase<Opaque3d>,
|
||||||
|
&mut RenderPhase<Transparent3d>,
|
||||||
|
)>,
|
||||||
) {
|
) {
|
||||||
let draw_outline = transparent_3d_draw_functions
|
let draw_opaque_outline = opaque_3d_draw_functions
|
||||||
|
.read()
|
||||||
|
.get_id::<DrawOutline>()
|
||||||
|
.unwrap();
|
||||||
|
let draw_transparent_outline = transparent_3d_draw_functions
|
||||||
.read()
|
.read()
|
||||||
.get_id::<DrawOutline>()
|
.get_id::<DrawOutline>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let key = MeshPipelineKey::from_msaa_samples(msaa.samples)
|
let base_key = MeshPipelineKey::from_msaa_samples(msaa.samples)
|
||||||
| MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);
|
| MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);
|
||||||
|
|
||||||
for (view, mut transparent_phase) in views.iter_mut() {
|
for (view, mut opaque_phase, mut transparent_phase) in views.iter_mut() {
|
||||||
let view_matrix = view.transform.compute_matrix();
|
let inverse_view_matrix = view.transform.compute_matrix().inverse();
|
||||||
let view_row_2 = view_matrix.row(2);
|
let inverse_view_row_2 = inverse_view_matrix.row(2);
|
||||||
for (entity, mesh_uniform, mesh_handle, _) in material_meshes.iter() {
|
for (entity, mesh_uniform, mesh_handle, outline_handle) in material_meshes.iter() {
|
||||||
if let Some(mesh) = render_meshes.get(mesh_handle) {
|
if let Some(mesh) = render_meshes.get(mesh_handle) {
|
||||||
let pipeline = pipelines
|
if let Some(outline) = render_outlines.get(outline_handle) {
|
||||||
.specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout)
|
let key = if outline.transparent {
|
||||||
.unwrap();
|
base_key | MeshPipelineKey::TRANSPARENT_MAIN_PASS
|
||||||
transparent_phase.add(Transparent3d {
|
} else {
|
||||||
entity,
|
base_key
|
||||||
pipeline,
|
};
|
||||||
draw_function: draw_outline,
|
let pipeline = pipelines
|
||||||
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
|
.specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout)
|
||||||
});
|
.unwrap();
|
||||||
|
let distance = nextafterf(
|
||||||
|
inverse_view_row_2.dot(mesh_uniform.transform.col(3)),
|
||||||
|
f32::NEG_INFINITY,
|
||||||
|
);
|
||||||
|
if outline.transparent {
|
||||||
|
transparent_phase.add(Transparent3d {
|
||||||
|
entity,
|
||||||
|
pipeline,
|
||||||
|
draw_function: draw_transparent_outline,
|
||||||
|
distance,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
opaque_phase.add(Opaque3d {
|
||||||
|
entity,
|
||||||
|
pipeline,
|
||||||
|
draw_function: draw_opaque_outline,
|
||||||
|
distance: -distance,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OutlinePipeline {
|
pub struct OutlinePipeline {
|
||||||
mesh_pipeline: MeshPipeline,
|
mesh_pipeline: MeshPipeline,
|
||||||
|
bind_group_layout: BindGroupLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWorld for OutlinePipeline {
|
impl FromWorld for OutlinePipeline {
|
||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
let world = world.cell();
|
let world = world.cell();
|
||||||
let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap().clone();
|
let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap().clone();
|
||||||
OutlinePipeline { mesh_pipeline }
|
let render_device = world.get_resource::<RenderDevice>().unwrap();
|
||||||
|
let bind_group_layout =
|
||||||
|
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||||
|
label: Some("outline_pipeline_bind_group_layout"),
|
||||||
|
entries: &[
|
||||||
|
BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: ShaderStages::VERTEX,
|
||||||
|
ty: BindingType::Buffer {
|
||||||
|
ty: BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: BufferSize::new(
|
||||||
|
VertexStageData::std140_size_static() as u64,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: ShaderStages::FRAGMENT,
|
||||||
|
ty: BindingType::Buffer {
|
||||||
|
ty: BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: BufferSize::new(
|
||||||
|
FragmentStageData::std140_size_static() as u64,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
OutlinePipeline {
|
||||||
|
mesh_pipeline,
|
||||||
|
bind_group_layout,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,13 +281,12 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
|||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut descriptor = self.mesh_pipeline.specialize(key, layout)?;
|
let mut descriptor = self.mesh_pipeline.specialize(key, layout)?;
|
||||||
descriptor.primitive.cull_mode = Some(Face::Front);
|
descriptor.primitive.cull_mode = Some(Face::Front);
|
||||||
//descriptor.depth_stencil.as_mut().unwrap().depth_write_enabled = false;
|
|
||||||
//descriptor.depth_stencil.as_mut().unwrap().depth_compare = CompareFunction::Always;
|
|
||||||
descriptor.vertex.shader = OUTLINE_SHADER_HANDLE.typed();
|
descriptor.vertex.shader = OUTLINE_SHADER_HANDLE.typed();
|
||||||
descriptor.fragment.as_mut().unwrap().shader = OUTLINE_SHADER_HANDLE.typed();
|
descriptor.fragment.as_mut().unwrap().shader = OUTLINE_SHADER_HANDLE.typed();
|
||||||
descriptor.layout = Some(vec![
|
descriptor.layout = Some(vec![
|
||||||
self.mesh_pipeline.view_layout.clone(),
|
self.mesh_pipeline.view_layout.clone(),
|
||||||
self.mesh_pipeline.mesh_layout.clone(),
|
self.mesh_pipeline.mesh_layout.clone(),
|
||||||
|
self.bind_group_layout.clone(),
|
||||||
]);
|
]);
|
||||||
Ok(descriptor)
|
Ok(descriptor)
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,23 @@ struct VertexOutput {
|
|||||||
[[builtin(position)]] clip_position: vec4<f32>;
|
[[builtin(position)]] clip_position: vec4<f32>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VertexStageData {
|
||||||
|
width: f32;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentStageData {
|
||||||
|
colour: vec4<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
[[group(1), binding(0)]]
|
[[group(1), binding(0)]]
|
||||||
var<uniform> mesh: Mesh;
|
var<uniform> mesh: Mesh;
|
||||||
|
|
||||||
|
[[group(2), binding(0)]]
|
||||||
|
var<uniform> vstage: VertexStageData;
|
||||||
|
|
||||||
|
[[group(2), binding(1)]]
|
||||||
|
var<uniform> fstage: FragmentStageData;
|
||||||
|
|
||||||
fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> {
|
fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> {
|
||||||
return mat3x3<f32>(
|
return mat3x3<f32>(
|
||||||
m[0].xyz, m[1].xyz, m[2].xyz
|
m[0].xyz, m[1].xyz, m[2].xyz
|
||||||
@ -24,8 +38,8 @@ fn vertex(vertex: Vertex) -> VertexOutput {
|
|||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
var clip_pos = view.view_proj * (mesh.model * vec4<f32>(vertex.position, 1.0));
|
var clip_pos = view.view_proj * (mesh.model * vec4<f32>(vertex.position, 1.0));
|
||||||
var clip_norm = mat4to3(view.view_proj) * (mat4to3(mesh.model) * normalize(vertex.normal));
|
var clip_norm = mat4to3(view.view_proj) * (mat4to3(mesh.model) * normalize(vertex.normal));
|
||||||
var n_pos = clip_pos + vec4<f32>(50.0 * normalize(clip_norm.xy) * clip_pos.w / vec2<f32>(view.width, view.height), 0.0, 0.0);
|
var clip_delta = vec4<f32>(vstage.width * normalize(clip_norm.xy) * clip_pos.w / vec2<f32>(view.width, view.height), 0.0, 0.0);
|
||||||
out.clip_position = n_pos + vec4<f32>(0.0,0.0,0.0,0.0);
|
out.clip_position = clip_pos + clip_delta;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,5 +49,5 @@ struct FragmentInput {
|
|||||||
|
|
||||||
[[stage(fragment)]]
|
[[stage(fragment)]]
|
||||||
fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
||||||
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
|
return fstage.colour;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user