Skip to content

Instantly share code, notes, and snippets.

@DGriffin91
Last active November 25, 2024 04:16
Show Gist options
  • Save DGriffin91/c3591937b1364f8a2626ac98db8ae9c2 to your computer and use it in GitHub Desktop.
Save DGriffin91/c3591937b1364f8a2626ac98db8ae9c2 to your computer and use it in GitHub Desktop.
bs13_custom_material_example
#include "mesh_type.hlsl"
#include "shader_util.hlsl"
#include "view_model_type.hlsl"
cbuffer ubo : register(b0, space1)
{
ViewUniform view;
}
struct CustomMaterial
{
float4 base_color;
uint spare1;
uint spare2;
uint spare3;
uint spare4;
};
[[vk::binding(1, 0)]]
ByteAddressBuffer vertex_buffer : register(t0, space0);
[[vk::binding(2, 0)]]
StructuredBuffer<uint> index_buffer : register(t0, space0);
[[vk::binding(1, 1)]]
StructuredBuffer<DynInstanceData> object_instance : register(t0, space1);
[[vk::binding(2, 1)]]
ByteAddressBuffer materials : register(t0, space1);
REFLECT(CustomMaterial)
struct VertexOutput
{
float4 position : SV_Position;
uint instance_index : INSTANCE_INDEX;
};
VertexOutput vertex_main(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID)
{
DynInstanceData instance = object_instance[instance_id];
VertexData vert = vertex_buffer.Load<VertexData>(instance.first_vertex_byte_offset + index_buffer[vertex_id] * sizeof(VertexData));
VertexOutput output;
float3 world_position = instance.position_local_to_world(vert.position);
output.position = view.position_jittered_world_to_clip(world_position);
output.instance_index = instance_id;
return output;
}
float4 fragment_main(VertexOutput input)
: SV_TARGET
{
uint instance_material_offset = object_instance[input.instance_index].material_index;
CustomMaterial material = materials.Load<CustomMaterial>(instance_material_offset * 4);
return material.base_color;
}
use std::path::Path;
use bevy::{
prelude::*,
render::{settings::WgpuSettings, RenderPlugin},
};
use bs13_render::{
dyn_material::DynMaterialArchetypes,
dyn_material_pipeline::dyn_layout_from_frag,
dyn_material_type::{
DynMaterial, DynMaterialArchetype, DynMaterialHandle, DynMaterialPipelineBitFlag,
DynMaterialPipelineKey,
},
BS13PluginsSet,
};
use bytemuck::{Pod, Zeroable};
use dyn_pod_struct::DynLayout;
use glam::vec4;
fn main() {
App::new()
.add_plugins((
DefaultPlugins.set(RenderPlugin {
// Disable bevy's default render backend
render_creation: WgpuSettings {
backends: None,
..default()
}
.into(),
..default()
}),
BS13PluginsSet,
))
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
archetypes: Res<DynMaterialArchetypes>,
mut meshes: ResMut<Assets<Mesh>>,
) {
let shader_path = Path::new("assets/shaders/custom_material.hlsl");
// Generate shader material struct layout from shader code
let layout = dyn_layout_from_frag(shader_path, "fragment_main", "CustomMaterial");
// Create material archetype asset
let archetype_id = archetypes.add(DynMaterialArchetype {
layout: layout.clone(),
shader: shader_path.to_path_buf(),
..default()
});
// Create pipeline key from archetype and pipeline options (Things like alpha blend could be specified here)
let main_key = DynMaterialPipelineKey::new(
DynMaterialPipelineBitFlag::ALPHA_BLEND,
archetype_id,
archetypes.clone(),
);
// Create material data
let material_data = CustomMaterial {
base_color: vec4(1.0, 0.0, 1.0, 1.0),
..default()
};
// Create material instance that includes this material data, key and layout.
// Layout is included here directly so the archetype asset doesn't need to be accessed to reflect the material data.
let dyn_material = DynMaterial::default_prepass(&material_data, main_key, layout);
// Get handle for material asset. Using an entity for the asset here because of performance issues with using
// the asset system directly with large quantities of materials.
let material_h = DynMaterialHandle(commands.spawn(dyn_material).id());
// Spawn an entity with a Bevy mesh, SpatialBundle, and the DynMaterialHandle.
commands.spawn((
meshes.add(Cuboid::new(1.0, 1.0, 1.0)),
SpatialBundle {
transform: Transform::from_xyz(0.0, 0.5, 0.0),
..default()
},
material_h,
));
// Spawn a camera
commands.spawn((Camera3dBundle {
transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
},));
}
// The DynLayout derive here will allow us to reflect the layout of the fields and generate a DynLayout.
// A DynLayout can also be generated by reflecting spirv shader code.
#[repr(C)]
#[derive(DynLayout, Copy, Clone, Default, Pod, Zeroable, Debug)]
pub struct CustomMaterial {
base_color: Vec4,
spare1: u32,
spare2: u32,
spare3: u32,
spare4: u32,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment