mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'overclockx64/fluids' into 'master'
Fluids See merge request veloren/veloren!436
This commit is contained in:
commit
2828e40ef4
@ -31,7 +31,7 @@ void main() {
|
|||||||
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) + light_at(f_pos, f_norm);
|
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) + light_at(f_pos, f_norm);
|
||||||
vec3 surf_color = srgb_to_linear(model_col.rgb * f_col) * 4.0 * light;
|
vec3 surf_color = srgb_to_linear(model_col.rgb * f_col) * 4.0 * light;
|
||||||
|
|
||||||
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||||
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 color = mix(surf_color, fog_color, fog_level);
|
vec3 color = mix(surf_color, fog_color, fog_level);
|
||||||
|
|
||||||
|
58
assets/voxygen/shaders/fluid-frag.glsl
Normal file
58
assets/voxygen/shaders/fluid-frag.glsl
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
#include <globals.glsl>
|
||||||
|
#include <random.glsl>
|
||||||
|
|
||||||
|
in vec3 f_pos;
|
||||||
|
flat in vec3 f_norm;
|
||||||
|
in vec3 f_col;
|
||||||
|
in float f_light;
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_locals {
|
||||||
|
vec3 model_offs;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 tgt_color;
|
||||||
|
|
||||||
|
#include <sky.glsl>
|
||||||
|
#include <light.glsl>
|
||||||
|
|
||||||
|
vec3 warp_normal(vec3 norm, vec3 pos, float time) {
|
||||||
|
return normalize(norm
|
||||||
|
+ smooth_rand(pos * 1.0, time * 1.0) * 0.05
|
||||||
|
+ smooth_rand(pos * 0.25, time * 0.25) * 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
/*
|
||||||
|
// Round the position to the nearest triangular grid cell
|
||||||
|
vec3 hex_pos = f_pos * 2.0;
|
||||||
|
hex_pos = hex_pos + vec3(hex_pos.y * 1.4 / 3.0, hex_pos.y * 0.1, 0);
|
||||||
|
if (fract(hex_pos.x) > fract(hex_pos.y)) {
|
||||||
|
hex_pos += vec3(1.0, 1.0, 0);
|
||||||
|
}
|
||||||
|
hex_pos = floor(hex_pos);
|
||||||
|
*/
|
||||||
|
|
||||||
|
vec3 norm = warp_normal(f_norm, f_pos, tick.x);
|
||||||
|
|
||||||
|
vec3 light = get_sun_diffuse(norm, time_of_day.x) * f_light + light_at(f_pos, norm);
|
||||||
|
vec3 surf_color = f_col * light;
|
||||||
|
|
||||||
|
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||||
|
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x);
|
||||||
|
|
||||||
|
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||||
|
vec3 reflect_ray_dir = reflect(cam_to_frag, norm);
|
||||||
|
// Hack to prevent the reflection ray dipping below the horizon and creating weird blue spots in the water
|
||||||
|
reflect_ray_dir.z = max(reflect_ray_dir.z, 0.05);
|
||||||
|
|
||||||
|
vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x) * f_light;
|
||||||
|
// 0 = 100% reflection, 1 = translucent water
|
||||||
|
float passthrough = pow(dot(faceforward(norm, norm, cam_to_frag), -cam_to_frag), 1.0);
|
||||||
|
|
||||||
|
vec4 color = mix(vec4(reflect_color, 1.0), vec4(surf_color, 0.5 / (1.0 + light * 2.0)), passthrough);
|
||||||
|
|
||||||
|
tgt_color = mix(color, vec4(fog_color, 0.0), fog_level);
|
||||||
|
}
|
49
assets/voxygen/shaders/fluid-vert.glsl
Normal file
49
assets/voxygen/shaders/fluid-vert.glsl
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
#include <globals.glsl>
|
||||||
|
|
||||||
|
in uint v_pos_norm;
|
||||||
|
in uint v_col_light;
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_locals {
|
||||||
|
vec3 model_offs;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec3 f_pos;
|
||||||
|
flat out vec3 f_norm;
|
||||||
|
out vec3 f_col;
|
||||||
|
out float f_light;
|
||||||
|
|
||||||
|
// First 3 normals are negative, next 3 are positive
|
||||||
|
vec3 normals[6] = vec3[]( vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) );
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
f_pos = vec3(
|
||||||
|
float((v_pos_norm >> 0) & 0x00FFu),
|
||||||
|
float((v_pos_norm >> 8) & 0x00FFu),
|
||||||
|
float((v_pos_norm >> 16) & 0x1FFFu)
|
||||||
|
) + model_offs;
|
||||||
|
|
||||||
|
// TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction.
|
||||||
|
uint norm_axis = (v_pos_norm >> 30) & 0x3u;
|
||||||
|
|
||||||
|
// Increase array access by 3 to access positive values
|
||||||
|
uint norm_dir = ((v_pos_norm >> 29) & 0x1u) * 3u;
|
||||||
|
|
||||||
|
// Use an array to avoid conditional branching
|
||||||
|
f_norm = normals[norm_axis + norm_dir];
|
||||||
|
|
||||||
|
f_col = vec3(
|
||||||
|
float((v_col_light >> 8) & 0xFFu),
|
||||||
|
float((v_col_light >> 16) & 0xFFu),
|
||||||
|
float((v_col_light >> 24) & 0xFFu)
|
||||||
|
) / 200.0;
|
||||||
|
|
||||||
|
f_light = float(v_col_light & 0xFFu) / 255.0;
|
||||||
|
|
||||||
|
gl_Position =
|
||||||
|
proj_mat *
|
||||||
|
view_mat *
|
||||||
|
vec4(f_pos, 1);
|
||||||
|
}
|
@ -9,4 +9,5 @@ uniform u_globals {
|
|||||||
vec4 tick;
|
vec4 tick;
|
||||||
vec4 screen_res;
|
vec4 screen_res;
|
||||||
uvec4 light_count;
|
uvec4 light_count;
|
||||||
|
uvec4 medium;
|
||||||
};
|
};
|
||||||
|
48
assets/voxygen/shaders/include/random.glsl
Normal file
48
assets/voxygen/shaders/include/random.glsl
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
float hash(vec4 p) {
|
||||||
|
p = fract( p*0.3183099+.1);
|
||||||
|
p *= 17.0;
|
||||||
|
return (fract(p.x*p.y*p.z*p.w*(p.x+p.y+p.z+p.w)) - 0.5) * 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float snoise(in vec4 x) {
|
||||||
|
vec4 p = floor(x);
|
||||||
|
vec4 f = fract(x);
|
||||||
|
f = f * f * (3.0 - 2.0 * f);
|
||||||
|
return mix(
|
||||||
|
mix(
|
||||||
|
mix(
|
||||||
|
mix(hash(p + vec4(0,0,0,0)), hash(p + vec4(1,0,0,0)), f.x),
|
||||||
|
mix(hash(p + vec4(0,1,0,0)), hash(p + vec4(1,1,0,0)), f.x),
|
||||||
|
f.y),
|
||||||
|
mix(
|
||||||
|
mix(hash(p + vec4(0,0,1,0)), hash(p + vec4(1,0,1,0)), f.x),
|
||||||
|
mix(hash(p + vec4(0,1,1,0)), hash(p + vec4(1,1,1,0)), f.x),
|
||||||
|
f.y),
|
||||||
|
f.z),
|
||||||
|
mix(
|
||||||
|
mix(
|
||||||
|
mix(hash(p + vec4(0,0,0,1)), hash(p + vec4(1,0,0,1)), f.x),
|
||||||
|
mix(hash(p + vec4(0,1,0,1)), hash(p + vec4(1,1,0,1)), f.x),
|
||||||
|
f.y),
|
||||||
|
mix(
|
||||||
|
mix(hash(p + vec4(0,0,1,1)), hash(p + vec4(1,0,1,1)), f.x),
|
||||||
|
mix(hash(p + vec4(0,1,1,1)), hash(p + vec4(1,1,1,1)), f.x),
|
||||||
|
f.y),
|
||||||
|
f.z),
|
||||||
|
f.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return vec3(snoise(vec4(pos, lerp_axis)), snoise(vec4(pos + 400.0, lerp_axis)), snoise(vec4(pos + 1000.0, 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);
|
||||||
@ -146,11 +144,20 @@ vec3 get_sky_color(vec3 dir, float time_of_day) {
|
|||||||
return sky_color + sun_light;
|
return sky_color + sun_light;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fog(vec2 f_pos, vec2 focus_pos) {
|
float fog(vec3 f_pos, vec3 focus_pos, uint medium) {
|
||||||
float dist = distance(f_pos, focus_pos) / view_distance.x;
|
float fog_radius = view_distance.x;
|
||||||
const float min_fog = 0.5;
|
float mist_radius = 10000000.0;
|
||||||
const float max_fog = 1.0;
|
|
||||||
const float diff_fog = 0.5; // max - min
|
|
||||||
|
|
||||||
return pow(clamp((dist - min_fog) / (diff_fog), 0.0, 1.0), 1.7);
|
float min_fog = 0.5;
|
||||||
|
float max_fog = 1.0;
|
||||||
|
|
||||||
|
if (medium == 1u) {
|
||||||
|
mist_radius = 32.0;
|
||||||
|
min_fog = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fog = distance(f_pos.xy, focus_pos.xy) / fog_radius;
|
||||||
|
float mist = distance(f_pos, focus_pos) / mist_radius;
|
||||||
|
|
||||||
|
return pow(clamp((max(fog, mist) - min_fog) / (max_fog - min_fog), 0.0, 1.0), 1.7);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ void main() {
|
|||||||
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm);
|
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm);
|
||||||
vec3 surf_color = f_col * light;
|
vec3 surf_color = f_col * light;
|
||||||
|
|
||||||
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||||
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 color = mix(surf_color, fog_color, fog_level);
|
vec3 color = mix(surf_color, fog_color, fog_level);
|
||||||
|
|
||||||
|
BIN
assets/world/structure/dungeon/meso_sewer_temple.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/structure/dungeon/meso_sewer_temple.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/structure/dungeon/ruins_maze.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/structure/dungeon/ruins_maze.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -108,7 +108,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
if terrain
|
if terrain
|
||||||
.get(block_pos)
|
.get(block_pos)
|
||||||
.map(|vox| !vox.is_empty())
|
.map(|vox| vox.is_solid())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
let player_aabb = Aabb {
|
let player_aabb = Aabb {
|
||||||
@ -183,7 +183,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
.filter(|(block_pos, _)| {
|
.filter(|(block_pos, _)| {
|
||||||
terrain
|
terrain
|
||||||
.get(*block_pos)
|
.get(*block_pos)
|
||||||
.map(|vox| !vox.is_empty())
|
.map(|vox| vox.is_solid())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
// Find the maximum of the minimum collision axes (this bit is weird, trust me that it works)
|
// Find the maximum of the minimum collision axes (this bit is weird, trust me that it works)
|
||||||
|
@ -1,47 +1,105 @@
|
|||||||
use crate::vol::Vox;
|
use crate::vol::Vox;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::ops::Deref;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum BlockKind {
|
||||||
|
Air,
|
||||||
|
Normal,
|
||||||
|
Dense,
|
||||||
|
Water,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockKind {
|
||||||
|
pub fn is_air(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlockKind::Air => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_fluid(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlockKind::Water => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_opaque(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlockKind::Air => false,
|
||||||
|
BlockKind::Water => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_solid(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlockKind::Air => false,
|
||||||
|
BlockKind::Water => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[repr(packed)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
kind: u8,
|
kind: BlockKind,
|
||||||
color: [u8; 3],
|
color: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn new(kind: u8, color: Rgb<u8>) -> Self {
|
pub fn new(kind: BlockKind, color: Rgb<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind,
|
kind,
|
||||||
color: color.into_array(),
|
color: color.into_array(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_color(self) -> Option<Rgb<u8>> {
|
pub fn get_color(&self) -> Option<Rgb<u8>> {
|
||||||
if self.is_empty() {
|
if !self.is_air() {
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(self.color.into())
|
Some(self.color.into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_opacity(self) -> Option<f32> {
|
pub fn kind(&self) -> BlockKind {
|
||||||
match self.kind {
|
self.kind
|
||||||
0 => None,
|
|
||||||
1 => Some(0.85),
|
|
||||||
_ => Some(3.0),
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Block {
|
||||||
|
type Target = BlockKind;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.kind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vox for Block {
|
impl Vox for Block {
|
||||||
fn empty() -> Self {
|
fn empty() -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind: 0,
|
kind: BlockKind::Air,
|
||||||
color: [0; 3],
|
color: [0; 3],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.kind == 0
|
self.is_air()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_size() {
|
||||||
|
assert_eq!(std::mem::size_of::<BlockKind>(), 1);
|
||||||
|
assert_eq!(std::mem::size_of::<Block>(), 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,11 @@ pub mod chonk;
|
|||||||
pub mod structure;
|
pub mod structure;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{biome::BiomeKind, block::Block, structure::Structure};
|
pub use self::{
|
||||||
|
biome::BiomeKind,
|
||||||
|
block::{Block, BlockKind},
|
||||||
|
structure::Structure,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{vol::VolSize, volumes::vol_map_2d::VolMap2d};
|
use crate::{vol::VolSize, volumes::vol_map_2d::VolMap2d};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::Block;
|
use super::{Block, BlockKind};
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::{self, Asset},
|
assets::{self, Asset},
|
||||||
vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol},
|
vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol},
|
||||||
@ -11,23 +11,26 @@ use vek::*;
|
|||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum StructureBlock {
|
pub enum StructureBlock {
|
||||||
|
None,
|
||||||
TemperateLeaves,
|
TemperateLeaves,
|
||||||
PineLeaves,
|
PineLeaves,
|
||||||
Acacia,
|
Acacia,
|
||||||
PalmLeaves,
|
PalmLeaves,
|
||||||
|
Water,
|
||||||
|
GreenSludge,
|
||||||
Fruit,
|
Fruit,
|
||||||
Hollow,
|
Hollow,
|
||||||
Block(Block),
|
Normal(Rgb<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vox for StructureBlock {
|
impl Vox for StructureBlock {
|
||||||
fn empty() -> Self {
|
fn empty() -> Self {
|
||||||
StructureBlock::Block(Block::empty())
|
StructureBlock::None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
StructureBlock::Block(block) => block.is_empty(),
|
StructureBlock::None => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,6 +44,7 @@ pub struct Structure {
|
|||||||
center: Vec3<i32>,
|
center: Vec3<i32>,
|
||||||
vol: Dyna<StructureBlock, ()>,
|
vol: Dyna<StructureBlock, ()>,
|
||||||
empty: StructureBlock,
|
empty: StructureBlock,
|
||||||
|
default_kind: BlockKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Structure {
|
impl Structure {
|
||||||
@ -49,12 +53,21 @@ impl Structure {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_default_kind(mut self, kind: BlockKind) -> Self {
|
||||||
|
self.default_kind = kind;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_bounds(&self) -> Aabb<i32> {
|
pub fn get_bounds(&self) -> Aabb<i32> {
|
||||||
Aabb {
|
Aabb {
|
||||||
min: -self.center,
|
min: -self.center,
|
||||||
max: self.vol.get_size().map(|e| e as i32) - self.center,
|
max: self.vol.get_size().map(|e| e as i32) - self.center,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_kind(&self) -> BlockKind {
|
||||||
|
self.default_kind
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseVol for Structure {
|
impl BaseVol for Structure {
|
||||||
@ -95,7 +108,9 @@ impl Asset for Structure {
|
|||||||
0 => StructureBlock::TemperateLeaves,
|
0 => StructureBlock::TemperateLeaves,
|
||||||
1 => StructureBlock::PineLeaves,
|
1 => StructureBlock::PineLeaves,
|
||||||
2 => StructureBlock::PalmLeaves,
|
2 => StructureBlock::PalmLeaves,
|
||||||
|
3 => StructureBlock::Water,
|
||||||
4 => StructureBlock::Acacia,
|
4 => StructureBlock::Acacia,
|
||||||
|
6 => StructureBlock::GreenSludge,
|
||||||
7 => StructureBlock::Fruit,
|
7 => StructureBlock::Fruit,
|
||||||
15 => StructureBlock::Hollow,
|
15 => StructureBlock::Hollow,
|
||||||
index => {
|
index => {
|
||||||
@ -103,7 +118,7 @@ impl Asset for Structure {
|
|||||||
.get(index as usize)
|
.get(index as usize)
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or_else(|| Rgb::broadcast(0));
|
.unwrap_or_else(|| Rgb::broadcast(0));
|
||||||
StructureBlock::Block(Block::new(1, color))
|
StructureBlock::Normal(color)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,12 +132,14 @@ impl Asset for Structure {
|
|||||||
center: Vec3::zero(),
|
center: Vec3::zero(),
|
||||||
vol,
|
vol,
|
||||||
empty: StructureBlock::empty(),
|
empty: StructureBlock::empty(),
|
||||||
|
default_kind: BlockKind::Normal,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
center: Vec3::zero(),
|
center: Vec3::zero(),
|
||||||
vol: Dyna::filled(Vec3::zero(), StructureBlock::empty(), ()),
|
vol: Dyna::filled(Vec3::zero(), StructureBlock::empty(), ()),
|
||||||
empty: StructureBlock::empty(),
|
empty: StructureBlock::empty(),
|
||||||
|
default_kind: BlockKind::Normal,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ use client::Client;
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{humanoid, Body},
|
comp::{humanoid, Body},
|
||||||
state::DeltaTime,
|
state::DeltaTime,
|
||||||
|
terrain::BlockKind,
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -102,6 +103,7 @@ impl Scene {
|
|||||||
client.state().get_time(),
|
client.state().get_time(),
|
||||||
renderer.get_resolution(),
|
renderer.get_resolution(),
|
||||||
0,
|
0,
|
||||||
|
BlockKind::Air,
|
||||||
)],
|
)],
|
||||||
) {
|
) {
|
||||||
error!("Renderer failed to update: {:?}", err);
|
error!("Renderer failed to update: {:?}", err);
|
||||||
|
@ -6,7 +6,12 @@ use crate::render::{self, Mesh};
|
|||||||
|
|
||||||
pub trait Meshable {
|
pub trait Meshable {
|
||||||
type Pipeline: render::Pipeline;
|
type Pipeline: render::Pipeline;
|
||||||
|
type TranslucentPipeline: render::Pipeline;
|
||||||
type Supplement;
|
type Supplement;
|
||||||
|
|
||||||
fn generate_mesh(&self, supp: Self::Supplement) -> Mesh<Self::Pipeline>;
|
// Generate meshes - one opaque, one translucent
|
||||||
|
fn generate_mesh(
|
||||||
|
&self,
|
||||||
|
supp: Self::Supplement,
|
||||||
|
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
use common::{
|
use common::{
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
util::{linear_to_srgb, srgb_to_linear},
|
util::{linear_to_srgb, srgb_to_linear},
|
||||||
vol::{ReadVol, SizedVol},
|
vol::{ReadVol, SizedVol, Vox},
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -13,9 +13,13 @@ type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
|||||||
|
|
||||||
impl Meshable for Segment {
|
impl Meshable for Segment {
|
||||||
type Pipeline = FigurePipeline;
|
type Pipeline = FigurePipeline;
|
||||||
|
type TranslucentPipeline = FigurePipeline;
|
||||||
type Supplement = Vec3<f32>;
|
type Supplement = Vec3<f32>;
|
||||||
|
|
||||||
fn generate_mesh(&self, offs: Self::Supplement) -> Mesh<Self::Pipeline> {
|
fn generate_mesh(
|
||||||
|
&self,
|
||||||
|
offs: Self::Supplement,
|
||||||
|
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
||||||
let mut mesh = Mesh::new();
|
let mut mesh = Mesh::new();
|
||||||
|
|
||||||
for pos in self.iter_positions() {
|
for pos in self.iter_positions() {
|
||||||
@ -38,10 +42,12 @@ impl Meshable for Segment {
|
|||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
&[[[1.0; 3]; 3]; 3],
|
&[[[1.0; 3]; 3]; 3],
|
||||||
|
|vox| vox.is_empty(),
|
||||||
|
|vox| !vox.is_empty(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh
|
(mesh, Mesh::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{vol, Meshable},
|
mesh::{vol, Meshable},
|
||||||
render::{self, Mesh, TerrainPipeline},
|
render::{self, FluidPipeline, Mesh, TerrainPipeline},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::Block,
|
terrain::{Block, BlockKind},
|
||||||
vol::{BaseVol, ReadVol, VolSize},
|
vol::{BaseVol, ReadVol, VolSize},
|
||||||
volumes::vol_map_2d::VolMap2d,
|
volumes::vol_map_2d::VolMap2d,
|
||||||
};
|
};
|
||||||
@ -11,43 +11,28 @@ use std::fmt::Debug;
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
||||||
|
type FluidVertex = <FluidPipeline as render::Pipeline>::Vertex;
|
||||||
|
|
||||||
/*
|
fn block_shadow_density(kind: BlockKind) -> (f32, f32) {
|
||||||
impl<M> Meshable for Dyna<Block, M> {
|
match kind {
|
||||||
type Pipeline = TerrainPipeline;
|
BlockKind::Air => (0.0, 0.0),
|
||||||
type Supplement = ();
|
BlockKind::Normal => (0.085, 0.3),
|
||||||
|
BlockKind::Dense => (0.3, 0.0),
|
||||||
fn generate_mesh(&self, _: Self::Supplement) -> Mesh<Self::Pipeline> {
|
BlockKind::Water => (0.15, 0.0),
|
||||||
let mut mesh = Mesh::new();
|
|
||||||
|
|
||||||
for pos in self
|
|
||||||
.iter_positions()
|
|
||||||
.filter(|pos| pos.map(|e| e >= 1).reduce_and())
|
|
||||||
.filter(|pos| {
|
|
||||||
pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1)
|
|
||||||
.reduce_and()
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let offs = pos.map(|e| e as f32 - 1.0);
|
|
||||||
|
|
||||||
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
|
|
||||||
let col = col.map(|e| e as f32 / 255.0);
|
|
||||||
|
|
||||||
vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d<V, S> {
|
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d<V, S> {
|
||||||
type Pipeline = TerrainPipeline;
|
type Pipeline = TerrainPipeline;
|
||||||
|
type TranslucentPipeline = FluidPipeline;
|
||||||
type Supplement = Aabb<i32>;
|
type Supplement = Aabb<i32>;
|
||||||
|
|
||||||
fn generate_mesh(&self, range: Self::Supplement) -> Mesh<Self::Pipeline> {
|
fn generate_mesh(
|
||||||
let mut mesh = Mesh::new();
|
&self,
|
||||||
|
range: Self::Supplement,
|
||||||
|
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
||||||
|
let mut opaque_mesh = Mesh::new();
|
||||||
|
let mut fluid_mesh = Mesh::new();
|
||||||
|
|
||||||
for x in range.min.x + 1..range.max.x - 1 {
|
for x in range.min.x + 1..range.max.x - 1 {
|
||||||
for y in range.min.y + 1..range.max.y - 1 {
|
for y in range.min.y + 1..range.max.y - 1 {
|
||||||
@ -55,16 +40,19 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for
|
|||||||
|
|
||||||
for z in (range.min.z..range.max.z).rev() {
|
for z in (range.min.z..range.max.z).rev() {
|
||||||
let pos = Vec3::new(x, y, z);
|
let pos = Vec3::new(x, y, z);
|
||||||
|
let offs = (pos - (range.min + 1) * Vec3::new(1, 1, 0)).map(|e| e as f32);
|
||||||
|
|
||||||
|
let block = self.get(pos).ok();
|
||||||
|
|
||||||
// Create mesh polygons
|
// Create mesh polygons
|
||||||
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
|
if let Some(col) = block
|
||||||
|
.filter(|vox| vox.is_opaque())
|
||||||
|
.and_then(|vox| vox.get_color())
|
||||||
|
{
|
||||||
let col = col.map(|e| e as f32 / 255.0);
|
let col = col.map(|e| e as f32 / 255.0);
|
||||||
|
|
||||||
let offs = (pos - range.min * Vec3::new(1, 1, 0)).map(|e| e as f32)
|
|
||||||
- Vec3::new(1.0, 1.0, 0.0);
|
|
||||||
|
|
||||||
vol::push_vox_verts(
|
vol::push_vox_verts(
|
||||||
&mut mesh,
|
&mut opaque_mesh,
|
||||||
self,
|
self,
|
||||||
pos,
|
pos,
|
||||||
offs,
|
offs,
|
||||||
@ -74,6 +62,28 @@ 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(),
|
||||||
|
);
|
||||||
|
} else if let Some(col) = block
|
||||||
|
.filter(|vox| vox.is_fluid())
|
||||||
|
.and_then(|vox| vox.get_color())
|
||||||
|
{
|
||||||
|
let col = col.map(|e| e as f32 / 255.0);
|
||||||
|
|
||||||
|
vol::push_vox_verts(
|
||||||
|
&mut fluid_mesh,
|
||||||
|
self,
|
||||||
|
pos,
|
||||||
|
offs,
|
||||||
|
col,
|
||||||
|
|pos, norm, col, ao, light| {
|
||||||
|
FluidVertex::new(pos, norm, col, light * ao, 0.3)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
&neighbour_light,
|
||||||
|
|vox| vox.is_air(),
|
||||||
|
|vox| vox.is_opaque(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,16 +94,14 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for
|
|||||||
// Accumulate shade under opaque blocks
|
// Accumulate shade under opaque blocks
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
for j in 0..3 {
|
for j in 0..3 {
|
||||||
neighbour_light[0][i][j] = if let Some(opacity) = self
|
let (density, cap) = self
|
||||||
.get(pos + Vec3::new(i as i32 - 1, j as i32 - 1, -1))
|
.get(pos + Vec3::new(i as i32 - 1, j as i32 - 1, -1))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|vox| vox.get_opacity())
|
.map(|vox| block_shadow_density(vox.kind()))
|
||||||
{
|
.unwrap_or((0.0, 0.0));
|
||||||
(neighbour_light[0][i][j] * (1.0 - opacity * 0.1))
|
|
||||||
.max(1.0 - opacity)
|
neighbour_light[0][i][j] =
|
||||||
} else {
|
(neighbour_light[0][i][j] * (1.0 - density)).max(cap);
|
||||||
(neighbour_light[0][i][j] * 1.025).min(1.0)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +116,8 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mesh
|
|
||||||
|
(opaque_mesh, fluid_mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
@ -88,26 +89,24 @@ fn create_quad<P: Pipeline, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_vox_verts<
|
pub fn push_vox_verts<V: ReadVol, P: Pipeline>(
|
||||||
V: ReadVol,
|
|
||||||
P: Pipeline,
|
|
||||||
F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P::Vertex,
|
|
||||||
>(
|
|
||||||
mesh: &mut Mesh<P>,
|
mesh: &mut Mesh<P>,
|
||||||
vol: &V,
|
vol: &V,
|
||||||
pos: Vec3<i32>,
|
pos: Vec3<i32>,
|
||||||
offs: Vec3<f32>,
|
offs: Vec3<f32>,
|
||||||
col: Rgb<f32>,
|
col: Rgb<f32>,
|
||||||
vcons: F,
|
vcons: impl Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P::Vertex,
|
||||||
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,
|
||||||
|
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());
|
||||||
|
|
||||||
// -x
|
// -x
|
||||||
if vol
|
if vol
|
||||||
.get(pos - Vec3::unit_x())
|
.get(pos - Vec3::unit_x())
|
||||||
.map(|v| v.is_empty())
|
.map(|v| should_add(v))
|
||||||
.unwrap_or(error_makes_face)
|
.unwrap_or(error_makes_face)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
@ -116,14 +115,21 @@ pub fn push_vox_verts<
|
|||||||
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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// +x
|
// +x
|
||||||
if vol
|
if vol
|
||||||
.get(pos + Vec3::unit_x())
|
.get(pos + Vec3::unit_x())
|
||||||
.map(|v| v.is_empty())
|
.map(|v| should_add(v))
|
||||||
.unwrap_or(error_makes_face)
|
.unwrap_or(error_makes_face)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
@ -132,14 +138,21 @@ pub fn push_vox_verts<
|
|||||||
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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// -y
|
// -y
|
||||||
if vol
|
if vol
|
||||||
.get(pos - Vec3::unit_y())
|
.get(pos - Vec3::unit_y())
|
||||||
.map(|v| v.is_empty())
|
.map(|v| should_add(v))
|
||||||
.unwrap_or(error_makes_face)
|
.unwrap_or(error_makes_face)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
@ -148,14 +161,21 @@ pub fn push_vox_verts<
|
|||||||
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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// +y
|
// +y
|
||||||
if vol
|
if vol
|
||||||
.get(pos + Vec3::unit_y())
|
.get(pos + Vec3::unit_y())
|
||||||
.map(|v| v.is_empty())
|
.map(|v| should_add(v))
|
||||||
.unwrap_or(error_makes_face)
|
.unwrap_or(error_makes_face)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
@ -164,14 +184,21 @@ pub fn push_vox_verts<
|
|||||||
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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// -z
|
// -z
|
||||||
if vol
|
if vol
|
||||||
.get(pos - Vec3::unit_z())
|
.get(pos - Vec3::unit_z())
|
||||||
.map(|v| v.is_empty())
|
.map(|v| should_add(v))
|
||||||
.unwrap_or(error_makes_face)
|
.unwrap_or(error_makes_face)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
@ -180,14 +207,21 @@ pub fn push_vox_verts<
|
|||||||
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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// +z
|
// +z
|
||||||
if vol
|
if vol
|
||||||
.get(pos + Vec3::unit_z())
|
.get(pos + Vec3::unit_z())
|
||||||
.map(|v| v.is_empty())
|
.map(|v| should_add(v))
|
||||||
.unwrap_or(error_makes_face)
|
.unwrap_or(error_makes_face)
|
||||||
{
|
{
|
||||||
mesh.push_quad(create_quad(
|
mesh.push_quad(create_quad(
|
||||||
@ -196,7 +230,14 @@ pub fn push_vox_verts<
|
|||||||
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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ pub use self::{
|
|||||||
model::{DynamicModel, Model},
|
model::{DynamicModel, Model},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
||||||
|
fluid::FluidPipeline,
|
||||||
postprocess::{
|
postprocess::{
|
||||||
create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline,
|
create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline,
|
||||||
},
|
},
|
||||||
|
66
voxygen/src/render/pipelines/fluid.rs
Normal file
66
voxygen/src/render/pipelines/fluid.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use super::{
|
||||||
|
super::{Pipeline, TerrainLocals, TgtColorFmt, TgtDepthFmt},
|
||||||
|
Globals, Light,
|
||||||
|
};
|
||||||
|
use gfx::{
|
||||||
|
self,
|
||||||
|
// Macros
|
||||||
|
gfx_defines,
|
||||||
|
gfx_impl_struct_meta,
|
||||||
|
gfx_pipeline,
|
||||||
|
gfx_pipeline_inner,
|
||||||
|
gfx_vertex_struct_meta,
|
||||||
|
state::ColorMask,
|
||||||
|
};
|
||||||
|
use std::ops::Mul;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
gfx_defines! {
|
||||||
|
vertex Vertex {
|
||||||
|
pos_norm: u32 = "v_pos_norm",
|
||||||
|
col_light: u32 = "v_col_light",
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline pipe {
|
||||||
|
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||||
|
|
||||||
|
locals: gfx::ConstantBuffer<TerrainLocals> = "u_locals",
|
||||||
|
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||||
|
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||||
|
|
||||||
|
tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA),
|
||||||
|
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_TEST,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>, light: f32, _opac: f32) -> Self {
|
||||||
|
let (norm_axis, norm_dir) = norm
|
||||||
|
.as_slice()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_i, e)| **e != 0.0)
|
||||||
|
.unwrap_or((0, &1.0));
|
||||||
|
let norm_bits = (norm_axis << 1) | if *norm_dir > 0.0 { 1 } else { 0 };
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pos_norm: 0
|
||||||
|
| ((pos.x as u32) & 0x00FF) << 0
|
||||||
|
| ((pos.y as u32) & 0x00FF) << 8
|
||||||
|
| ((pos.z.max(0.0).min((1 << 13) as f32) as u32) & 0x1FFF) << 16
|
||||||
|
| ((norm_bits as u32) & 0x7) << 29,
|
||||||
|
col_light: 0
|
||||||
|
| ((col.r.mul(200.0) as u32) & 0xFF) << 8
|
||||||
|
| ((col.g.mul(200.0) as u32) & 0xFF) << 16
|
||||||
|
| ((col.b.mul(200.0) as u32) & 0xFF) << 24
|
||||||
|
| ((light.mul(255.0) as u32) & 0xFF) << 0,
|
||||||
|
//| ((opac.mul(0.4) as u32) & 0xFF) << 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FluidPipeline;
|
||||||
|
|
||||||
|
impl Pipeline for FluidPipeline {
|
||||||
|
type Vertex = Vertex;
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
pub mod figure;
|
pub mod figure;
|
||||||
|
pub mod fluid;
|
||||||
pub mod postprocess;
|
pub mod postprocess;
|
||||||
pub mod skybox;
|
pub mod skybox;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
use super::util::arr_to_mat;
|
use super::util::arr_to_mat;
|
||||||
|
use common::terrain::BlockKind;
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self,
|
self,
|
||||||
gfx_constant_struct_meta,
|
gfx_constant_struct_meta,
|
||||||
@ -26,6 +28,7 @@ gfx_defines! {
|
|||||||
tick: [f32; 4] = "tick",
|
tick: [f32; 4] = "tick",
|
||||||
screen_res: [f32; 4] = "screen_res",
|
screen_res: [f32; 4] = "screen_res",
|
||||||
light_count: [u32; 4] = "light_count",
|
light_count: [u32; 4] = "light_count",
|
||||||
|
medium: [u32; 4] = "medium",
|
||||||
}
|
}
|
||||||
|
|
||||||
constant Light {
|
constant Light {
|
||||||
@ -46,6 +49,7 @@ impl Globals {
|
|||||||
tick: f64,
|
tick: f64,
|
||||||
screen_res: Vec2<u16>,
|
screen_res: Vec2<u16>,
|
||||||
light_count: usize,
|
light_count: usize,
|
||||||
|
medium: BlockKind,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
view_mat: arr_to_mat(view_mat.into_col_array()),
|
view_mat: arr_to_mat(view_mat.into_col_array()),
|
||||||
@ -57,6 +61,7 @@ impl Globals {
|
|||||||
tick: [tick as f32; 4],
|
tick: [tick as f32; 4],
|
||||||
screen_res: Vec4::from(screen_res.map(|e| e as f32)).into_array(),
|
screen_res: Vec4::from(screen_res.map(|e| e as f32)).into_array(),
|
||||||
light_count: [light_count as u32; 4],
|
light_count: [light_count as u32; 4],
|
||||||
|
medium: [if medium.is_fluid() { 1 } else { 0 }; 4],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,6 +78,7 @@ impl Default for Globals {
|
|||||||
0.0,
|
0.0,
|
||||||
Vec2::new(800, 500),
|
Vec2::new(800, 500),
|
||||||
0,
|
0,
|
||||||
|
BlockKind::Air,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use super::{
|
|||||||
gfx_backend,
|
gfx_backend,
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
model::{DynamicModel, Model},
|
model::{DynamicModel, Model},
|
||||||
pipelines::{figure, postprocess, skybox, terrain, ui, Globals, Light},
|
pipelines::{figure, fluid, postprocess, skybox, terrain, ui, Globals, Light},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
Pipeline, RenderError,
|
Pipeline, RenderError,
|
||||||
};
|
};
|
||||||
@ -64,6 +64,7 @@ pub struct Renderer {
|
|||||||
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
||||||
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
||||||
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
|
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
|
||||||
|
fluid_pipeline: GfxPipeline<fluid::pipe::Init<'static>>,
|
||||||
ui_pipeline: GfxPipeline<ui::pipe::Init<'static>>,
|
ui_pipeline: GfxPipeline<ui::pipe::Init<'static>>,
|
||||||
postprocess_pipeline: GfxPipeline<postprocess::pipe::Init<'static>>,
|
postprocess_pipeline: GfxPipeline<postprocess::pipe::Init<'static>>,
|
||||||
|
|
||||||
@ -80,8 +81,14 @@ impl Renderer {
|
|||||||
) -> Result<Self, RenderError> {
|
) -> Result<Self, RenderError> {
|
||||||
let mut shader_reload_indicator = ReloadIndicator::new();
|
let mut shader_reload_indicator = ReloadIndicator::new();
|
||||||
|
|
||||||
let (skybox_pipeline, figure_pipeline, terrain_pipeline, ui_pipeline, postprocess_pipeline) =
|
let (
|
||||||
create_pipelines(&mut factory, &mut shader_reload_indicator)?;
|
skybox_pipeline,
|
||||||
|
figure_pipeline,
|
||||||
|
terrain_pipeline,
|
||||||
|
fluid_pipeline,
|
||||||
|
ui_pipeline,
|
||||||
|
postprocess_pipeline,
|
||||||
|
) = create_pipelines(&mut factory, &mut shader_reload_indicator)?;
|
||||||
|
|
||||||
let dims = win_color_view.get_dimensions();
|
let dims = win_color_view.get_dimensions();
|
||||||
let (tgt_color_view, tgt_depth_view, tgt_color_res) =
|
let (tgt_color_view, tgt_depth_view, tgt_color_res) =
|
||||||
@ -106,6 +113,7 @@ impl Renderer {
|
|||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
figure_pipeline,
|
figure_pipeline,
|
||||||
terrain_pipeline,
|
terrain_pipeline,
|
||||||
|
fluid_pipeline,
|
||||||
ui_pipeline,
|
ui_pipeline,
|
||||||
postprocess_pipeline,
|
postprocess_pipeline,
|
||||||
|
|
||||||
@ -191,13 +199,15 @@ impl Renderer {
|
|||||||
Ok((
|
Ok((
|
||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
figure_pipeline,
|
figure_pipeline,
|
||||||
terrain_pipline,
|
terrain_pipeline,
|
||||||
|
fluid_pipeline,
|
||||||
ui_pipeline,
|
ui_pipeline,
|
||||||
postprocess_pipeline,
|
postprocess_pipeline,
|
||||||
)) => {
|
)) => {
|
||||||
self.skybox_pipeline = skybox_pipeline;
|
self.skybox_pipeline = skybox_pipeline;
|
||||||
self.figure_pipeline = figure_pipeline;
|
self.figure_pipeline = figure_pipeline;
|
||||||
self.terrain_pipeline = terrain_pipline;
|
self.terrain_pipeline = terrain_pipeline;
|
||||||
|
self.fluid_pipeline = fluid_pipeline;
|
||||||
self.ui_pipeline = ui_pipeline;
|
self.ui_pipeline = ui_pipeline;
|
||||||
self.postprocess_pipeline = postprocess_pipeline;
|
self.postprocess_pipeline = postprocess_pipeline;
|
||||||
}
|
}
|
||||||
@ -398,6 +408,28 @@ impl Renderer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queue the rendering of the provided terrain chunk model in the upcoming frame.
|
||||||
|
pub fn render_fluid_chunk(
|
||||||
|
&mut self,
|
||||||
|
model: &Model<fluid::FluidPipeline>,
|
||||||
|
globals: &Consts<Globals>,
|
||||||
|
locals: &Consts<terrain::Locals>,
|
||||||
|
lights: &Consts<Light>,
|
||||||
|
) {
|
||||||
|
self.encoder.draw(
|
||||||
|
&model.slice,
|
||||||
|
&self.fluid_pipeline.pso,
|
||||||
|
&fluid::pipe::Data {
|
||||||
|
vbuf: model.vbuf.clone(),
|
||||||
|
locals: locals.buf.clone(),
|
||||||
|
globals: globals.buf.clone(),
|
||||||
|
lights: lights.buf.clone(),
|
||||||
|
tgt_color: self.tgt_color_view.clone(),
|
||||||
|
tgt_depth: self.tgt_depth_view.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Queue the rendering of the provided UI element in the upcoming frame.
|
/// Queue the rendering of the provided UI element in the upcoming frame.
|
||||||
pub fn render_ui_element(
|
pub fn render_ui_element(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -462,6 +494,7 @@ fn create_pipelines(
|
|||||||
GfxPipeline<skybox::pipe::Init<'static>>,
|
GfxPipeline<skybox::pipe::Init<'static>>,
|
||||||
GfxPipeline<figure::pipe::Init<'static>>,
|
GfxPipeline<figure::pipe::Init<'static>>,
|
||||||
GfxPipeline<terrain::pipe::Init<'static>>,
|
GfxPipeline<terrain::pipe::Init<'static>>,
|
||||||
|
GfxPipeline<fluid::pipe::Init<'static>>,
|
||||||
GfxPipeline<ui::pipe::Init<'static>>,
|
GfxPipeline<ui::pipe::Init<'static>>,
|
||||||
GfxPipeline<postprocess::pipe::Init<'static>>,
|
GfxPipeline<postprocess::pipe::Init<'static>>,
|
||||||
),
|
),
|
||||||
@ -479,12 +512,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(
|
||||||
@ -495,6 +532,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
|
||||||
@ -506,6 +544,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
|
||||||
@ -517,6 +556,19 @@ 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
|
||||||
|
let fluid_pipeline = create_pipeline(
|
||||||
|
factory,
|
||||||
|
fluid::pipe::new(),
|
||||||
|
&assets::load_watched::<String>("voxygen.shaders.fluid-vert", shader_reload_indicator)
|
||||||
|
.unwrap(),
|
||||||
|
&assets::load_watched::<String>("voxygen.shaders.fluid-frag", shader_reload_indicator)
|
||||||
|
.unwrap(),
|
||||||
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Nothing,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering UI elements
|
// Construct a pipeline for rendering UI elements
|
||||||
@ -528,6 +580,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
|
||||||
@ -545,12 +598,14 @@ fn create_pipelines(
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&include_ctx,
|
&include_ctx,
|
||||||
|
gfx::state::CullFace::Back,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
figure_pipeline,
|
figure_pipeline,
|
||||||
terrain_pipeline,
|
terrain_pipeline,
|
||||||
|
fluid_pipeline,
|
||||||
ui_pipeline,
|
ui_pipeline,
|
||||||
postprocess_pipeline,
|
postprocess_pipeline,
|
||||||
))
|
))
|
||||||
@ -563,6 +618,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)?;
|
||||||
@ -578,7 +634,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),
|
||||||
|
@ -165,6 +165,7 @@ impl FigureModelCache {
|
|||||||
let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
|
let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
|
||||||
Segment::from(assets::load_expect::<DotVoxData>(full_specifier.as_str()).as_ref())
|
Segment::from(assets::load_expect::<DotVoxData>(full_specifier.as_str()).as_ref())
|
||||||
.generate_mesh(position)
|
.generate_mesh(position)
|
||||||
|
.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_head(race: humanoid::Race, body_type: humanoid::BodyType) -> Mesh<FigurePipeline> {
|
fn load_head(race: humanoid::Race, body_type: humanoid::BodyType) -> Mesh<FigurePipeline> {
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
window::Event,
|
window::Event,
|
||||||
};
|
};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::comp;
|
use common::{comp, terrain::BlockKind, vol::ReadVol};
|
||||||
use specs::Join;
|
use specs::Join;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -194,6 +194,12 @@ impl Scene {
|
|||||||
client.state().get_time(),
|
client.state().get_time(),
|
||||||
renderer.get_resolution(),
|
renderer.get_resolution(),
|
||||||
lights.len(),
|
lights.len(),
|
||||||
|
client
|
||||||
|
.state()
|
||||||
|
.terrain()
|
||||||
|
.get(cam_pos.map(|e| e.floor() as i32))
|
||||||
|
.map(|b| b.kind())
|
||||||
|
.unwrap_or(BlockKind::Air),
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.expect("Failed to update global constants");
|
.expect("Failed to update global constants");
|
||||||
@ -221,9 +227,9 @@ impl Scene {
|
|||||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||||
|
|
||||||
// Render terrain and figures.
|
// Render terrain and figures.
|
||||||
self.terrain.render(renderer, &self.globals, &self.lights);
|
|
||||||
self.figure_mgr
|
self.figure_mgr
|
||||||
.render(renderer, client, &self.globals, &self.lights, &self.camera);
|
.render(renderer, client, &self.globals, &self.lights, &self.camera);
|
||||||
|
self.terrain.render(renderer, &self.globals, &self.lights);
|
||||||
|
|
||||||
renderer.render_post_process(
|
renderer.render_post_process(
|
||||||
&self.postprocess.model,
|
&self.postprocess.model,
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::Meshable,
|
mesh::Meshable,
|
||||||
render::{Consts, Globals, Light, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline},
|
render::{
|
||||||
|
Consts, FluidPipeline, Globals, Light, Mesh, Model, Renderer, TerrainLocals,
|
||||||
|
TerrainPipeline,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
@ -16,7 +19,8 @@ use vek::*;
|
|||||||
|
|
||||||
struct TerrainChunk {
|
struct TerrainChunk {
|
||||||
// GPU data
|
// GPU data
|
||||||
model: Model<TerrainPipeline>,
|
opaque_model: Model<TerrainPipeline>,
|
||||||
|
fluid_model: Model<FluidPipeline>,
|
||||||
locals: Consts<TerrainLocals>,
|
locals: Consts<TerrainLocals>,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
z_bounds: (f32, f32),
|
z_bounds: (f32, f32),
|
||||||
@ -32,7 +36,8 @@ struct ChunkMeshState {
|
|||||||
struct MeshWorkerResponse {
|
struct MeshWorkerResponse {
|
||||||
pos: Vec2<i32>,
|
pos: Vec2<i32>,
|
||||||
z_bounds: (f32, f32),
|
z_bounds: (f32, f32),
|
||||||
mesh: Mesh<TerrainPipeline>,
|
opaque_mesh: Mesh<TerrainPipeline>,
|
||||||
|
fluid_mesh: Mesh<FluidPipeline>,
|
||||||
started_tick: u64,
|
started_tick: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,10 +49,12 @@ fn mesh_worker(
|
|||||||
volume: <TerrainMap as SampleVol<Aabr<i32>>>::Sample,
|
volume: <TerrainMap as SampleVol<Aabr<i32>>>::Sample,
|
||||||
range: Aabb<i32>,
|
range: Aabb<i32>,
|
||||||
) -> MeshWorkerResponse {
|
) -> MeshWorkerResponse {
|
||||||
|
let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range);
|
||||||
MeshWorkerResponse {
|
MeshWorkerResponse {
|
||||||
pos,
|
pos,
|
||||||
z_bounds,
|
z_bounds,
|
||||||
mesh: volume.generate_mesh(range),
|
opaque_mesh,
|
||||||
|
fluid_mesh,
|
||||||
started_tick,
|
started_tick,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,8 +269,11 @@ impl Terrain {
|
|||||||
self.chunks.insert(
|
self.chunks.insert(
|
||||||
response.pos,
|
response.pos,
|
||||||
TerrainChunk {
|
TerrainChunk {
|
||||||
model: renderer
|
opaque_model: renderer
|
||||||
.create_model(&response.mesh)
|
.create_model(&response.opaque_mesh)
|
||||||
|
.expect("Failed to upload chunk mesh to the GPU!"),
|
||||||
|
fluid_model: renderer
|
||||||
|
.create_model(&response.fluid_mesh)
|
||||||
.expect("Failed to upload chunk mesh to the GPU!"),
|
.expect("Failed to upload chunk mesh to the GPU!"),
|
||||||
locals: renderer
|
locals: renderer
|
||||||
.create_consts(&[TerrainLocals {
|
.create_consts(&[TerrainLocals {
|
||||||
@ -334,9 +344,17 @@ impl Terrain {
|
|||||||
globals: &Consts<Globals>,
|
globals: &Consts<Globals>,
|
||||||
lights: &Consts<Light>,
|
lights: &Consts<Light>,
|
||||||
) {
|
) {
|
||||||
|
// Opaque
|
||||||
for (_pos, chunk) in &self.chunks {
|
for (_pos, chunk) in &self.chunks {
|
||||||
if chunk.visible {
|
if chunk.visible {
|
||||||
renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals, lights);
|
renderer.render_terrain_chunk(&chunk.opaque_model, globals, &chunk.locals, lights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translucent
|
||||||
|
for (_pos, chunk) in &self.chunks {
|
||||||
|
if chunk.visible {
|
||||||
|
renderer.render_fluid_chunk(&chunk.fluid_model, globals, &chunk.locals, lights);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use client::{self, Client};
|
use client::{self, Client};
|
||||||
use common::{
|
use common::{
|
||||||
clock::Clock, comp, comp::Pos, comp::Vel, msg::ClientState, terrain::Block, vol::ReadVol,
|
clock::Clock,
|
||||||
|
comp,
|
||||||
|
comp::Pos,
|
||||||
|
comp::Vel,
|
||||||
|
msg::ClientState,
|
||||||
|
terrain::{Block, BlockKind},
|
||||||
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use specs::Join;
|
use specs::Join;
|
||||||
@ -39,7 +45,7 @@ impl SessionState {
|
|||||||
key_state: KeyState::new(),
|
key_state: KeyState::new(),
|
||||||
controller: comp::Controller::default(),
|
controller: comp::Controller::default(),
|
||||||
hud: Hud::new(global_state),
|
hud: Hud::new(global_state),
|
||||||
selected_block: Block::new(1, Rgb::broadcast(255)),
|
selected_block: Block::new(BlockKind::Normal, Rgb::broadcast(255)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
World, CONFIG,
|
World, CONFIG,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::{structure::StructureBlock, Block, Structure},
|
terrain::{structure::StructureBlock, Block, BlockKind, Structure},
|
||||||
util::saturate_srgb,
|
util::saturate_srgb,
|
||||||
vol::{ReadVol, Vox},
|
vol::{ReadVol, Vox},
|
||||||
};
|
};
|
||||||
@ -163,7 +163,7 @@ impl<'a> BlockGen<'a> {
|
|||||||
let (definitely_underground, height, water_height) =
|
let (definitely_underground, height, water_height) =
|
||||||
if (wposf.z as f32) < alt - 64.0 * chaos {
|
if (wposf.z as f32) < alt - 64.0 * chaos {
|
||||||
// Shortcut warping
|
// Shortcut warping
|
||||||
(true, alt, water_level)
|
(true, alt, CONFIG.sea_level /*water_level*/)
|
||||||
} else {
|
} else {
|
||||||
// Apply warping
|
// Apply warping
|
||||||
let warp = (world
|
let warp = (world
|
||||||
@ -204,7 +204,11 @@ impl<'a> BlockGen<'a> {
|
|||||||
(alt + warp).max(cliff_height)
|
(alt + warp).max(cliff_height)
|
||||||
};
|
};
|
||||||
|
|
||||||
(false, height, (water_level + warp).max(CONFIG.sea_level))
|
(
|
||||||
|
false,
|
||||||
|
height,
|
||||||
|
/*(water_level + warp).max(*/ CONFIG.sea_level, /*)*/
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sample blocks
|
// Sample blocks
|
||||||
@ -221,8 +225,7 @@ impl<'a> BlockGen<'a> {
|
|||||||
// let sand = Block::new(1, Rgb::new(180, 150, 50));
|
// let sand = Block::new(1, Rgb::new(180, 150, 50));
|
||||||
// let warm_stone = Block::new(1, Rgb::new(165, 165, 130));
|
// let warm_stone = Block::new(1, Rgb::new(165, 165, 130));
|
||||||
|
|
||||||
//let water = Block::new(1, Rgb::new(100, 150, 255));
|
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
|
||||||
let water = Block::new(1, Rgb::new(0, 24, 255));
|
|
||||||
|
|
||||||
let grass_depth = 1.5 + 2.0 * chaos;
|
let grass_depth = 1.5 + 2.0 * chaos;
|
||||||
let block = if (wposf.z as f32) < height - grass_depth {
|
let block = if (wposf.z as f32) < height - grass_depth {
|
||||||
@ -234,9 +237,9 @@ impl<'a> BlockGen<'a> {
|
|||||||
|
|
||||||
// Underground
|
// Underground
|
||||||
if (wposf.z as f32) > alt - 32.0 * chaos {
|
if (wposf.z as f32) > alt - 32.0 * chaos {
|
||||||
Some(Block::new(1, col))
|
Some(Block::new(BlockKind::Normal, col))
|
||||||
} else {
|
} else {
|
||||||
Some(Block::new(2, col))
|
Some(Block::new(BlockKind::Dense, col))
|
||||||
}
|
}
|
||||||
} else if (wposf.z as f32) < height {
|
} else if (wposf.z as f32) < height {
|
||||||
let col = Lerp::lerp(
|
let col = Lerp::lerp(
|
||||||
@ -248,12 +251,9 @@ impl<'a> BlockGen<'a> {
|
|||||||
);
|
);
|
||||||
// Surface
|
// Surface
|
||||||
Some(Block::new(
|
Some(Block::new(
|
||||||
1,
|
BlockKind::Normal,
|
||||||
saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8),
|
saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8),
|
||||||
))
|
))
|
||||||
} else if (wposf.z as f32) < water_height {
|
|
||||||
// Ocean
|
|
||||||
Some(water)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -284,7 +284,7 @@ impl<'a> BlockGen<'a> {
|
|||||||
let field2 = RandomField::new(world.sim().seed + 2);
|
let field2 = RandomField::new(world.sim().seed + 2);
|
||||||
|
|
||||||
Some(Block::new(
|
Some(Block::new(
|
||||||
1,
|
BlockKind::Normal,
|
||||||
stone_col
|
stone_col
|
||||||
- Rgb::new(
|
- Rgb::new(
|
||||||
field0.get(wpos) as u8 % 16,
|
field0.get(wpos) as u8 % 16,
|
||||||
@ -297,6 +297,16 @@ impl<'a> BlockGen<'a> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Water
|
||||||
|
let block = block.or_else(|| {
|
||||||
|
if (wposf.z as f32) < water_height {
|
||||||
|
// Ocean
|
||||||
|
Some(water)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let block = structures
|
let block = structures
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|st| {
|
.find_map(|st| {
|
||||||
@ -415,7 +425,7 @@ impl StructureInfo {
|
|||||||
.map(|e: i32| (e.abs() / 2) * 2)
|
.map(|e: i32| (e.abs() / 2) * 2)
|
||||||
.reduce_max()
|
.reduce_max()
|
||||||
{
|
{
|
||||||
Some(Block::new(2, Rgb::new(203, 170, 146)))
|
Some(Block::new(BlockKind::Dense, Rgb::new(203, 170, 146)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -430,7 +440,14 @@ impl StructureInfo {
|
|||||||
.get((block_pos * 128) / 128) // Scaling
|
.get((block_pos * 128) / 128) // Scaling
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|b| {
|
.and_then(|b| {
|
||||||
block_from_structure(*b, block_pos, self.pos.into(), self.seed, sample)
|
block_from_structure(
|
||||||
|
*b,
|
||||||
|
volume.default_kind(),
|
||||||
|
block_pos,
|
||||||
|
self.pos.into(),
|
||||||
|
self.seed,
|
||||||
|
sample,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,6 +456,7 @@ impl StructureInfo {
|
|||||||
|
|
||||||
fn block_from_structure(
|
fn block_from_structure(
|
||||||
sblock: StructureBlock,
|
sblock: StructureBlock,
|
||||||
|
default_kind: BlockKind,
|
||||||
pos: Vec3<i32>,
|
pos: Vec3<i32>,
|
||||||
structure_pos: Vec2<i32>,
|
structure_pos: Vec2<i32>,
|
||||||
structure_seed: u32,
|
structure_seed: u32,
|
||||||
@ -451,8 +469,9 @@ fn block_from_structure(
|
|||||||
+ ((field.get(Vec3::from(pos)) % 256) as f32 / 256.0 - 0.5) * 0.15;
|
+ ((field.get(Vec3::from(pos)) % 256) as f32 / 256.0 - 0.5) * 0.15;
|
||||||
|
|
||||||
match sblock {
|
match sblock {
|
||||||
|
StructureBlock::None => None,
|
||||||
StructureBlock::TemperateLeaves => Some(Block::new(
|
StructureBlock::TemperateLeaves => Some(Block::new(
|
||||||
1,
|
BlockKind::Normal,
|
||||||
Lerp::lerp(
|
Lerp::lerp(
|
||||||
Rgb::new(0.0, 132.0, 94.0),
|
Rgb::new(0.0, 132.0, 94.0),
|
||||||
Rgb::new(142.0, 181.0, 0.0),
|
Rgb::new(142.0, 181.0, 0.0),
|
||||||
@ -461,7 +480,12 @@ fn block_from_structure(
|
|||||||
.map(|e| e as u8),
|
.map(|e| e as u8),
|
||||||
)),
|
)),
|
||||||
StructureBlock::PineLeaves => Some(Block::new(
|
StructureBlock::PineLeaves => Some(Block::new(
|
||||||
1,
|
BlockKind::Normal,
|
||||||
|
Lerp::lerp(Rgb::new(0.0, 60.0, 50.0), Rgb::new(30.0, 100.0, 10.0), lerp)
|
||||||
|
.map(|e| e as u8),
|
||||||
|
)),
|
||||||
|
StructureBlock::PalmLeaves => Some(Block::new(
|
||||||
|
BlockKind::Normal,
|
||||||
Lerp::lerp(
|
Lerp::lerp(
|
||||||
Rgb::new(0.0, 108.0, 113.0),
|
Rgb::new(0.0, 108.0, 113.0),
|
||||||
Rgb::new(30.0, 156.0, 10.0),
|
Rgb::new(30.0, 156.0, 10.0),
|
||||||
@ -469,26 +493,25 @@ fn block_from_structure(
|
|||||||
)
|
)
|
||||||
.map(|e| e as u8),
|
.map(|e| e as u8),
|
||||||
)),
|
)),
|
||||||
StructureBlock::PalmLeaves => Some(Block::new(
|
StructureBlock::Water => Some(Block::new(BlockKind::Water, Rgb::new(100, 150, 255))),
|
||||||
1,
|
StructureBlock::GreenSludge => Some(Block::new(BlockKind::Water, Rgb::new(30, 126, 23))),
|
||||||
|
StructureBlock::Acacia => Some(Block::new(
|
||||||
|
BlockKind::Normal,
|
||||||
Lerp::lerp(
|
Lerp::lerp(
|
||||||
Rgb::new(15.0, 156.0, 70.0),
|
Rgb::new(15.0, 126.0, 50.0),
|
||||||
Rgb::new(40.0, 222.0, 0.0),
|
Rgb::new(30.0, 180.0, 10.0),
|
||||||
lerp,
|
lerp,
|
||||||
)
|
)
|
||||||
.map(|e| e as u8),
|
.map(|e| e as u8),
|
||||||
)),
|
)),
|
||||||
StructureBlock::Acacia => Some(Block::new(
|
|
||||||
1,
|
|
||||||
Lerp::lerp(Rgb::new(35.0, 156.0, 0.0), Rgb::new(62.0, 208.0, 0.0), lerp)
|
|
||||||
.map(|e| e as u8),
|
|
||||||
)),
|
|
||||||
StructureBlock::Fruit => Some(Block::new(
|
StructureBlock::Fruit => Some(Block::new(
|
||||||
1,
|
BlockKind::Normal,
|
||||||
Lerp::lerp(Rgb::new(237.0, 0.0, 0.0), Rgb::new(200.0, 237.0, 0.0), lerp)
|
Lerp::lerp(Rgb::new(237.0, 0.0, 0.0), Rgb::new(200.0, 237.0, 0.0), lerp)
|
||||||
.map(|e| e as u8),
|
.map(|e| e as u8),
|
||||||
)),
|
)),
|
||||||
StructureBlock::Hollow => Some(Block::empty()),
|
StructureBlock::Hollow => Some(Block::empty()),
|
||||||
StructureBlock::Block(block) => Some(block).filter(|block| !block.is_empty()),
|
StructureBlock::Normal(color) => {
|
||||||
|
Some(Block::new(default_kind, color)).filter(|block| !block.is_empty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets,
|
assets,
|
||||||
terrain::{Structure, TerrainChunkSize},
|
terrain::{BlockKind, Structure, TerrainChunkSize},
|
||||||
vol::VolSize,
|
vol::VolSize,
|
||||||
};
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -29,13 +29,27 @@ static DUNGEON_RAND: RandomPerm = RandomPerm::new(0x42782335);
|
|||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref DUNGEONS: Vec<Arc<Structure>> = vec![
|
pub static ref DUNGEONS: Vec<Arc<Structure>> = vec![
|
||||||
assets::load_map("world.structure.dungeon.ruins", |s: Structure| s
|
assets::load_map("world.structure.dungeon.ruins", |s: Structure| s
|
||||||
.with_center(Vec3::new(57, 58, 61)))
|
.with_center(Vec3::new(57, 58, 61))
|
||||||
|
.with_default_kind(BlockKind::Dense))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
assets::load_map("world.structure.dungeon.ruins_2", |s: Structure| s
|
assets::load_map("world.structure.dungeon.ruins_2", |s: Structure| s
|
||||||
.with_center(Vec3::new(53, 57, 60)))
|
.with_center(Vec3::new(53, 57, 60))
|
||||||
|
.with_default_kind(BlockKind::Dense))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
assets::load_map("world.structure.dungeon.ruins_3", |s: Structure| s
|
assets::load_map("world.structure.dungeon.ruins_3", |s: Structure| s
|
||||||
.with_center(Vec3::new(58, 45, 72)))
|
.with_center(Vec3::new(58, 45, 72))
|
||||||
|
.with_default_kind(BlockKind::Dense))
|
||||||
|
.unwrap(),
|
||||||
|
assets::load_map(
|
||||||
|
"world.structure.dungeon.meso_sewer_temple",
|
||||||
|
|s: Structure| s
|
||||||
|
.with_center(Vec3::new(63, 62, 60))
|
||||||
|
.with_default_kind(BlockKind::Dense)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
assets::load_map("world.structure.dungeon.ruins_maze", |s: Structure| s
|
||||||
|
.with_center(Vec3::new(60, 60, 116))
|
||||||
|
.with_default_kind(BlockKind::Dense))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -335,7 +349,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,
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||||||
util::{Sampler, SamplerMut},
|
util::{Sampler, SamplerMut},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||||
vol::{ReadVol, VolSize, Vox, WriteVol},
|
vol::{ReadVol, VolSize, Vox, WriteVol},
|
||||||
};
|
};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@ -59,8 +59,8 @@ impl World {
|
|||||||
|
|
||||||
pub fn generate_chunk(&self, chunk_pos: Vec2<i32>) -> (TerrainChunk, ChunkSupplement) {
|
pub fn generate_chunk(&self, chunk_pos: Vec2<i32>) -> (TerrainChunk, ChunkSupplement) {
|
||||||
let air = Block::empty();
|
let air = Block::empty();
|
||||||
let stone = Block::new(2, Rgb::new(200, 220, 255));
|
let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255));
|
||||||
let water = Block::new(5, Rgb::new(100, 150, 255));
|
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
|
||||||
|
|
||||||
let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE);
|
let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE);
|
||||||
let (base_z, sim_chunk) = match self
|
let (base_z, sim_chunk) = match self
|
||||||
|
Loading…
Reference in New Issue
Block a user