pbr lightning for volumetric sphere
This commit is contained in:
parent
38513627ca
commit
27d27feba7
2 changed files with 65 additions and 16 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
#import bevy_pbr::{
|
#import bevy_pbr::{
|
||||||
forward_io::{VertexOutput, FragmentOutput},
|
forward_io::{VertexOutput, FragmentOutput},
|
||||||
mesh_view_bindings::view,
|
mesh_view_bindings::view,
|
||||||
|
pbr_functions::{alpha_discard, apply_pbr_lighting, main_pass_post_lighting_processing},
|
||||||
|
pbr_fragment::pbr_input_from_standard_material,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VoluMaterial {
|
struct VoluMaterial {
|
||||||
|
|
@ -12,33 +14,78 @@ struct VoluMaterial {
|
||||||
@group(2) @binding(100)
|
@group(2) @binding(100)
|
||||||
var<storage, read> volu_material: VoluMaterial;
|
var<storage, read> volu_material: VoluMaterial;
|
||||||
|
|
||||||
fn raymarch_hit(position_: vec3<f32>, direction: vec3<f32>) -> bool {
|
fn sphere_sdf(p: vec3<f32>, center: vec3<f32>, radius: f32) -> f32 {
|
||||||
var position = position_;
|
return length(p - center) - radius;
|
||||||
for (var i = 0; i < 200; i++) {
|
|
||||||
if sphere_hit(position) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
position += direction * 0.01;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sphere_hit(p: vec3<f32>) -> bool {
|
fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
||||||
return distance(p, volu_material.mesh_translation) < volu_material.sphere_radius;
|
var t = 0.0;
|
||||||
|
let max_distance = 100.0;
|
||||||
|
let max_steps = 128;
|
||||||
|
let epsilon = 0.001;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if distance < epsilon {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
t += distance;
|
||||||
|
|
||||||
|
if t > max_distance {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@fragment
|
||||||
fn fragment(
|
fn fragment(
|
||||||
in: VertexOutput,
|
vertex_output: VertexOutput,
|
||||||
@builtin(front_facing) is_front: bool,
|
@builtin(front_facing) is_front: bool,
|
||||||
) -> FragmentOutput {
|
) -> FragmentOutput {
|
||||||
let view_direction = normalize(in.world_position.xyz - view.world_position);
|
var in = vertex_output;
|
||||||
|
|
||||||
|
let ray_origin = view.world_position;
|
||||||
|
let ray_direction = normalize(in.world_position.xyz - view.world_position);
|
||||||
|
|
||||||
|
let t = raymarch(ray_origin, ray_direction);
|
||||||
|
|
||||||
var out: FragmentOutput;
|
var out: FragmentOutput;
|
||||||
if (raymarch_hit(in.world_position.xyz, view_direction)) {
|
|
||||||
out.color = volu_material.color;
|
if t > 0.0 {
|
||||||
|
let hit_point = ray_origin + t * ray_direction;
|
||||||
|
let normal = sphere_normal(hit_point);
|
||||||
|
|
||||||
|
in.world_position = vec4<f32>(hit_point, 1.0);
|
||||||
|
in.world_normal = 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);
|
||||||
|
|
||||||
|
out.color = apply_pbr_lighting(pbr_input);
|
||||||
|
|
||||||
|
out.color = main_pass_post_lighting_processing(pbr_input, out.color);
|
||||||
} else {
|
} else {
|
||||||
out.color = vec4(1.0, 1.0, 1.0, 0.2);
|
out.color = vec4(1.0, 1.0, 1.0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
|
color::palettes::css::RED,
|
||||||
pbr::{ExtendedMaterial, MaterialExtension},
|
pbr::{ExtendedMaterial, MaterialExtension},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{render_resource::*, storage::ShaderStorageBuffer},
|
render::{render_resource::*, storage::ShaderStorageBuffer},
|
||||||
|
|
@ -35,6 +36,7 @@ fn setup(
|
||||||
Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))),
|
Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))),
|
||||||
MeshMaterial3d(materials.add(ExtendedMaterial {
|
MeshMaterial3d(materials.add(ExtendedMaterial {
|
||||||
base: StandardMaterial {
|
base: StandardMaterial {
|
||||||
|
base_color: RED.into(),
|
||||||
alpha_mode: AlphaMode::Blend,
|
alpha_mode: AlphaMode::Blend,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue