Skip to content

Instantly share code, notes, and snippets.

@ChristopherBiscardi
Created July 17, 2022 09:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChristopherBiscardi/9260184e71b40035ca874d6c4781da6a to your computer and use it in GitHub Desktop.
Save ChristopherBiscardi/9260184e71b40035ca874d6c4781da6a to your computer and use it in GitHub Desktop.
land-vertex exploration
#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
struct StandardMaterial {
time: 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: StandardMaterial;
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 {
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));
#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
var noise = simplexNoise3(vertex.position);
// out.color = vec4<f32>(vertex.position.x, noise, vertex.position.z, 1.0);
out.color = vec4<f32>(vertex.uv.x, noise, vertex.uv.y, 1.0);
out.world_position = mesh_position_local_to_world(model, vec4<f32>(vertex.position.x, noise, vertex.position.z, 1.0));
// out.world_position.x = -100.0;
out.clip_position = mesh_position_world_to_clip(out.world_position);
return out;
}
//! Loads and renders a glTF file as a scene.
use bevy::{
pbr::wireframe::{
Wireframe, WireframeConfig, WireframePlugin,
},
prelude::*,
reflect::TypeUuid,
render::{
mesh::{
Indices, PrimitiveTopology,
VertexAttributeValues,
},
render_resource::{AsBindGroup, ShaderRef},
},
render::{
render_resource::WgpuFeatures,
settings::WgpuSettings,
},
};
use bevy_shader_utils::ShaderUtilsPlugin;
use itertools::Itertools;
fn main() {
App::new()
.insert_resource(AmbientLight {
color: Color::WHITE,
brightness: 1.0 / 5.0f32,
})
.insert_resource(ClearColor(
Color::hex("071f3c").unwrap(),
))
.insert_resource(WgpuSettings {
features: WgpuFeatures::POLYGON_MODE_LINE,
..default()
})
.add_plugins(DefaultPlugins)
.add_plugin(WireframePlugin)
.add_plugin(ShaderUtilsPlugin)
.add_plugin(
MaterialPlugin::<LandMaterial>::default(),
)
.add_startup_system(setup)
.add_system(animate_light_direction)
.add_system(movement)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<LandMaterial>>,
mut standard_materials: ResMut<
Assets<StandardMaterial>,
>,
asset_server: Res<AssetServer>,
) {
commands
.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(0.0, 1.5, 10.0)
.looking_at(
Vec3::new(0.0, 0.3, 0.0),
Vec3::Y,
),
..default()
})
.insert(Movable);
const HALF_SIZE: f32 = 1.0;
commands.spawn_bundle(DirectionalLightBundle {
directional_light: DirectionalLight {
shadow_projection: OrthographicProjection {
left: -HALF_SIZE,
right: HALF_SIZE,
bottom: -HALF_SIZE,
top: HALF_SIZE,
near: -10.0 * HALF_SIZE,
far: 10.0 * HALF_SIZE,
..default()
},
shadows_enabled: true,
..default()
},
..default()
});
// land
let mut land = Mesh::from(Land {
size: 1000.0,
num_vertices: 1000,
});
if let Some(VertexAttributeValues::Float32x3(
positions,
)) = land.attribute(Mesh::ATTRIBUTE_POSITION)
{
let colors: Vec<[f32; 4]> = positions
.iter()
.map(|[r, g, b]| {
[
(1. - *r) / 2.,
(1. - *g) / 2.,
(1. - *b) / 2.,
1.,
]
})
.collect();
land.insert_attribute(
Mesh::ATTRIBUTE_COLOR,
colors,
);
}
commands
.spawn()
.insert_bundle(MaterialMeshBundle {
mesh: meshes.add(land),
transform: Transform::from_xyz(0.0, 0.5, 0.0),
material: materials.add(LandMaterial {
time: 0.,
alpha_mode: AlphaMode::Blend,
}),
// material: standard_materials.add(
// StandardMaterial {
// base_color: Color::WHITE,
// ..default()
// },
// ),
..default()
})
.insert(Wireframe);
// ship
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes
.add(Mesh::from(shape::Cube { size: 1.0 })),
transform: Transform::from_xyz(0.0, 1.5, 0.0),
material: standard_materials.add(
StandardMaterial {
base_color: Color::BLUE,
..default()
},
),
..default()
});
// commands.spawn_bundle(SceneBundle {
// scene: asset_server
// .load("craft/craft_racer.glb#Scene0"),
// // scene: asset_server
// // .load("racecar/raceCarGreen.glb/#Scene0"),
// ..default()
// });
// let my_gltf =
// asset_server.load("craft/craft_racer.glb#Scene0");
}
fn animate_light_direction(
time: Res<Time>,
mut query: Query<
&mut Transform,
With<DirectionalLight>,
>,
) {
for mut transform in &mut query {
transform.rotation = Quat::from_euler(
EulerRot::ZYX,
0.0,
time.seconds_since_startup() as f32
* std::f32::consts::TAU
/ 10.0,
-std::f32::consts::FRAC_PI_4,
);
}
}
fn change_color(
mut materials: ResMut<Assets<LandMaterial>>,
time: Res<Time>,
) {
for material in materials.iter_mut() {
material.1.time =
time.seconds_since_startup() as f32;
}
}
/// The Material trait is very configurable, but comes with sensible defaults for all methods.
/// You only need to implement functions for features that need non-default behavior. See the Material api docs for details!
impl Material for LandMaterial {
// fn fragment_shader() -> ShaderRef {
// "shaders/custom_material.wgsl".into()
// }
fn vertex_shader() -> ShaderRef {
"shaders/land_vertex_shader.wgsl".into()
}
fn alpha_mode(&self) -> AlphaMode {
self.alpha_mode
}
}
// This is the struct that will be passed to your shader
#[derive(AsBindGroup, TypeUuid, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct LandMaterial {
#[uniform(0)]
time: f32,
alpha_mode: AlphaMode,
}
#[derive(Debug, Copy, Clone)]
struct Land {
size: f32,
num_vertices: u32,
}
impl From<Land> for Mesh {
fn from(plane: Land) -> Self {
let extent = plane.size / 2.0;
let jump = extent / plane.num_vertices as f32;
let vertices = (0..=plane.num_vertices)
.cartesian_product(0..=plane.num_vertices)
.map(|(x, y)| {
(
[
x as f32 * jump - 0.5 * extent,
0.0,
y as f32 * jump - 0.5 * extent,
],
[0.0, 1.0, 0.0],
[
x as f32
/ plane.num_vertices as f32,
y as f32
/ plane.num_vertices as f32,
],
)
})
.collect::<Vec<_>>();
// let vertices = [
// (
// [extent, 0.0, -extent],
// [0.0, 1.0, 0.0],
// [1.0, 1.0],
// ),
// (
// [extent, 0.0, extent],
// [0.0, 1.0, 0.0],
// [1.0, 0.0],
// ),
// (
// [-extent, 0.0, extent],
// [0.0, 1.0, 0.0],
// [0.0, 0.0],
// ),
// (
// [-extent, 0.0, -extent],
// [0.0, 1.0, 0.0],
// [0.0, 1.0],
// ),
// ];
// let indices = Indices::U32(vec![0, 2, 1, 0, 3, 2]);
let indices = Indices::U32(
(0..=plane.num_vertices)
.cartesian_product(0..=plane.num_vertices)
.enumerate()
.filter_map(|(index, (x, y))| {
if y >= plane.num_vertices {
None
} else if x >= plane.num_vertices {
None
} else {
Some([
[
index as u32,
index as u32 + 1,
index as u32
+ 1
+ plane.num_vertices,
],
[
index as u32,
index as u32
+ plane.num_vertices
+ 1,
index as u32
+ plane.num_vertices,
],
])
}
})
.flatten()
.flatten()
.collect::<Vec<_>>(),
);
dbg!(&indices.iter().take(6).collect::<Vec<_>>());
let positions: Vec<_> =
vertices.iter().map(|(p, _, _)| *p).collect();
let normals: Vec<_> =
vertices.iter().map(|(_, n, _)| *n).collect();
let uvs: Vec<_> =
vertices.iter().map(|(_, _, uv)| *uv).collect();
let mut mesh =
Mesh::new(PrimitiveTopology::TriangleList);
mesh.set_indices(Some(indices));
mesh.insert_attribute(
Mesh::ATTRIBUTE_POSITION,
positions,
);
mesh.insert_attribute(
Mesh::ATTRIBUTE_NORMAL,
normals,
);
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
mesh
}
}
#[derive(Component)]
struct Movable;
fn movement(
input: Res<Input<KeyCode>>,
time: Res<Time>,
mut query: Query<&mut Transform, With<Movable>>,
) {
for mut transform in query.iter_mut() {
let mut direction = Vec3::ZERO;
if input.pressed(KeyCode::Up) {
direction.z += 1.0;
}
if input.pressed(KeyCode::Down) {
direction.z -= 1.0;
}
if input.pressed(KeyCode::Left) {
direction.x -= 1.0;
}
if input.pressed(KeyCode::Right) {
direction.x += 1.0;
}
transform.translation +=
time.delta_seconds() * 2.0 * direction;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment