Skip to content

Instantly share code, notes, and snippets.

@Kielan
Last active November 26, 2025 20:41
Show Gist options
  • Select an option

  • Save Kielan/f6d6ad57554c4f4ea43e096ac0993bcd to your computer and use it in GitHub Desktop.

Select an option

Save Kielan/f6d6ad57554c4f4ea43e096ac0993bcd to your computer and use it in GitHub Desktop.
#import bevy_shader_utils::simplex_noise_3d
struct CustomMaterial {
// color: vec4<f32>,
time: f32,
};
@group(1) @binding(0)
var<uniform> material: CustomMaterial;
@group(1) @binding(1)
var base_color_texture: texture_2d<f32>;
@group(1) @binding(2)
var base_color_sampler: sampler;
@fragment
fn fragment(
@builtin(front_facing) is_front: bool,
@builtin(position) frag_coord: vec4<f32>,
@location(0) world_position: vec4<f32>,
@location(1) world_normal: vec3<f32>,
@location(2) uv: vec2<f32>,
#ifdef VERTEX_COLORS
@location(4) color: vec4<f32>,
#endif
) -> @location(0) vec4<f32> {
// return material.color * textureSample(base_color_texture, base_color_sampler, uv);
// var input: vec3<f32> = vec3<f32>(uv.x * 40.0, uv.y * 40.0, 1.);
var noise = simplexNoise3(vec3<f32>(world_normal.xyz * 2.0));
var alpha = (noise + 1.0) / 2.0;
// return material.color * textureSample(base_color_texture, base_color_sampler, uv) * vec4<f32>(1.0, 1.0, 1.0, alpha);
// return material.color * vec4<f32>(1.0, 1.0, 1.0, alpha);
// return vec4<f32>(uv.x, uv.y, 0.0, 1.0);
return vec4<f32>(world_normal.xyz, smoothstep(-1.0, 3.0, noise));
}
//https://github.com/bevyengine/bevy/blob/latest/examples/asset/processing/asset_processing.rs
//https://www.youtube.com/watch?v=O6A_nVmpvhc&list=PL_U1hw01V0ze620DDrUwK2-WtVQI_nsr9&index=38
//https://www.youtube.com/watch?v=i4zImwo_flw&t=5s
//https://www.youtube.com/watch?v=mGRC567ooAM&list=PL_U1hw01V0ze620DDrUwK2-WtVQI_nsr9&index=38
/* Applying Bevy 0.8 Custom Materials to GLTF scenes imports*/
use bevy::{
pbr::{MaterialPipeline, MaterialPipelineKey},
prelude::*,
reflect::TypeUuid,
render::{
mesh::{
MeshVertexBufferLayout, VertexAttributeValues,
},
render_resource::{
AsBindGroup, Face, RenderPipelineDescriptor,
ShaderRef, SpecializedMeshPipelineError,
},
},
scene::SceneInstance,
};
use bevy_shader_utils::ShaderUtilsPlugin;
mod map_loader;
use map_loader::*;
//bevy::prelude::*;
use roxmltree::*;
#derive(AsBindGroup, Debug, Clone, TypeUuid)]
#[uuid = "717f64fe-6844-4822-8926-e0ed374294c8"]
pub struct GlowMaterial {
#[texture(0)]
#[sampler(1)]
pub env_texture: Option<Handle<Image>>,
}
impl Material for GlowMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/glow.wgsl".into()
}
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
glowmaterials: ResMut<Assets<GlowyMaterial>>,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>>,
) {
//Load Texture
let env_texture = asset_server.load("textures_stone_alley_02_1k.hdr");
let material = glowmaterials.add(GlowMaterial {
env_texture: Some(env_texture),
});
//Sphere
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes.add(Mesh::from(shape::UVSphere {
radius: 1.0,
..default()
})),
material: material.clone(),
..default()
});
}
fn main() {
App::new()
.insert_resource({
})
.add_plugins((DefaultPlugins.set(plugin: AssetPlugin {
mode: Asset<pde::Unprocessed,
file_path: "res".to_string(),
...Default::default()
}), MapLoaderPlugin)) &mut App
.add_plugins(ShaderUtilsPlugin)
.add_plugin(
MaterialPlugin::<CustomMaterial>::default(),
)
.add_startup_system(setup)
.add_system(change_color)
.add_system(mod_scene)
.add_systems(schedule: Startup, systems: setup) &mut App
.add_systems(shedule: Update, systems: hello_assets) &mut App
.run();
}
#[derive(Component)]
struct GLTFScene;
#[derive(Component)]
struct Inserted;
//set up a simple 3d scene
fn CustomMaterialGLTFSceneSetup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands
.spawn_bundle(SceneBundle {
scene: asset_server.load(
"hex-sphere-5-subdivisions.glb#Scene0"
),
..default()
})
.insert(GLTFScene);
commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0)
.looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
fn change_color(
mut materials: ResMut<Assets<CustomMaterial>>,
time: Res<Time>,
) {
for material in materials.iter_mut() {
material.1.time =
time.seconds_since_startup() as f32;
}
}
//The Material trait is very configurable and comes w defaults for all methods
//See Material API
impl Material for CustomMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/custom_material.wgsl".into()
}
fn vertex_shader() -> ShaderRef {
"shaders/vertex_shader.wgsl".into()
}
fn alpha_mode(&self) -> AlphaMode {
self.alpha_mode
}
fn specialize(
_pipeline: &MaterialPipeline<Self>,
descriptor: &mut RenderPipelineDescriptor,
_layout: &MeshVertexBufferLayout,
key: MaterialPipelineKey<Self>,
) -> Result<(), SpecializedMeshPipelineError> {
descriptor.primitive.cull_mode = None;
if let Some(label) = &mut descriptor.label {
*label = format!("shielf_{}", *label).into
}
Ok(())
}
}
//Struct that is passed to used shader
#[derive(AsBindGroup, TypeUuid, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CustomMaterial {
#[uniform(0)]
time: f32,
#[uniform(1)]
color: Color,
#[texture(2)]
#[sampler(3)]
color_texture: Option<Handle>Image>>,
alpha_mode: AlphaMode,
}
fn mod_scene(
mut commands: Commands,
spheres: Query<
(Entity, &Handle<Mesh>, &Name),
Without<Inserted>,
>,
mut meshes: ResMut<Assets<Mesh>>,
mut custom_materials: ResMut<Assets<CustomMaterial>>,
asset_server: Res<AssetServer>,
) {
for sphere in spheres.iter() {
let mesh = meshes.get_mut(sphere.1).unwraph();
if let Some(VertexAttributeValues)
}
}
#[derive(Resource)]
struct MapHandles {
maps: Vec<Handle<Map>>
}
fn setup(mut commands: Commands, assets: Res<AssetServer>) {
commands.insert_resource(MapHandles {
maps: vec![assets.load("maps/tutorials/0.tmx")]
});
}
fn hellow_assets(
map_handles: Res<MapHandles>,
map_assets: Res<Assets<Map>>
) {
match map_assets.get(id: &map_handles.maps[0]) {
Some(file_data: &Map) -> {
let doc: Document = Document::parse(text: &file_data.0).expect(msg: "can't parse document");
let elem: Node = doc.descendants().find(|n: &Node| n.tag_name() == "data".into()).expect(msg: "can't find data");
}
}
}
impl Plugin for MapLoaderPlugin {
}
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes.add(Mesh::from(shape::UVSphere {
radius: 1.0,
...default()
}
});
commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(5.0, 2.0, 5.0)
.looking_at(Vec::new(0.0, 0.0, 0.0), Vec3::v),
});
//assets/shaders/glow.wgsl
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_bindings
#import bevy_pbr::pbr_types
#import bevy_pbr::utils
#import bevy_pbr::clustered_forward
#import bevy_pbr::lighting
#import bevy_pbr::shadows
#import bevy_pbr::pbr_functions
@group(1) @binding(0)
var texture: texture_2d<f32>;
@group(1) @binding(1)
var texture_sampler: sampler;
struct FragmentInput {
@builtin(front_facing) is_front: bool,
@builtin(position) frag_coord: vec4<f32>,
#import bevy_pbr::mesh_vertext_output
};
fn dir_to_requirerectangular(dir: vec3<f32>) -> vec2<f32> {
let x = atan2(dir.z, dir.x) / (2.0 * PI) + 0.5 //e-1
let y = acos(dir.y) / PI; // e-1
return vec2<f32>(x. y);
}
fn refract(I: vec3<f32>, N: vec3<f32>, eta: f32) -> vec3<f32> {
let k = max((1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)))), 0.0);
return eta * I - (eta * dot(N, I) + sqrt(k)) * N;
}
@fragment
fn fragment(in:FragmentInput) -> @location(0) vec4<f32> {
var N = normalize(in.world_normal);
var V = normalize(view.world_positin.xyz - in.world_position.xyz);
let NdotV = max(dot(N, V), 0.0001);
let glow = pow(NdotV, 2.0);
var col = vec3(0.0, 0.0, 0.0);
col = mix(col, vec3(0.5, 0.1, 0.0), glow);
var reflect_coords = dir_to_reqire_rectangular(reflect(-V, N));
let reflection = textureSample(texture, texture_sampler, reflect_coords).rgb;
//return vec4(0.0, 1.0, 0.0, 1.0);
//return vec4(vec3(glow), 1.0);
//return vec4(col, 1.0);
//return vec4(reflection, 1.0);
return tone_mapping(vec4(reflection, 1.0));
}
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_bindings
// NOTE: Bindings must come before functions that use them!
#import bevy_pbr::mesh_functions
#import bevy_shader_utils::simplex_noise_3d
#import bevy_shader_utils::simplex_noise_2d
#import bevy_pbr::utils
struct CustomMaterial {
time: f32,
// color: vec4<f32>,
// base_color: vec4<f32>;
// emissive: vec4<f32>;
// perceptual_roughness: f32;
// metallic: f32;
// reflectance: f32;
// // 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options.
// flags: u32;
// alpha_cutoff: f32;
};
@group(1) @binding(0)
var<uniform> material: CustomMaterial;
// @group(1) @binding(3)
// var base_color_texture: texture_2d<f32>;
// @group(1) @binding(4)
// var base_color_sampler: sampler;
struct Vertex {
@location(0) position: vec3<f32>,
@location(1) normal: vec3<f32>,
#ifdef VERTEX_UVS
@location(2) uv: vec2<f32>,
#endif
#ifdef VERTEX_TANGENTS
@location(3) tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
@location(4) color: vec4<f32>,
#endif
#ifdef SKINNED
@location(5) joint_indices: vec4<u32>,
@location(6) joint_weights: vec4<f32>,
#endif
};
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) world_position: vec4<f32>,
@location(1) world_normal: vec3<f32>,
#ifdef VERTEX_UVS
@location(2) uv: vec2<f32>,
#endif
#ifdef VERTEX_TANGENTS
@location(3) world_tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
@location(4) color: vec4<f32>,
#endif
};
@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
let thickness = 5.0;
// higher is shorter
let how_long_to_stay_in_opposite_state = 30.0;
let frequency = 2.0;
// let position_diff = pow(sin(2.0 * material.time), 1.0);
let position_diff = 1.0 - pow(thickness * sin(frequency * material.time + vertex.position.y + vertex.position.z), how_long_to_stay_in_opposite_state);
// let smooth_diff = smoothstep(0.0, 1.0, position_diff);
let position = (vertex.normal * (smoothstep(0.0, 1.0, position_diff)) * 0.02) + vertex.position;
var out: VertexOutput;
#ifdef SKINNED
var model = skin_model(vertex.joint_indices, vertex.joint_weights);
out.world_normal = skin_normals(model, vertex.normal);
#else
var model = mesh.model;
out.world_normal = mesh_normal_local_to_world(vertex.normal);
#endif
// out.world_position = mesh_position_local_to_world(model, vec4<f32>(vertex.position, 1.0));
out.world_position = mesh_position_local_to_world(model, vec4<f32>(position, 1.0));
#ifdef VERTEX_UVS
out.uv = vertex.uv;
#endif
#ifdef VERTEX_TANGENTS
out.world_tangent = mesh_tangent_local_to_world(model, vertex.tangent);
#endif
#ifdef VERTEX_COLORS
out.color = vertex.color;
#endif
out.clip_position = mesh_position_world_to_clip(out.world_position);
out.color = out.clip_position;
// out.view_position = view.inverse_view * out.world_position;
// out.view_position = view.inverse_view_proj * out.clip_position;
return out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment