mandelbulb
This commit is contained in:
parent
2598c9420e
commit
fabfefbf50
2 changed files with 66 additions and 27 deletions
|
|
@ -9,13 +9,51 @@ struct VoluMaterial {
|
|||
mesh_translation: vec3<f32>,
|
||||
sphere_radius: f32,
|
||||
color: vec4<f32>,
|
||||
model_inverse: mat4x4<f32>,
|
||||
power: f32,
|
||||
iterations: i32,
|
||||
}
|
||||
|
||||
@group(2) @binding(100)
|
||||
var<storage, read> volu_material: VoluMaterial;
|
||||
|
||||
fn sphere_sdf(p: vec3<f32>, center: vec3<f32>, radius: f32) -> f32 {
|
||||
return length(p - center) - radius;
|
||||
fn mandelbulb_sdf(p: vec3<f32>) -> f32 {
|
||||
var z = p;
|
||||
var dr = 1.0;
|
||||
var r = 0.0;
|
||||
let power = volu_material.power;
|
||||
let iterations = volu_material.iterations;
|
||||
|
||||
for (var i = 0; i < iterations; i++) {
|
||||
r = length(z);
|
||||
if r > 2.0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let theta = acos(clamp(z.z / r, -1.0, 1.0));
|
||||
let phi = atan2(z.y, z.x);
|
||||
dr = pow(r, power - 1.0) * power * dr + 1.0;
|
||||
|
||||
let zr = pow(r, power);
|
||||
let new_theta = theta * power;
|
||||
let new_phi = phi * power;
|
||||
|
||||
z = zr * vec3<f32>(
|
||||
sin(new_theta) * cos(new_phi),
|
||||
sin(new_theta) * sin(new_phi),
|
||||
cos(new_theta)
|
||||
) + p;
|
||||
}
|
||||
|
||||
return 0.5 * log(max(r, 0.001)) * r / dr;
|
||||
}
|
||||
|
||||
fn mandelbulb_normal(p: vec3<f32>) -> vec3<f32> {
|
||||
let e = 0.001;
|
||||
let dx = mandelbulb_sdf(p + vec3<f32>(e, 0.0, 0.0)) - mandelbulb_sdf(p - vec3<f32>(e, 0.0, 0.0));
|
||||
let dy = mandelbulb_sdf(p + vec3<f32>(0.0, e, 0.0)) - mandelbulb_sdf(p - vec3<f32>(0.0, e, 0.0));
|
||||
let dz = mandelbulb_sdf(p + vec3<f32>(0.0, 0.0, e)) - mandelbulb_sdf(p - vec3<f32>(0.0, 0.0, e));
|
||||
return normalize(vec3<f32>(dx, dy, dz));
|
||||
}
|
||||
|
||||
fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
||||
|
|
@ -26,7 +64,7 @@ fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
|||
|
||||
for (var i = 0; i < max_steps; i++) {
|
||||
let current_pos = ray_origin + t * ray_direction;
|
||||
let distance = sphere_sdf(current_pos, volu_material.mesh_translation, volu_material.sphere_radius);
|
||||
let distance = mandelbulb_sdf(current_pos);
|
||||
|
||||
if distance < epsilon {
|
||||
return t;
|
||||
|
|
@ -42,20 +80,6 @@ fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
|||
return -1.0;
|
||||
}
|
||||
|
||||
fn sphere_normal(p: vec3<f32>) -> vec3<f32> {
|
||||
let epsilon = 0.001;
|
||||
let center = volu_material.mesh_translation;
|
||||
let radius = volu_material.sphere_radius;
|
||||
|
||||
let gradient = vec3<f32>(
|
||||
sphere_sdf(p + vec3<f32>(epsilon, 0.0, 0.0), center, radius) - sphere_sdf(p - vec3<f32>(epsilon, 0.0, 0.0), center, radius),
|
||||
sphere_sdf(p + vec3<f32>(0.0, epsilon, 0.0), center, radius) - sphere_sdf(p - vec3<f32>(0.0, epsilon, 0.0), center, radius),
|
||||
sphere_sdf(p + vec3<f32>(0.0, 0.0, epsilon), center, radius) - sphere_sdf(p - vec3<f32>(0.0, 0.0, epsilon), center, radius)
|
||||
);
|
||||
|
||||
return normalize(gradient);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
vertex_output: VertexOutput,
|
||||
|
|
@ -66,20 +90,27 @@ fn fragment(
|
|||
let ray_origin = view.world_position;
|
||||
let ray_direction = normalize(in.world_position.xyz - view.world_position);
|
||||
|
||||
let t = raymarch(ray_origin, ray_direction);
|
||||
let local_origin = (volu_material.model_inverse * vec4<f32>(ray_origin, 1.0)).xyz;
|
||||
let local_direction = normalize((volu_material.model_inverse * vec4<f32>(ray_direction, 0.0)).xyz);
|
||||
|
||||
let t = raymarch(local_origin, local_direction);
|
||||
|
||||
var out: FragmentOutput;
|
||||
|
||||
if t > 0.0 {
|
||||
let hit_point = ray_origin + t * ray_direction;
|
||||
let normal = sphere_normal(hit_point);
|
||||
let local_hit_point = ray_origin + t * ray_direction;
|
||||
let local_normal = mandelbulb_normal(local_hit_point);
|
||||
|
||||
in.world_position = vec4<f32>(hit_point, 1.0);
|
||||
in.world_normal = normal;
|
||||
let world_hit_point = (transpose(volu_material.model_inverse) * vec4<f32>(local_hit_point, 1.0)).xyz;
|
||||
let world_normal = normalize((transpose(volu_material.model_inverse) * vec4<f32>(local_normal, 0.0)).xyz);
|
||||
|
||||
in.world_position = vec4<f32>(world_hit_point, 1.0);
|
||||
in.world_normal = world_normal;
|
||||
|
||||
var pbr_input = pbr_input_from_standard_material(in, is_front);
|
||||
|
||||
pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color);
|
||||
let n = world_normal * 0.5 + 0.5;
|
||||
pbr_input.material.base_color = alpha_discard(pbr_input.material, vec4<f32>(n, 1.0));
|
||||
|
||||
out.color = apply_pbr_lighting(pbr_input);
|
||||
|
||||
|
|
|
|||
16
src/main.rs
16
src/main.rs
|
|
@ -30,6 +30,9 @@ fn setup(
|
|||
mesh_translation: transform.translation,
|
||||
sphere_radius: 1.0,
|
||||
color: Vec4::default(),
|
||||
model_inverse: transform.compute_matrix().inverse(),
|
||||
power: 8.0,
|
||||
iterations: 32,
|
||||
}));
|
||||
|
||||
commands.spawn((
|
||||
|
|
@ -49,6 +52,7 @@ fn setup(
|
|||
commands.spawn((
|
||||
DirectionalLight::default(),
|
||||
Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
Rotate,
|
||||
));
|
||||
|
||||
commands.spawn((
|
||||
|
|
@ -67,14 +71,12 @@ fn rotate_things(mut q: Query<&mut Transform, With<Rotate>>, time: Res<Time>) {
|
|||
}
|
||||
|
||||
fn update_volu_material(
|
||||
mut q: Query<(&mut Transform, &MeshMaterial3d<VoluMaterial>), Changed<Transform>>,
|
||||
q: Query<(&Transform, &MeshMaterial3d<VoluMaterial>), Changed<Transform>>,
|
||||
mut volu_materials: ResMut<Assets<VoluMaterial>>,
|
||||
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
for (mut transform, material) in q.iter_mut() {
|
||||
transform.translation.y = time.elapsed_secs().sin();
|
||||
|
||||
for (transform, material) in q.iter() {
|
||||
let volu_material = volu_materials.get_mut(material.0.id()).unwrap();
|
||||
|
||||
let buffer = buffers
|
||||
|
|
@ -87,6 +89,9 @@ fn update_volu_material(
|
|||
mesh_translation: transform.translation,
|
||||
sphere_radius: (elapsed.sin() + 3.) / 4.,
|
||||
color: vec4((elapsed.sin() + 1.) / 2., 0.0, 0.0, 1.0),
|
||||
model_inverse: transform.compute_matrix(),
|
||||
power: 8.0,
|
||||
iterations: 32,
|
||||
};
|
||||
|
||||
buffer.set_data(volu_storage);
|
||||
|
|
@ -110,4 +115,7 @@ pub struct VoluStorage {
|
|||
mesh_translation: Vec3,
|
||||
sphere_radius: f32,
|
||||
color: Vec4,
|
||||
model_inverse: Mat4,
|
||||
power: f32,
|
||||
iterations: i32,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue