mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Better fluid meshing, disabled fluid backface culling and depth buffer writing
This commit is contained in:
parent
42237a84e4
commit
fa6825f13b
@ -1,6 +1,7 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
#include <globals.glsl>
|
#include <globals.glsl>
|
||||||
|
#include <random.glsl>
|
||||||
|
|
||||||
in vec3 f_pos;
|
in vec3 f_pos;
|
||||||
flat in vec3 f_norm;
|
flat in vec3 f_norm;
|
||||||
@ -25,7 +26,7 @@ void main() {
|
|||||||
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
||||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x);
|
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x);
|
||||||
|
|
||||||
vec3 warped_norm = normalize(f_norm + (sin(f_pos.xyz + tick.x + 13.7) + sin(f_pos.zxy + tick.x + 19.3)) * 0.3);
|
vec3 warped_norm = normalize(f_norm + smooth_rand(floor(f_pos), tick.x) * 0.5);
|
||||||
vec3 reflect_color = get_sky_color(reflect(normalize(f_pos - cam_pos.xyz), warped_norm), time_of_day.x);
|
vec3 reflect_color = get_sky_color(reflect(normalize(f_pos - cam_pos.xyz), warped_norm), time_of_day.x);
|
||||||
|
|
||||||
vec3 color = mix(surf_color + reflect_color * 0.5, fog_color, fog_level);
|
vec3 color = mix(surf_color + reflect_color * 0.5, fog_color, fog_level);
|
||||||
|
@ -43,7 +43,7 @@ void main() {
|
|||||||
|
|
||||||
f_light = float(v_col_light & 0xFFu) / 255.0;
|
f_light = float(v_col_light & 0xFFu) / 255.0;
|
||||||
|
|
||||||
f_opac = 0.1;
|
f_opac = 0.3;
|
||||||
|
|
||||||
gl_Position =
|
gl_Position =
|
||||||
proj_mat *
|
proj_mat *
|
||||||
|
13
assets/voxygen/shaders/include/random.glsl
Normal file
13
assets/voxygen/shaders/include/random.glsl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
vec3 rand_perm_3(vec3 pos) {
|
||||||
|
return sin(pos * vec3(1473.7 * pos.z + 472.3, 8891.1 * pos.x + 723.1, 3813.3 * pos.y + 982.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 rand_perm_4(vec4 pos) {
|
||||||
|
return sin(473.3 * pos * vec4(317.3 * pos.w + 917.7, 1473.7 * pos.z + 472.3, 8891.1 * pos.x + 723.1, 3813.3 * pos.y + 982.5) / pos.yxwz);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 smooth_rand(vec3 pos, float lerp_axis) {
|
||||||
|
vec3 r0 = rand_perm_3(vec3(pos.x, pos.y, pos.z) + floor(lerp_axis));
|
||||||
|
vec3 r1 = rand_perm_3(vec3(pos.x, pos.y, pos.z) + floor(lerp_axis + 1.0));
|
||||||
|
return r0 + (r1 - r0) * fract(lerp_axis);
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <random.glsl>
|
||||||
|
|
||||||
const float PI = 3.141592;
|
const float PI = 3.141592;
|
||||||
|
|
||||||
const vec3 SKY_DAY_TOP = vec3(0.1, 0.2, 0.9);
|
const vec3 SKY_DAY_TOP = vec3(0.1, 0.2, 0.9);
|
||||||
@ -54,10 +56,6 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) {
|
|||||||
return diffuse_light;
|
return diffuse_light;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 rand_offs(vec3 pos) {
|
|
||||||
return sin(pos * vec3(1473.7 * pos.z + 472.3, 8891.1 * pos.x + 723.1, 3813.3 * pos.y + 982.5));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This has been extracted into a function to allow quick exit when detecting a star.
|
// This has been extracted into a function to allow quick exit when detecting a star.
|
||||||
float is_star_at(vec3 dir) {
|
float is_star_at(vec3 dir) {
|
||||||
float star_scale = 30.0;
|
float star_scale = 30.0;
|
||||||
@ -69,7 +67,7 @@ float is_star_at(vec3 dir) {
|
|||||||
vec3 pos = (floor(dir * star_scale) + vec3(i, j, k) - vec3(0.5)) / star_scale;
|
vec3 pos = (floor(dir * star_scale) + vec3(i, j, k) - vec3(0.5)) / star_scale;
|
||||||
|
|
||||||
// Noisy offsets
|
// Noisy offsets
|
||||||
pos += (3.0 / star_scale) * rand_offs(pos);
|
pos += (3.0 / star_scale) * rand_perm_3(pos);
|
||||||
|
|
||||||
// Find distance to fragment
|
// Find distance to fragment
|
||||||
float dist = length(normalize(pos) - dir);
|
float dist = length(normalize(pos) - dir);
|
||||||
|
@ -43,6 +43,7 @@ impl Meshable for Segment {
|
|||||||
true,
|
true,
|
||||||
&[[[1.0; 3]; 3]; 3],
|
&[[[1.0; 3]; 3]; 3],
|
||||||
|vox| vox.is_empty(),
|
|vox| vox.is_empty(),
|
||||||
|
|vox| !vox.is_empty(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ fn block_shadow_density(kind: BlockKind) -> Option<f32> {
|
|||||||
BlockKind::Air => None,
|
BlockKind::Air => None,
|
||||||
BlockKind::Normal => Some(0.85),
|
BlockKind::Normal => Some(0.85),
|
||||||
BlockKind::Dense => Some(3.0),
|
BlockKind::Dense => Some(3.0),
|
||||||
BlockKind::Water => Some(0.01),
|
BlockKind::Water => Some(0.8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +63,7 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for
|
|||||||
false,
|
false,
|
||||||
&neighbour_light,
|
&neighbour_light,
|
||||||
|vox| !vox.is_opaque(),
|
|vox| !vox.is_opaque(),
|
||||||
|
|vox| vox.is_opaque(),
|
||||||
);
|
);
|
||||||
} else if let Some(col) = block
|
} else if let Some(col) = block
|
||||||
.filter(|vox| vox.is_fluid())
|
.filter(|vox| vox.is_fluid())
|
||||||
@ -82,6 +83,7 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for
|
|||||||
false,
|
false,
|
||||||
&neighbour_light,
|
&neighbour_light,
|
||||||
|vox| vox.is_air(),
|
|vox| vox.is_air(),
|
||||||
|
|vox| vox.is_opaque(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
use common::vol::{ReadVol, Vox};
|
use common::vol::ReadVol;
|
||||||
|
|
||||||
use crate::render::{
|
use crate::render::{
|
||||||
mesh::{Mesh, Quad},
|
mesh::{Mesh, Quad},
|
||||||
@ -16,15 +16,16 @@ fn get_ao_quad<V: ReadVol>(
|
|||||||
shift: Vec3<i32>,
|
shift: Vec3<i32>,
|
||||||
dirs: &[Vec3<i32>],
|
dirs: &[Vec3<i32>],
|
||||||
darknesses: &[[[f32; 3]; 3]; 3],
|
darknesses: &[[[f32; 3]; 3]; 3],
|
||||||
|
is_opaque: impl Fn(&V::Vox) -> bool,
|
||||||
) -> Vec4<(f32, f32)> {
|
) -> Vec4<(f32, f32)> {
|
||||||
dirs.windows(2)
|
dirs.windows(2)
|
||||||
.map(|offs| {
|
.map(|offs| {
|
||||||
let (s1, s2) = (
|
let (s1, s2) = (
|
||||||
vol.get(pos + shift + offs[0])
|
vol.get(pos + shift + offs[0])
|
||||||
.map(|v| !v.is_empty())
|
.map(&is_opaque)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
vol.get(pos + shift + offs[1])
|
vol.get(pos + shift + offs[1])
|
||||||
.map(|v| !v.is_empty())
|
.map(&is_opaque)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ fn get_ao_quad<V: ReadVol>(
|
|||||||
} else {
|
} else {
|
||||||
let corner = vol
|
let corner = vol
|
||||||
.get(pos + shift + offs[0] + offs[1])
|
.get(pos + shift + offs[0] + offs[1])
|
||||||
.map(|v| !v.is_empty())
|
.map(&is_opaque)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
// Map both 1 and 2 neighbors to 0.5 occlusion.
|
// Map both 1 and 2 neighbors to 0.5 occlusion.
|
||||||
if s1 || s2 || corner {
|
if s1 || s2 || corner {
|
||||||
@ -98,6 +99,7 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
error_makes_face: bool,
|
error_makes_face: bool,
|
||||||
darknesses: &[[[f32; 3]; 3]; 3],
|
darknesses: &[[[f32; 3]; 3]; 3],
|
||||||
should_add: impl Fn(&V::Vox) -> bool,
|
should_add: impl Fn(&V::Vox) -> bool,
|
||||||
|
is_opaque: impl Fn(&V::Vox) -> bool,
|
||||||
) {
|
) {
|
||||||
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
|
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
|
||||||
|
|
||||||
@ -113,7 +115,14 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
-Vec3::unit_x(),
|
-Vec3::unit_x(),
|
||||||
col,
|
col,
|
||||||
get_ao_quad(vol, pos, -Vec3::unit_x(), &[-z, -y, z, y, -z], darknesses),
|
get_ao_quad(
|
||||||
|
vol,
|
||||||
|
pos,
|
||||||
|
-Vec3::unit_x(),
|
||||||
|
&[-z, -y, z, y, -z],
|
||||||
|
darknesses,
|
||||||
|
&is_opaque,
|
||||||
|
),
|
||||||
&vcons,
|
&vcons,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -129,7 +138,14 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
col,
|
col,
|
||||||
get_ao_quad(vol, pos, Vec3::unit_x(), &[-y, -z, y, z, -y], darknesses),
|
get_ao_quad(
|
||||||
|
vol,
|
||||||
|
pos,
|
||||||
|
Vec3::unit_x(),
|
||||||
|
&[-y, -z, y, z, -y],
|
||||||
|
darknesses,
|
||||||
|
&is_opaque,
|
||||||
|
),
|
||||||
&vcons,
|
&vcons,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -145,7 +161,14 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
-Vec3::unit_y(),
|
-Vec3::unit_y(),
|
||||||
col,
|
col,
|
||||||
get_ao_quad(vol, pos, -Vec3::unit_y(), &[-x, -z, x, z, -x], darknesses),
|
get_ao_quad(
|
||||||
|
vol,
|
||||||
|
pos,
|
||||||
|
-Vec3::unit_y(),
|
||||||
|
&[-x, -z, x, z, -x],
|
||||||
|
darknesses,
|
||||||
|
&is_opaque,
|
||||||
|
),
|
||||||
&vcons,
|
&vcons,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -161,7 +184,14 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
col,
|
col,
|
||||||
get_ao_quad(vol, pos, Vec3::unit_y(), &[-z, -x, z, x, -z], darknesses),
|
get_ao_quad(
|
||||||
|
vol,
|
||||||
|
pos,
|
||||||
|
Vec3::unit_y(),
|
||||||
|
&[-z, -x, z, x, -z],
|
||||||
|
darknesses,
|
||||||
|
&is_opaque,
|
||||||
|
),
|
||||||
&vcons,
|
&vcons,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -177,7 +207,14 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
Vec3::unit_x(),
|
Vec3::unit_x(),
|
||||||
-Vec3::unit_z(),
|
-Vec3::unit_z(),
|
||||||
col,
|
col,
|
||||||
get_ao_quad(vol, pos, -Vec3::unit_z(), &[-y, -x, y, x, -y], darknesses),
|
get_ao_quad(
|
||||||
|
vol,
|
||||||
|
pos,
|
||||||
|
-Vec3::unit_z(),
|
||||||
|
&[-y, -x, y, x, -y],
|
||||||
|
darknesses,
|
||||||
|
&is_opaque,
|
||||||
|
),
|
||||||
&vcons,
|
&vcons,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -193,7 +230,14 @@ pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
|||||||
Vec3::unit_y(),
|
Vec3::unit_y(),
|
||||||
Vec3::unit_z(),
|
Vec3::unit_z(),
|
||||||
col,
|
col,
|
||||||
get_ao_quad(vol, pos, Vec3::unit_z(), &[-x, -y, x, y, -x], darknesses),
|
get_ao_quad(
|
||||||
|
vol,
|
||||||
|
pos,
|
||||||
|
Vec3::unit_z(),
|
||||||
|
&[-x, -y, x, y, -x],
|
||||||
|
darknesses,
|
||||||
|
&is_opaque,
|
||||||
|
),
|
||||||
&vcons,
|
&vcons,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,12 @@ gfx_defines! {
|
|||||||
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||||
|
|
||||||
tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA),
|
tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA),
|
||||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_TEST,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vertex {
|
impl Vertex {
|
||||||
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>, light: f32, opac: f32) -> Self {
|
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>, light: f32, _opac: f32) -> Self {
|
||||||
let (norm_axis, norm_dir) = norm
|
let (norm_axis, norm_dir) = norm
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -506,12 +506,16 @@ fn create_pipelines(
|
|||||||
let srgb =
|
let srgb =
|
||||||
assets::load_watched::<String>("voxygen.shaders.include.srgb", shader_reload_indicator)
|
assets::load_watched::<String>("voxygen.shaders.include.srgb", shader_reload_indicator)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let random =
|
||||||
|
assets::load_watched::<String>("voxygen.shaders.include.random", shader_reload_indicator)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut include_ctx = IncludeContext::new();
|
let mut include_ctx = IncludeContext::new();
|
||||||
include_ctx.include("globals.glsl", &globals);
|
include_ctx.include("globals.glsl", &globals);
|
||||||
include_ctx.include("sky.glsl", &sky);
|
include_ctx.include("sky.glsl", &sky);
|
||||||
include_ctx.include("light.glsl", &light);
|
include_ctx.include("light.glsl", &light);
|
||||||
include_ctx.include("srgb.glsl", &srgb);
|
include_ctx.include("srgb.glsl", &srgb);
|
||||||
|
include_ctx.include("random.glsl", &random);
|
||||||
|
|
||||||
// Construct a pipeline for rendering skyboxes
|
// Construct a pipeline for rendering skyboxes
|
||||||
let skybox_pipeline = create_pipeline(
|
let skybox_pipeline = create_pipeline(
|
||||||
@ -522,6 +526,7 @@ fn create_pipelines(
|
|||||||
&assets::load_watched::<String>("voxygen.shaders.skybox-frag", shader_reload_indicator)
|
&assets::load_watched::<String>("voxygen.shaders.skybox-frag", shader_reload_indicator)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Back,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering figures
|
// Construct a pipeline for rendering figures
|
||||||
@ -533,6 +538,7 @@ fn create_pipelines(
|
|||||||
&assets::load_watched::<String>("voxygen.shaders.figure-frag", shader_reload_indicator)
|
&assets::load_watched::<String>("voxygen.shaders.figure-frag", shader_reload_indicator)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Back,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering terrain
|
// Construct a pipeline for rendering terrain
|
||||||
@ -544,6 +550,7 @@ fn create_pipelines(
|
|||||||
&assets::load_watched::<String>("voxygen.shaders.terrain-frag", shader_reload_indicator)
|
&assets::load_watched::<String>("voxygen.shaders.terrain-frag", shader_reload_indicator)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Back,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering fluids
|
// Construct a pipeline for rendering fluids
|
||||||
@ -555,6 +562,7 @@ fn create_pipelines(
|
|||||||
&assets::load_watched::<String>("voxygen.shaders.fluid-frag", shader_reload_indicator)
|
&assets::load_watched::<String>("voxygen.shaders.fluid-frag", shader_reload_indicator)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Nothing,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering UI elements
|
// Construct a pipeline for rendering UI elements
|
||||||
@ -566,6 +574,7 @@ fn create_pipelines(
|
|||||||
&assets::load_watched::<String>("voxygen.shaders.ui-frag", shader_reload_indicator)
|
&assets::load_watched::<String>("voxygen.shaders.ui-frag", shader_reload_indicator)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Back,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering our post-processing
|
// Construct a pipeline for rendering our post-processing
|
||||||
@ -583,6 +592,7 @@ fn create_pipelines(
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Back,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@ -602,6 +612,7 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
|||||||
vs: &str,
|
vs: &str,
|
||||||
fs: &str,
|
fs: &str,
|
||||||
ctx: &IncludeContext,
|
ctx: &IncludeContext,
|
||||||
|
cull_face: gfx::state::CullFace,
|
||||||
) -> Result<GfxPipeline<P>, RenderError> {
|
) -> Result<GfxPipeline<P>, RenderError> {
|
||||||
let vs = ctx.expand(vs).map_err(RenderError::IncludeError)?;
|
let vs = ctx.expand(vs).map_err(RenderError::IncludeError)?;
|
||||||
let fs = ctx.expand(fs).map_err(RenderError::IncludeError)?;
|
let fs = ctx.expand(fs).map_err(RenderError::IncludeError)?;
|
||||||
@ -617,7 +628,7 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
|||||||
gfx::Primitive::TriangleList,
|
gfx::Primitive::TriangleList,
|
||||||
gfx::state::Rasterizer {
|
gfx::state::Rasterizer {
|
||||||
front_face: gfx::state::FrontFace::CounterClockwise,
|
front_face: gfx::state::FrontFace::CounterClockwise,
|
||||||
cull_face: gfx::state::CullFace::Back,
|
cull_face,
|
||||||
method: gfx::state::RasterMethod::Fill,
|
method: gfx::state::RasterMethod::Fill,
|
||||||
offset: None,
|
offset: None,
|
||||||
samples: Some(gfx::state::MultiSample),
|
samples: Some(gfx::state::MultiSample),
|
||||||
|
@ -335,7 +335,9 @@ impl<'a> Sampler for ColumnGen<'a> {
|
|||||||
/ 100.0,
|
/ 100.0,
|
||||||
),
|
),
|
||||||
// Beach
|
// Beach
|
||||||
((alt - CONFIG.sea_level - 1.0) / 2.0).min(1.0 - river * 2.0),
|
((alt - CONFIG.sea_level - 1.0) / 2.0)
|
||||||
|
.min(1.0 - river * 2.0)
|
||||||
|
.max(0.0),
|
||||||
),
|
),
|
||||||
sub_surface_color: dirt,
|
sub_surface_color: dirt,
|
||||||
tree_density,
|
tree_density,
|
||||||
|
Loading…
Reference in New Issue
Block a user