Port to Bevy 0.8.
This commit is contained in:
parent
e06fb383a3
commit
4627eaa093
13
Cargo.toml
13
Cargo.toml
@ -10,22 +10,19 @@ repository = "https://github.com/komadori/bevy_mod_outline/"
|
||||
keywords = ["gamedev", "bevy", "outline"]
|
||||
categories = ["game-engines", "rendering"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.7", default-features = false, features = [
|
||||
bevy = { version = "0.8", default-features = false, features = [
|
||||
"bevy_asset",
|
||||
"render",
|
||||
] }
|
||||
bevy_asset = { version = "0.7", default-features = false }
|
||||
libm = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
bevy = { version = "0.7", default-features = false, features = [
|
||||
bevy = { version = "0.8", default-features = false, features = [
|
||||
"bevy_winit",
|
||||
"x11",
|
||||
] }
|
||||
bevy_mod_rounded_box = "0.1"
|
||||
|
||||
[[example]]
|
||||
name = "cube"
|
||||
path = "examples/cube.rs"
|
||||
name = "torus"
|
||||
path = "examples/torus.rs"
|
@ -1,9 +1,8 @@
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::prelude::{shape::Torus, *};
|
||||
|
||||
use bevy_mod_outline::*;
|
||||
use bevy_mod_rounded_box::*;
|
||||
|
||||
#[bevy_main]
|
||||
fn main() {
|
||||
@ -34,10 +33,11 @@ fn setup(
|
||||
});
|
||||
commands
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(RoundedBox {
|
||||
size: Vec3::new(1., 1., 1.),
|
||||
radius: 0.3,
|
||||
subdivisions: 5,
|
||||
mesh: meshes.add(Mesh::from(Torus {
|
||||
radius: 0.6,
|
||||
ring_radius: 0.2,
|
||||
subdivisions_segments: 20,
|
||||
subdivisions_sides: 10,
|
||||
})),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
||||
@ -57,7 +57,7 @@ fn setup(
|
||||
transform: Transform::from_xyz(4.0, 8.0, 4.0),
|
||||
..default()
|
||||
});
|
||||
commands.spawn_bundle(PerspectiveCameraBundle {
|
||||
commands.spawn_bundle(Camera3dBundle {
|
||||
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
});
|
156
src/lib.rs
156
src/lib.rs
@ -1,5 +1,5 @@
|
||||
use bevy::asset::load_internal_asset;
|
||||
use bevy::core_pipeline::{Opaque3d, Transparent3d};
|
||||
use bevy::core_pipeline::core_3d::{Opaque3d, Transparent3d};
|
||||
use bevy::ecs::system::lifetimeless::{Read, SQuery, SRes};
|
||||
use bevy::ecs::system::SystemParamItem;
|
||||
use bevy::pbr::{
|
||||
@ -7,24 +7,24 @@ use bevy::pbr::{
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
use bevy::reflect::TypeUuid;
|
||||
use bevy::render::camera::{ActiveCamera, Camera3d};
|
||||
use bevy::render::extract_component::ExtractComponentPlugin;
|
||||
use bevy::render::mesh::{MeshVertexBufferLayout, PrimitiveTopology};
|
||||
use bevy::render::render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets};
|
||||
use bevy::render::render_component::ExtractComponentPlugin;
|
||||
use bevy::render::render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets};
|
||||
use bevy::render::render_phase::{
|
||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||
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, DynamicUniformVec, Face, PipelineCache, RenderPipelineDescriptor, ShaderStages,
|
||||
SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines,
|
||||
AsBindGroup, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout,
|
||||
BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize,
|
||||
DynamicUniformBuffer, Face, PipelineCache, PreparedBindGroup, RenderPipelineDescriptor,
|
||||
ShaderSize, ShaderStages, ShaderType, SpecializedMeshPipeline, SpecializedMeshPipelineError,
|
||||
SpecializedMeshPipelines,
|
||||
};
|
||||
use bevy::render::renderer::{RenderDevice, RenderQueue};
|
||||
use bevy::render::texture::FallbackImage;
|
||||
use bevy::render::view::ExtractedView;
|
||||
use bevy::render::{RenderApp, RenderStage};
|
||||
use bevy::render::{Extract, RenderApp, RenderStage};
|
||||
use libm::nextafterf;
|
||||
|
||||
// See https://alexanderameye.github.io/notes/rendering-outlines/
|
||||
@ -33,12 +33,14 @@ const OUTLINE_SHADER_HANDLE: HandleUntyped =
|
||||
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2101625026478770097);
|
||||
|
||||
/// An asset for rendering outlines around meshes.
|
||||
#[derive(Clone, TypeUuid)]
|
||||
#[derive(Clone, TypeUuid, AsBindGroup)]
|
||||
#[uuid = "552e416b-2766-4e6a-9ee5-9ebd0e8c0230"]
|
||||
pub struct Outline {
|
||||
/// Colour of the outline
|
||||
#[uniform(1, visibility(fragment))]
|
||||
pub colour: Color,
|
||||
/// Width of the outline in logical pixels
|
||||
#[uniform(0, visibility(vertex))]
|
||||
pub width: f32,
|
||||
}
|
||||
|
||||
@ -47,7 +49,12 @@ impl RenderAsset for Outline {
|
||||
|
||||
type PreparedAsset = GpuOutline;
|
||||
|
||||
type Param = (SRes<RenderDevice>, SRes<OutlinePipeline>);
|
||||
type Param = (
|
||||
SRes<RenderDevice>,
|
||||
SRes<OutlinePipeline>,
|
||||
SRes<RenderAssets<Image>>,
|
||||
SRes<FallbackImage>,
|
||||
);
|
||||
|
||||
fn extract_asset(&self) -> Self::ExtractedAsset {
|
||||
self.clone()
|
||||
@ -55,57 +62,35 @@ impl RenderAsset for Outline {
|
||||
|
||||
fn prepare_asset(
|
||||
outline: Self::ExtractedAsset,
|
||||
(render_device, outline_pipeline): &mut bevy::ecs::system::SystemParamItem<Self::Param>,
|
||||
(render_device, outline_pipeline, images, fallback_image): &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.outline_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,
|
||||
})
|
||||
if let Ok(pbg) = outline.as_bind_group(
|
||||
&outline_pipeline.outline_bind_group_layout,
|
||||
render_device,
|
||||
images,
|
||||
fallback_image,
|
||||
) {
|
||||
Ok(GpuOutline {
|
||||
bind_group: pbg,
|
||||
transparent: outline.colour.a() < 1.0,
|
||||
})
|
||||
} else {
|
||||
Err(PrepareAssetError::RetryNextUpdate(outline))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Component, AsStd140)]
|
||||
#[derive(Clone, Component, ShaderType)]
|
||||
struct ViewSizeUniform {
|
||||
logical_size: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ViewSizeUniforms {
|
||||
pub uniforms: DynamicUniformVec<ViewSizeUniform>,
|
||||
pub uniforms: DynamicUniformBuffer<ViewSizeUniform>,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
@ -117,20 +102,8 @@ struct GpuViewSize {
|
||||
bind_group: BindGroup,
|
||||
}
|
||||
|
||||
#[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,
|
||||
bind_group: PreparedBindGroup<Outline>,
|
||||
transparent: bool,
|
||||
}
|
||||
|
||||
@ -203,25 +176,23 @@ impl<const I: usize> EntityRenderCommand for SetOutlineBindGroup<I> {
|
||||
) -> 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, &[]);
|
||||
pass.set_bind_group(I, &outline.bind_group.bind_group, &[]);
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_view_size_uniforms(
|
||||
mut commands: Commands,
|
||||
windows: Res<Windows>,
|
||||
images: Res<Assets<Image>>,
|
||||
active_camera: Res<ActiveCamera<Camera3d>>,
|
||||
query: Query<&Camera, With<Camera3d>>,
|
||||
query: Extract<Query<(Entity, &Camera), With<Camera3d>>>,
|
||||
) {
|
||||
if let Some(entity) = active_camera.get() {
|
||||
if let Ok(camera) = query.get(entity) {
|
||||
if let Some(size) = camera.target.get_logical_size(&windows, &images) {
|
||||
commands
|
||||
.get_or_spawn(entity)
|
||||
.insert(ViewSizeUniform { logical_size: size });
|
||||
}
|
||||
for (entity, camera) in query.iter() {
|
||||
if !camera.is_active {
|
||||
continue;
|
||||
}
|
||||
if let Some(size) = camera.logical_viewport_size() {
|
||||
commands
|
||||
.get_or_spawn(entity)
|
||||
.insert(ViewSizeUniform { logical_size: size });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -348,43 +319,12 @@ impl FromWorld for OutlinePipeline {
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(
|
||||
ViewSizeUniform::std140_size_static() as u64
|
||||
),
|
||||
min_binding_size: BufferSize::new(ViewSizeUniform::SHADER_SIZE.get()),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
});
|
||||
let outline_bind_group_layout =
|
||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
label: Some("outline_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,
|
||||
},
|
||||
],
|
||||
});
|
||||
let outline_bind_group_layout = Outline::bind_group_layout(&render_device);
|
||||
OutlinePipeline {
|
||||
mesh_pipeline,
|
||||
view_size_bind_group_layout,
|
||||
|
@ -1,37 +1,37 @@
|
||||
#import bevy_pbr::mesh_view_bind_group
|
||||
#import bevy_pbr::mesh_struct
|
||||
#import bevy_pbr::mesh_types
|
||||
#import bevy_pbr::mesh_view_bindings
|
||||
|
||||
struct Vertex {
|
||||
[[location(0)]] position: vec3<f32>;
|
||||
[[location(1)]] normal: vec3<f32>;
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
[[builtin(position)]] clip_position: vec4<f32>;
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
};
|
||||
|
||||
struct ViewSizeUniforms {
|
||||
logical_size: vec2<f32>;
|
||||
logical_size: vec2<f32>,
|
||||
};
|
||||
|
||||
struct VertexStageData {
|
||||
width: f32;
|
||||
width: f32,
|
||||
};
|
||||
|
||||
struct FragmentStageData {
|
||||
colour: vec4<f32>;
|
||||
colour: vec4<f32>,
|
||||
};
|
||||
|
||||
[[group(1), binding(0)]]
|
||||
@group(1) @binding(0)
|
||||
var<uniform> mesh: Mesh;
|
||||
|
||||
[[group(2), binding(0)]]
|
||||
@group(2) @binding(0)
|
||||
var<uniform> view_size: ViewSizeUniforms;
|
||||
|
||||
[[group(3), binding(0)]]
|
||||
@group(3) @binding(0)
|
||||
var<uniform> vstage: VertexStageData;
|
||||
|
||||
[[group(3), binding(1)]]
|
||||
@group(3) @binding(1)
|
||||
var<uniform> fstage: FragmentStageData;
|
||||
|
||||
fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> {
|
||||
@ -40,7 +40,7 @@ fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> {
|
||||
);
|
||||
}
|
||||
|
||||
[[stage(vertex)]]
|
||||
@vertex
|
||||
fn vertex(vertex: Vertex) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
var clip_pos = view.view_proj * (mesh.model * vec4<f32>(vertex.position, 1.0));
|
||||
@ -50,11 +50,7 @@ fn vertex(vertex: Vertex) -> VertexOutput {
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragmentInput {
|
||||
[[builtin(front_facing)]] is_front: bool;
|
||||
};
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
||||
@fragment
|
||||
fn fragment() -> @location(0) vec4<f32> {
|
||||
return fstage.colour;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user