mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/instancing' into 'master'
Instancing (block sprites) See merge request veloren/veloren!450
This commit is contained in:
commit
d9854ad682
@ -32,7 +32,7 @@ void main() {
|
||||
vec3 surf_color = srgb_to_linear(model_col.rgb * f_col) * 4.0 * 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 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true);
|
||||
vec3 color = mix(surf_color, fog_color, fog_level);
|
||||
|
||||
tgt_color = vec4(color, 1.0);
|
||||
|
@ -41,14 +41,14 @@ void main() {
|
||||
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 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true);
|
||||
|
||||
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;
|
||||
vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, false) * f_light;
|
||||
// 0 = 100% reflection, 1 = translucent water
|
||||
float passthrough = pow(dot(faceforward(norm, norm, cam_to_frag), -cam_to_frag), 1.0);
|
||||
|
||||
|
@ -5,12 +5,12 @@ const float PI = 3.141592;
|
||||
const vec3 SKY_DAY_TOP = vec3(0.1, 0.2, 0.9);
|
||||
const vec3 SKY_DAY_MID = vec3(0.02, 0.08, 0.8);
|
||||
const vec3 SKY_DAY_BOT = vec3(0.02, 0.01, 0.3);
|
||||
const vec3 DAY_LIGHT = vec3(0.75, 0.75, 1.0);
|
||||
const vec3 DAY_LIGHT = vec3(1.3, 0.9, 1.1);
|
||||
|
||||
const vec3 SKY_DUSK_TOP = vec3(0.21, 0.28, 0.50);
|
||||
const vec3 SKY_DUSK_MID = vec3(0.68, 0.03, 0.0);
|
||||
const vec3 SKY_DUSK_BOT = vec3(0.0, 0.0, 0.13);
|
||||
const vec3 DUSK_LIGHT = vec3(0.95, 0.6, 0.4);
|
||||
const vec3 SKY_DUSK_TOP = vec3(0.06, 0.1, 0.20);
|
||||
const vec3 SKY_DUSK_MID = vec3(0.35, 0.1, 0.15);
|
||||
const vec3 SKY_DUSK_BOT = vec3(0.0, 0.1, 0.13);
|
||||
const vec3 DUSK_LIGHT = vec3(3.0, 0.65, 0.3);
|
||||
|
||||
const vec3 SKY_NIGHT_TOP = vec3(0.001, 0.001, 0.0025);
|
||||
const vec3 SKY_NIGHT_MID = vec3(0.001, 0.005, 0.02);
|
||||
@ -33,7 +33,7 @@ float get_sun_brightness(vec3 sun_dir) {
|
||||
const float PERSISTENT_AMBIANCE = 0.008;
|
||||
|
||||
vec3 get_sun_diffuse(vec3 norm, float time_of_day) {
|
||||
const float SUN_AMBIANCE = 0.075;
|
||||
const float SUN_AMBIANCE = 0.15;
|
||||
|
||||
vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
|
||||
@ -41,7 +41,7 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) {
|
||||
|
||||
// clamp() changed to max() as sun_dir.z is produced from a cos() function and therefore never greater than 1
|
||||
|
||||
vec3 sun_color = normalize(mix(
|
||||
vec3 sun_color = mix(
|
||||
mix(
|
||||
DUSK_LIGHT,
|
||||
NIGHT_LIGHT,
|
||||
@ -49,7 +49,7 @@ vec3 get_sun_diffuse(vec3 norm, float time_of_day) {
|
||||
),
|
||||
DAY_LIGHT,
|
||||
max(-sun_dir.z, 0)
|
||||
));
|
||||
);
|
||||
|
||||
vec3 diffuse_light = (SUN_AMBIANCE + max(dot(-norm, sun_dir), 0.0) * sun_color) * sun_light + PERSISTENT_AMBIANCE;
|
||||
|
||||
@ -83,12 +83,15 @@ float is_star_at(vec3 dir) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
vec3 get_sky_color(vec3 dir, float time_of_day) {
|
||||
vec3 get_sky_color(vec3 dir, float time_of_day, bool with_stars) {
|
||||
// Sky color
|
||||
vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
|
||||
// Add white dots for stars. Note these flicker and jump due to FXAA
|
||||
float star = is_star_at(dir);
|
||||
float star = 0.0;
|
||||
if (with_stars) {
|
||||
star = is_star_at(dir);
|
||||
}
|
||||
|
||||
// Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1
|
||||
|
||||
@ -134,8 +137,8 @@ vec3 get_sky_color(vec3 dir, float time_of_day) {
|
||||
|
||||
// Sun
|
||||
|
||||
const vec3 SUN_HALO_COLOR = vec3(1.0, 0.35, 0.1) * 0.3;
|
||||
const vec3 SUN_SURF_COLOR = vec3(1.0, 0.9, 0.35) * 200.0;
|
||||
const vec3 SUN_HALO_COLOR = vec3(1.5, 0.35, 0.0) * 0.3;
|
||||
const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 200.0;
|
||||
|
||||
vec3 sun_halo = pow(max(dot(dir, -sun_dir) + 0.1, 0.0), 8.0) * SUN_HALO_COLOR;
|
||||
vec3 sun_surf = pow(max(dot(dir, -sun_dir) - 0.0045, 0.0), 1000.0) * SUN_SURF_COLOR;
|
||||
|
@ -13,5 +13,5 @@ uniform u_locals {
|
||||
out vec4 tgt_color;
|
||||
|
||||
void main() {
|
||||
tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x), 1.0);
|
||||
tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, true), 1.0);
|
||||
}
|
||||
|
27
assets/voxygen/shaders/sprite-frag.glsl
Normal file
27
assets/voxygen/shaders/sprite-frag.glsl
Normal file
@ -0,0 +1,27 @@
|
||||
#version 330 core
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in vec3 f_norm;
|
||||
in vec3 f_col;
|
||||
in float f_light;
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
|
||||
const float RENDER_DIST = 112.0;
|
||||
const float FADE_DIST = 32.0;
|
||||
|
||||
void main() {
|
||||
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;
|
||||
|
||||
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, true);
|
||||
vec3 color = mix(surf_color, fog_color, fog_level);
|
||||
|
||||
tgt_color = vec4(color, 1.0 - clamp((distance(focus_pos.xy, f_pos.xy) - (RENDER_DIST - FADE_DIST)) / FADE_DIST, 0, 1));
|
||||
}
|
49
assets/voxygen/shaders/sprite-vert.glsl
Normal file
49
assets/voxygen/shaders/sprite-vert.glsl
Normal file
@ -0,0 +1,49 @@
|
||||
#version 330 core
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
|
||||
in vec3 v_pos;
|
||||
in vec3 v_norm;
|
||||
in vec3 v_col;
|
||||
in vec4 inst_mat0;
|
||||
in vec4 inst_mat1;
|
||||
in vec4 inst_mat2;
|
||||
in vec4 inst_mat3;
|
||||
in vec3 inst_col;
|
||||
in float inst_wind_sway;
|
||||
|
||||
out vec3 f_pos;
|
||||
flat out vec3 f_norm;
|
||||
out vec3 f_col;
|
||||
out float f_light;
|
||||
|
||||
const float SCALE = 1.0 / 11.0;
|
||||
|
||||
void main() {
|
||||
mat4 inst_mat;
|
||||
inst_mat[0] = inst_mat0;
|
||||
inst_mat[1] = inst_mat1;
|
||||
inst_mat[2] = inst_mat2;
|
||||
inst_mat[3] = inst_mat3;
|
||||
|
||||
f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz;
|
||||
|
||||
// Wind waving
|
||||
f_pos += inst_wind_sway * vec3(
|
||||
sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
|
||||
sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
|
||||
0.0
|
||||
) * pow(v_pos.z * SCALE, 1.3) * 0.2;
|
||||
|
||||
f_norm = (inst_mat * vec4(v_norm, 0)).xyz;
|
||||
|
||||
f_col = v_col * inst_col;
|
||||
|
||||
f_light = 1.0;
|
||||
|
||||
gl_Position =
|
||||
proj_mat *
|
||||
view_mat *
|
||||
vec4(f_pos, 1);
|
||||
}
|
@ -22,7 +22,7 @@ void main() {
|
||||
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 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, true);
|
||||
vec3 color = mix(surf_color, fog_color, fog_level);
|
||||
|
||||
tgt_color = vec4(color, 1.0);
|
||||
|
BIN
assets/voxygen/voxel/sprite/cacti/barrel_cactus.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cacti/barrel_cactus.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/cacti/large_cactus.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/cacti/large_cactus.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_blue_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_blue_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_blue_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_blue_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_pink_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_pink_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_pink_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_pink_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_pink_3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_pink_3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_purple_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_purple_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_red_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_red_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_white_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_white_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/flower_yellow_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/flower_yellow_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/sunflower_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/sunflower_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/flowers/sunflower_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/flowers/sunflower_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/fruit/apple.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/fruit/apple.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/fruit/apple_half.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/fruit/apple_half.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_long_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_long_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_long_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_long_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_long_3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_long_3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_long_4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_long_4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_long_5.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_long_5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_med_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_med_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_med_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_med_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_med_3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_med_3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_med_4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_med_4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_med_5.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_med_5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_short_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_short_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_short_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_short_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_short_3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_short_3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_short_4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_short_4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/grass/grass_short_5.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/grass/grass_short_5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_10.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_10.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_2.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_3.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_4.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_5.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_6.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_6.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_7.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_7.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_8.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_8.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_9.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/velorite_small/velorite_9.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/tree/fruit/1.vox
(Stored with Git LFS)
BIN
assets/world/tree/fruit/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/fruit/2.vox
(Stored with Git LFS)
BIN
assets/world/tree/fruit/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/fruit/3.vox
(Stored with Git LFS)
BIN
assets/world/tree/fruit/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/fruit/4.vox
(Stored with Git LFS)
BIN
assets/world/tree/fruit/4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/fruit/5.vox
(Stored with Git LFS)
BIN
assets/world/tree/fruit/5.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/fruit/6.vox
(Stored with Git LFS)
BIN
assets/world/tree/fruit/6.vox
(Stored with Git LFS)
Binary file not shown.
@ -3,19 +3,45 @@ use serde_derive::{Deserialize, Serialize};
|
||||
use std::ops::Deref;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[repr(u8)]
|
||||
pub enum BlockKind {
|
||||
Air,
|
||||
Normal,
|
||||
Dense,
|
||||
Water,
|
||||
LargeCactus,
|
||||
BarrelCactus,
|
||||
BlueFlower,
|
||||
PinkFlower,
|
||||
PurpleFlower,
|
||||
RedFlower,
|
||||
WhiteFlower,
|
||||
YellowFlower,
|
||||
Sunflower,
|
||||
LongGrass,
|
||||
MediumGrass,
|
||||
ShortGrass,
|
||||
Apple,
|
||||
}
|
||||
|
||||
impl BlockKind {
|
||||
pub fn is_air(&self) -> bool {
|
||||
match self {
|
||||
BlockKind::Air => true,
|
||||
BlockKind::LargeCactus => false,
|
||||
BlockKind::BarrelCactus => true,
|
||||
BlockKind::BlueFlower => true,
|
||||
BlockKind::PinkFlower => true,
|
||||
BlockKind::PurpleFlower => true,
|
||||
BlockKind::RedFlower => true,
|
||||
BlockKind::WhiteFlower => true,
|
||||
BlockKind::YellowFlower => true,
|
||||
BlockKind::Sunflower => true,
|
||||
BlockKind::LongGrass => true,
|
||||
BlockKind::MediumGrass => true,
|
||||
BlockKind::ShortGrass => true,
|
||||
BlockKind::Apple => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -31,6 +57,19 @@ impl BlockKind {
|
||||
match self {
|
||||
BlockKind::Air => false,
|
||||
BlockKind::Water => false,
|
||||
BlockKind::LargeCactus => false,
|
||||
BlockKind::BarrelCactus => false,
|
||||
BlockKind::BlueFlower => false,
|
||||
BlockKind::PinkFlower => false,
|
||||
BlockKind::PurpleFlower => false,
|
||||
BlockKind::RedFlower => false,
|
||||
BlockKind::WhiteFlower => false,
|
||||
BlockKind::YellowFlower => false,
|
||||
BlockKind::Sunflower => false,
|
||||
BlockKind::LongGrass => false,
|
||||
BlockKind::MediumGrass => false,
|
||||
BlockKind::ShortGrass => false,
|
||||
BlockKind::Apple => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
@ -39,6 +78,19 @@ impl BlockKind {
|
||||
match self {
|
||||
BlockKind::Air => false,
|
||||
BlockKind::Water => false,
|
||||
BlockKind::LargeCactus => true,
|
||||
BlockKind::BarrelCactus => true,
|
||||
BlockKind::BlueFlower => false,
|
||||
BlockKind::PinkFlower => false,
|
||||
BlockKind::PurpleFlower => false,
|
||||
BlockKind::RedFlower => false,
|
||||
BlockKind::WhiteFlower => false,
|
||||
BlockKind::YellowFlower => false,
|
||||
BlockKind::Sunflower => false,
|
||||
BlockKind::LongGrass => false,
|
||||
BlockKind::MediumGrass => false,
|
||||
BlockKind::ShortGrass => false,
|
||||
BlockKind::Apple => true,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ mod vol;
|
||||
|
||||
use crate::render::{self, Mesh};
|
||||
|
||||
pub trait Meshable {
|
||||
pub trait Meshable<P: render::Pipeline, T: render::Pipeline> {
|
||||
type Pipeline: render::Pipeline;
|
||||
type TranslucentPipeline: render::Pipeline;
|
||||
type Supplement;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
mesh::{vol, Meshable},
|
||||
render::{self, FigurePipeline, Mesh},
|
||||
render::{self, FigurePipeline, Mesh, SpritePipeline},
|
||||
};
|
||||
use common::{
|
||||
figure::Segment,
|
||||
@ -10,8 +10,9 @@ use common::{
|
||||
use vek::*;
|
||||
|
||||
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
||||
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
|
||||
|
||||
impl Meshable for Segment {
|
||||
impl Meshable<FigurePipeline, FigurePipeline> for Segment {
|
||||
type Pipeline = FigurePipeline;
|
||||
type TranslucentPipeline = FigurePipeline;
|
||||
type Supplement = Vec3<f32>;
|
||||
@ -51,3 +52,43 @@ impl Meshable for Segment {
|
||||
(mesh, Mesh::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl Meshable<SpritePipeline, SpritePipeline> for Segment {
|
||||
type Pipeline = SpritePipeline;
|
||||
type TranslucentPipeline = SpritePipeline;
|
||||
type Supplement = Vec3<f32>;
|
||||
|
||||
fn generate_mesh(
|
||||
&self,
|
||||
offs: Self::Supplement,
|
||||
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
||||
let mut mesh = Mesh::new();
|
||||
|
||||
for pos in self.iter_positions() {
|
||||
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 + pos.map(|e| e as f32),
|
||||
col,
|
||||
|origin, norm, col, ao, light| {
|
||||
SpriteVertex::new(
|
||||
origin,
|
||||
norm,
|
||||
linear_to_srgb(srgb_to_linear(col) * ao * light),
|
||||
)
|
||||
},
|
||||
true,
|
||||
&[[[1.0; 3]; 3]; 3],
|
||||
|vox| vox.is_empty(),
|
||||
|vox| !vox.is_empty(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(mesh, Mesh::new())
|
||||
}
|
||||
}
|
||||
|
@ -14,15 +14,19 @@ type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
||||
type FluidVertex = <FluidPipeline as render::Pipeline>::Vertex;
|
||||
|
||||
fn block_shadow_density(kind: BlockKind) -> (f32, f32) {
|
||||
// (density, cap)
|
||||
match kind {
|
||||
BlockKind::Air => (0.0, 0.0),
|
||||
BlockKind::Normal => (0.085, 0.3),
|
||||
BlockKind::Dense => (0.3, 0.0),
|
||||
BlockKind::Water => (0.15, 0.0),
|
||||
kind if kind.is_air() => (0.0, 0.0),
|
||||
_ => (1.0, 0.0),
|
||||
}
|
||||
}
|
||||
|
||||
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<TerrainPipeline, FluidPipeline> for VolMap2d<V, S>
|
||||
{
|
||||
type Pipeline = TerrainPipeline;
|
||||
type TranslucentPipeline = FluidPipeline;
|
||||
type Supplement = Aabb<i32>;
|
||||
|
36
voxygen/src/render/instances.rs
Normal file
36
voxygen/src/render/instances.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use super::{gfx_backend, RenderError};
|
||||
use gfx::{
|
||||
self,
|
||||
buffer::Role,
|
||||
memory::{Bind, Usage},
|
||||
Factory,
|
||||
};
|
||||
|
||||
/// Represents a mesh that has been sent to the GPU.
|
||||
pub struct Instances<T: Copy + gfx::traits::Pod> {
|
||||
pub ibuf: gfx::handle::Buffer<gfx_backend::Resources, T>,
|
||||
}
|
||||
|
||||
impl<T: Copy + gfx::traits::Pod> Instances<T> {
|
||||
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Result<Self, RenderError> {
|
||||
Ok(Self {
|
||||
ibuf: factory
|
||||
.create_buffer(len, Role::Vertex, Usage::Dynamic, Bind::TRANSFER_DST)
|
||||
.map_err(|err| RenderError::BufferCreationError(err))?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
self.ibuf.len()
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||
instances: &[T],
|
||||
) -> Result<(), RenderError> {
|
||||
encoder
|
||||
.update_buffer(&self.ibuf, instances, 0)
|
||||
.map_err(|err| RenderError::UpdateError(err))
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub mod consts;
|
||||
pub mod instances;
|
||||
pub mod mesh;
|
||||
pub mod model;
|
||||
pub mod pipelines;
|
||||
@ -9,6 +10,7 @@ mod util;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
consts::Consts,
|
||||
instances::Instances,
|
||||
mesh::{Mesh, Quad, Tri},
|
||||
model::{DynamicModel, Model},
|
||||
pipelines::{
|
||||
@ -18,6 +20,7 @@ pub use self::{
|
||||
create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline,
|
||||
},
|
||||
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
|
||||
sprite::{Instance as SpriteInstance, SpritePipeline},
|
||||
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
||||
ui::{
|
||||
create_quad as create_ui_quad, create_tri as create_ui_tri, Locals as UiLocals,
|
||||
|
@ -10,22 +10,20 @@ use std::ops::Range;
|
||||
/// Represents a mesh that has been sent to the GPU.
|
||||
pub struct Model<P: Pipeline> {
|
||||
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
|
||||
pub slice: gfx::Slice<gfx_backend::Resources>,
|
||||
pub vertex_range: Range<u32>,
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Model<P> {
|
||||
pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh<P>) -> Self {
|
||||
Self {
|
||||
vbuf: factory.create_vertex_buffer(mesh.vertices()),
|
||||
slice: gfx::Slice {
|
||||
start: 0,
|
||||
end: mesh.vertices().len() as u32,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
vertex_range: 0..mesh.vertices().len() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vertex_range(&self) -> Range<u32> {
|
||||
self.vertex_range.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a mesh on the GPU which can be updated dynamically.
|
||||
@ -46,13 +44,7 @@ impl<P: Pipeline> DynamicModel<P> {
|
||||
pub fn submodel(&self, range: Range<usize>) -> Model<P> {
|
||||
Model {
|
||||
vbuf: self.vbuf.clone(),
|
||||
slice: gfx::Slice {
|
||||
start: range.start as u32,
|
||||
end: range.end as u32,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
vertex_range: range.start as u32..range.end as u32,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ pub mod figure;
|
||||
pub mod fluid;
|
||||
pub mod postprocess;
|
||||
pub mod skybox;
|
||||
pub mod sprite;
|
||||
pub mod terrain;
|
||||
pub mod ui;
|
||||
|
||||
|
79
voxygen/src/render/pipelines/sprite.rs
Normal file
79
voxygen/src/render/pipelines/sprite.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use super::{
|
||||
super::{util::arr_to_mat, Pipeline, 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 vek::*;
|
||||
|
||||
gfx_defines! {
|
||||
vertex Vertex {
|
||||
pos: [f32; 3] = "v_pos",
|
||||
norm: [f32; 3] = "v_norm",
|
||||
col: [f32; 3] = "v_col",
|
||||
}
|
||||
|
||||
vertex Instance {
|
||||
inst_mat0: [f32; 4] = "inst_mat0",
|
||||
inst_mat1: [f32; 4] = "inst_mat1",
|
||||
inst_mat2: [f32; 4] = "inst_mat2",
|
||||
inst_mat3: [f32; 4] = "inst_mat3",
|
||||
inst_col: [f32; 3] = "inst_col",
|
||||
inst_wind_sway: f32 = "inst_wind_sway",
|
||||
}
|
||||
|
||||
pipeline pipe {
|
||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||
ibuf: gfx::InstanceBuffer<Instance> = (),
|
||||
|
||||
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_WRITE,
|
||||
}
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>) -> Self {
|
||||
Self {
|
||||
pos: pos.into_array(),
|
||||
col: col.into_array(),
|
||||
norm: norm.into_array(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(mat: Mat4<f32>, col: Rgb<f32>, wind_sway: f32) -> Self {
|
||||
let mat_arr = arr_to_mat(mat.into_col_array());
|
||||
Self {
|
||||
inst_mat0: mat_arr[0],
|
||||
inst_mat1: mat_arr[1],
|
||||
inst_mat2: mat_arr[2],
|
||||
inst_mat3: mat_arr[3],
|
||||
inst_col: col.into_array(),
|
||||
inst_wind_sway: wind_sway,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Instance {
|
||||
fn default() -> Self {
|
||||
Self::new(Mat4::identity(), Rgb::broadcast(1.0), 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpritePipeline;
|
||||
|
||||
impl Pipeline for SpritePipeline {
|
||||
type Vertex = Vertex;
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
use super::{
|
||||
consts::Consts,
|
||||
gfx_backend,
|
||||
instances::Instances,
|
||||
mesh::Mesh,
|
||||
model::{DynamicModel, Model},
|
||||
pipelines::{figure, fluid, postprocess, skybox, terrain, ui, Globals, Light},
|
||||
pipelines::{figure, fluid, postprocess, skybox, sprite, terrain, ui, Globals, Light},
|
||||
texture::Texture,
|
||||
Pipeline, RenderError,
|
||||
};
|
||||
@ -65,6 +66,7 @@ pub struct Renderer {
|
||||
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
||||
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
|
||||
fluid_pipeline: GfxPipeline<fluid::pipe::Init<'static>>,
|
||||
sprite_pipeline: GfxPipeline<sprite::pipe::Init<'static>>,
|
||||
ui_pipeline: GfxPipeline<ui::pipe::Init<'static>>,
|
||||
postprocess_pipeline: GfxPipeline<postprocess::pipe::Init<'static>>,
|
||||
|
||||
@ -86,6 +88,7 @@ impl Renderer {
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
) = create_pipelines(&mut factory, &mut shader_reload_indicator)?;
|
||||
@ -114,6 +117,7 @@ impl Renderer {
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
|
||||
@ -201,6 +205,7 @@ impl Renderer {
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
)) => {
|
||||
@ -208,6 +213,7 @@ impl Renderer {
|
||||
self.figure_pipeline = figure_pipeline;
|
||||
self.terrain_pipeline = terrain_pipeline;
|
||||
self.fluid_pipeline = fluid_pipeline;
|
||||
self.sprite_pipeline = sprite_pipeline;
|
||||
self.ui_pipeline = ui_pipeline;
|
||||
self.postprocess_pipeline = postprocess_pipeline;
|
||||
}
|
||||
@ -238,6 +244,16 @@ impl Renderer {
|
||||
consts.update(&mut self.encoder, vals)
|
||||
}
|
||||
|
||||
/// Create a new set of instances with the provided values.
|
||||
pub fn create_instances<T: Copy + gfx::traits::Pod>(
|
||||
&mut self,
|
||||
vals: &[T],
|
||||
) -> Result<Instances<T>, RenderError> {
|
||||
let mut instances = Instances::new(&mut self.factory, vals.len())?;
|
||||
instances.update(&mut self.encoder, vals)?;
|
||||
Ok(instances)
|
||||
}
|
||||
|
||||
/// Create a new model from the provided mesh.
|
||||
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
||||
Ok(Model::new(&mut self.factory, mesh))
|
||||
@ -350,7 +366,13 @@ impl Renderer {
|
||||
locals: &Consts<skybox::Locals>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.skybox_pipeline.pso,
|
||||
&skybox::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
@ -372,7 +394,13 @@ impl Renderer {
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.figure_pipeline.pso,
|
||||
&figure::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
@ -395,7 +423,13 @@ impl Renderer {
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.terrain_pipeline.pso,
|
||||
&terrain::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
@ -417,7 +451,13 @@ impl Renderer {
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.fluid_pipeline.pso,
|
||||
&fluid::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
@ -430,6 +470,34 @@ impl Renderer {
|
||||
);
|
||||
}
|
||||
|
||||
/// Queue the rendering of the provided terrain chunk model in the upcoming frame.
|
||||
pub fn render_sprites(
|
||||
&mut self,
|
||||
model: &Model<sprite::SpritePipeline>,
|
||||
globals: &Consts<Globals>,
|
||||
instances: &Instances<sprite::Instance>,
|
||||
lights: &Consts<Light>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: Some((instances.count() as u32, 0)),
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.sprite_pipeline.pso,
|
||||
&sprite::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
ibuf: instances.ibuf.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.
|
||||
pub fn render_ui_element(
|
||||
&mut self,
|
||||
@ -441,7 +509,13 @@ impl Renderer {
|
||||
) {
|
||||
let Aabr { min, max } = scissor;
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.ui_pipeline.pso,
|
||||
&ui::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
@ -467,7 +541,13 @@ impl Renderer {
|
||||
locals: &Consts<postprocess::Locals>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&model.slice,
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: None,
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.postprocess_pipeline.pso,
|
||||
&postprocess::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
@ -495,6 +575,7 @@ fn create_pipelines(
|
||||
GfxPipeline<figure::pipe::Init<'static>>,
|
||||
GfxPipeline<terrain::pipe::Init<'static>>,
|
||||
GfxPipeline<fluid::pipe::Init<'static>>,
|
||||
GfxPipeline<sprite::pipe::Init<'static>>,
|
||||
GfxPipeline<ui::pipe::Init<'static>>,
|
||||
GfxPipeline<postprocess::pipe::Init<'static>>,
|
||||
),
|
||||
@ -571,6 +652,18 @@ fn create_pipelines(
|
||||
gfx::state::CullFace::Nothing,
|
||||
)?;
|
||||
|
||||
// Construct a pipeline for rendering sprites
|
||||
let sprite_pipeline = create_pipeline(
|
||||
factory,
|
||||
sprite::pipe::new(),
|
||||
&assets::load_watched::<String>("voxygen.shaders.sprite-vert", shader_reload_indicator)
|
||||
.unwrap(),
|
||||
&assets::load_watched::<String>("voxygen.shaders.sprite-frag", shader_reload_indicator)
|
||||
.unwrap(),
|
||||
&include_ctx,
|
||||
gfx::state::CullFace::Back,
|
||||
)?;
|
||||
|
||||
// Construct a pipeline for rendering UI elements
|
||||
let ui_pipeline = create_pipeline(
|
||||
factory,
|
||||
@ -606,6 +699,7 @@ fn create_pipelines(
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
))
|
||||
|
@ -163,9 +163,11 @@ impl FigureModelCache {
|
||||
// TODO: Don't make this public.
|
||||
pub fn load_mesh(mesh_name: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
|
||||
let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
|
||||
Segment::from(assets::load_expect::<DotVoxData>(full_specifier.as_str()).as_ref())
|
||||
.generate_mesh(position)
|
||||
.0
|
||||
Meshable::<FigurePipeline, FigurePipeline>::generate_mesh(
|
||||
&Segment::from(assets::load_expect::<DotVoxData>(full_specifier.as_str()).as_ref()),
|
||||
position,
|
||||
)
|
||||
.0
|
||||
}
|
||||
|
||||
fn load_head(race: humanoid::Race, body_type: humanoid::BodyType) -> Mesh<FigurePipeline> {
|
||||
|
@ -68,7 +68,7 @@ impl Scene {
|
||||
.create_consts(&[PostProcessLocals::default()])
|
||||
.unwrap(),
|
||||
},
|
||||
terrain: Terrain::new(),
|
||||
terrain: Terrain::new(renderer),
|
||||
loaded_distance: 0.0,
|
||||
figure_mgr: FigureMgr::new(),
|
||||
}
|
||||
@ -229,7 +229,12 @@ impl Scene {
|
||||
// Render terrain and figures.
|
||||
self.figure_mgr
|
||||
.render(renderer, client, &self.globals, &self.lights, &self.camera);
|
||||
self.terrain.render(renderer, &self.globals, &self.lights);
|
||||
self.terrain.render(
|
||||
renderer,
|
||||
&self.globals,
|
||||
&self.lights,
|
||||
self.camera.get_focus_pos(),
|
||||
);
|
||||
|
||||
renderer.render_post_process(
|
||||
&self.postprocess.model,
|
||||
|
@ -1,27 +1,32 @@
|
||||
use crate::{
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
Consts, FluidPipeline, Globals, Light, Mesh, Model, Renderer, TerrainLocals,
|
||||
TerrainPipeline,
|
||||
Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model, Renderer, SpriteInstance,
|
||||
SpritePipeline, TerrainLocals, TerrainPipeline,
|
||||
},
|
||||
};
|
||||
use client::Client;
|
||||
use common::{
|
||||
terrain::{TerrainChunkSize, TerrainMap},
|
||||
vol::{SampleVol, VolSize},
|
||||
assets,
|
||||
figure::Segment,
|
||||
terrain::{Block, BlockKind, TerrainChunkSize, TerrainMap},
|
||||
vol::{ReadVol, SampleVol, VolSize, Vox},
|
||||
volumes::vol_map_2d::VolMap2dErr,
|
||||
};
|
||||
use crossbeam::channel;
|
||||
use dot_vox::DotVoxData;
|
||||
use frustum_query::frustum::Frustum;
|
||||
use hashbrown::HashMap;
|
||||
use std::{i32, ops::Mul, time::Duration};
|
||||
use std::{f32, i32, ops::Mul, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
struct TerrainChunk {
|
||||
// GPU data
|
||||
opaque_model: Model<TerrainPipeline>,
|
||||
fluid_model: Model<FluidPipeline>,
|
||||
sprite_instances: HashMap<(BlockKind, usize), Instances<SpriteInstance>>,
|
||||
locals: Consts<TerrainLocals>,
|
||||
|
||||
visible: bool,
|
||||
z_bounds: (f32, f32),
|
||||
}
|
||||
@ -38,9 +43,72 @@ struct MeshWorkerResponse {
|
||||
z_bounds: (f32, f32),
|
||||
opaque_mesh: Mesh<TerrainPipeline>,
|
||||
fluid_mesh: Mesh<FluidPipeline>,
|
||||
sprite_instances: HashMap<(BlockKind, usize), Vec<SpriteInstance>>,
|
||||
started_tick: u64,
|
||||
}
|
||||
|
||||
struct SpriteConfig {
|
||||
variations: usize,
|
||||
wind_sway: f32, // 1.0 is normal
|
||||
}
|
||||
|
||||
fn sprite_config_for(kind: BlockKind) -> Option<SpriteConfig> {
|
||||
match kind {
|
||||
BlockKind::LargeCactus => Some(SpriteConfig {
|
||||
variations: 1,
|
||||
wind_sway: 0.0,
|
||||
}),
|
||||
BlockKind::BarrelCactus => Some(SpriteConfig {
|
||||
variations: 1,
|
||||
wind_sway: 0.0,
|
||||
}),
|
||||
|
||||
BlockKind::BlueFlower => Some(SpriteConfig {
|
||||
variations: 2,
|
||||
wind_sway: 0.3,
|
||||
}),
|
||||
BlockKind::PinkFlower => Some(SpriteConfig {
|
||||
variations: 3,
|
||||
wind_sway: 0.3,
|
||||
}),
|
||||
BlockKind::RedFlower => Some(SpriteConfig {
|
||||
variations: 1,
|
||||
wind_sway: 0.3,
|
||||
}),
|
||||
BlockKind::WhiteFlower => Some(SpriteConfig {
|
||||
variations: 1,
|
||||
wind_sway: 0.3,
|
||||
}),
|
||||
BlockKind::YellowFlower => Some(SpriteConfig {
|
||||
variations: 1,
|
||||
wind_sway: 0.3,
|
||||
}),
|
||||
BlockKind::Sunflower => Some(SpriteConfig {
|
||||
variations: 2,
|
||||
wind_sway: 0.3,
|
||||
}),
|
||||
|
||||
BlockKind::LongGrass => Some(SpriteConfig {
|
||||
variations: 5,
|
||||
wind_sway: 1.0,
|
||||
}),
|
||||
BlockKind::MediumGrass => Some(SpriteConfig {
|
||||
variations: 5,
|
||||
wind_sway: 1.0,
|
||||
}),
|
||||
BlockKind::ShortGrass => Some(SpriteConfig {
|
||||
variations: 5,
|
||||
wind_sway: 1.0,
|
||||
}),
|
||||
|
||||
BlockKind::Apple => Some(SpriteConfig {
|
||||
variations: 1,
|
||||
wind_sway: 0.0,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Function executed by worker threads dedicated to chunk meshing.
|
||||
fn mesh_worker(
|
||||
pos: Vec2<i32>,
|
||||
@ -55,6 +123,43 @@ fn mesh_worker(
|
||||
z_bounds,
|
||||
opaque_mesh,
|
||||
fluid_mesh,
|
||||
// Extract sprite locations from volume
|
||||
sprite_instances: {
|
||||
let mut instances = HashMap::new();
|
||||
|
||||
for x in 0..TerrainChunkSize::SIZE.x as i32 {
|
||||
for y in 0..TerrainChunkSize::SIZE.y as i32 {
|
||||
for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 {
|
||||
let wpos = Vec3::from(
|
||||
pos * Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as i32),
|
||||
) + Vec3::new(x, y, z);
|
||||
|
||||
let kind = volume.get(wpos).unwrap_or(&Block::empty()).kind();
|
||||
|
||||
if let Some(cfg) = sprite_config_for(kind) {
|
||||
let seed = wpos.x * 3 + wpos.y * 7 + wpos.z * 13 + wpos.x * wpos.y;
|
||||
|
||||
let instance = SpriteInstance::new(
|
||||
Mat4::identity()
|
||||
.rotated_z(f32::consts::PI * 0.5 * (seed % 4) as f32)
|
||||
.translated_3d(
|
||||
wpos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0),
|
||||
),
|
||||
Rgb::broadcast(1.0),
|
||||
cfg.wind_sway,
|
||||
);
|
||||
|
||||
instances
|
||||
.entry((kind, seed as usize % cfg.variations))
|
||||
.or_insert_with(|| Vec::new())
|
||||
.push(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instances
|
||||
},
|
||||
started_tick,
|
||||
}
|
||||
}
|
||||
@ -67,19 +172,158 @@ pub struct Terrain {
|
||||
mesh_send_tmp: channel::Sender<MeshWorkerResponse>,
|
||||
mesh_recv: channel::Receiver<MeshWorkerResponse>,
|
||||
mesh_todo: HashMap<Vec2<i32>, ChunkMeshState>,
|
||||
|
||||
// GPU data
|
||||
sprite_models: HashMap<(BlockKind, usize), Model<SpritePipeline>>,
|
||||
}
|
||||
|
||||
impl Terrain {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(renderer: &mut Renderer) -> Self {
|
||||
// Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating with
|
||||
// worker threads that are meshing chunks.
|
||||
let (send, recv) = channel::unbounded();
|
||||
|
||||
let mut make_model = |s| {
|
||||
renderer
|
||||
.create_model(
|
||||
&Meshable::<SpritePipeline, SpritePipeline>::generate_mesh(
|
||||
&Segment::from(assets::load_expect::<DotVoxData>(s).as_ref()),
|
||||
Vec3::new(-6.0, -6.0, 0.0),
|
||||
)
|
||||
.0,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
Self {
|
||||
chunks: HashMap::default(),
|
||||
mesh_send_tmp: send,
|
||||
mesh_recv: recv,
|
||||
mesh_todo: HashMap::default(),
|
||||
sprite_models: vec![
|
||||
// Cacti
|
||||
(
|
||||
(BlockKind::LargeCactus, 0),
|
||||
make_model("voxygen.voxel.sprite.cacti.large_cactus"),
|
||||
),
|
||||
(
|
||||
(BlockKind::BarrelCactus, 0),
|
||||
make_model("voxygen.voxel.sprite.cacti.barrel_cactus"),
|
||||
),
|
||||
// Fruit
|
||||
(
|
||||
(BlockKind::Apple, 0),
|
||||
make_model("voxygen.voxel.sprite.fruit.apple"),
|
||||
),
|
||||
// Flowers
|
||||
(
|
||||
(BlockKind::BlueFlower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_blue_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::BlueFlower, 1),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_blue_2"),
|
||||
),
|
||||
(
|
||||
(BlockKind::PinkFlower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_pink_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::PinkFlower, 1),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_pink_2"),
|
||||
),
|
||||
(
|
||||
(BlockKind::PinkFlower, 2),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_pink_3"),
|
||||
),
|
||||
(
|
||||
(BlockKind::PurpleFlower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_purple_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::RedFlower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_red_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::WhiteFlower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_white_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::YellowFlower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.flower_purple_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::Sunflower, 0),
|
||||
make_model("voxygen.voxel.sprite.flowers.sunflower_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::Sunflower, 1),
|
||||
make_model("voxygen.voxel.sprite.flowers.sunflower_2"),
|
||||
),
|
||||
// Grass
|
||||
(
|
||||
(BlockKind::LongGrass, 0),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_long_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::LongGrass, 1),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_long_2"),
|
||||
),
|
||||
(
|
||||
(BlockKind::LongGrass, 2),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_long_3"),
|
||||
),
|
||||
(
|
||||
(BlockKind::LongGrass, 3),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_long_4"),
|
||||
),
|
||||
(
|
||||
(BlockKind::LongGrass, 4),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_long_5"),
|
||||
),
|
||||
(
|
||||
(BlockKind::MediumGrass, 0),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_med_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::MediumGrass, 1),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_med_2"),
|
||||
),
|
||||
(
|
||||
(BlockKind::MediumGrass, 2),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_med_3"),
|
||||
),
|
||||
(
|
||||
(BlockKind::MediumGrass, 3),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_med_4"),
|
||||
),
|
||||
(
|
||||
(BlockKind::MediumGrass, 4),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_med_5"),
|
||||
),
|
||||
(
|
||||
(BlockKind::ShortGrass, 0),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_short_1"),
|
||||
),
|
||||
(
|
||||
(BlockKind::ShortGrass, 1),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_short_2"),
|
||||
),
|
||||
(
|
||||
(BlockKind::ShortGrass, 2),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_short_3"),
|
||||
),
|
||||
(
|
||||
(BlockKind::ShortGrass, 3),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_short_3"),
|
||||
),
|
||||
(
|
||||
(BlockKind::ShortGrass, 4),
|
||||
make_model("voxygen.voxel.sprite.grass.grass_short_5"),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,6 +519,18 @@ impl Terrain {
|
||||
fluid_model: renderer
|
||||
.create_model(&response.fluid_mesh)
|
||||
.expect("Failed to upload chunk mesh to the GPU!"),
|
||||
sprite_instances: response
|
||||
.sprite_instances
|
||||
.into_iter()
|
||||
.map(|(kind, instances)| {
|
||||
(
|
||||
kind,
|
||||
renderer.create_instances(&instances).expect(
|
||||
"Failed to upload chunk sprite instances to the GPU!",
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
locals: renderer
|
||||
.create_consts(&[TerrainLocals {
|
||||
model_offs: Vec3::from(
|
||||
@ -343,18 +599,37 @@ impl Terrain {
|
||||
renderer: &mut Renderer,
|
||||
globals: &Consts<Globals>,
|
||||
lights: &Consts<Light>,
|
||||
focus_pos: Vec3<f32>,
|
||||
) {
|
||||
// Opaque
|
||||
for (_pos, chunk) in &self.chunks {
|
||||
for (_, chunk) in &self.chunks {
|
||||
if chunk.visible {
|
||||
renderer.render_terrain_chunk(&chunk.opaque_model, globals, &chunk.locals, lights);
|
||||
}
|
||||
}
|
||||
|
||||
// Translucent
|
||||
for (_pos, chunk) in &self.chunks {
|
||||
for (pos, chunk) in &self.chunks {
|
||||
if chunk.visible {
|
||||
renderer.render_fluid_chunk(&chunk.fluid_model, globals, &chunk.locals, lights);
|
||||
|
||||
const SPRITE_RENDER_DISTANCE: f32 = 128.0;
|
||||
|
||||
let chunk_center = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
(e as f32 + 0.5) * sz as f32
|
||||
});
|
||||
if Vec2::from(focus_pos).distance_squared(chunk_center)
|
||||
< SPRITE_RENDER_DISTANCE * SPRITE_RENDER_DISTANCE
|
||||
{
|
||||
for (kind, instances) in &chunk.sprite_instances {
|
||||
renderer.render_sprites(
|
||||
&self.sprite_models[&kind],
|
||||
globals,
|
||||
&instances,
|
||||
lights,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,11 +148,13 @@ impl<'a> BlockGen<'a> {
|
||||
//close_structures,
|
||||
cave_xy,
|
||||
cave_alt,
|
||||
marble,
|
||||
marble_small,
|
||||
rock,
|
||||
//cliffs,
|
||||
cliff_hill,
|
||||
close_cliffs,
|
||||
//temp,
|
||||
temp,
|
||||
..
|
||||
} = &z_cache?.sample;
|
||||
|
||||
@ -254,6 +256,49 @@ impl<'a> BlockGen<'a> {
|
||||
BlockKind::Normal,
|
||||
saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8),
|
||||
))
|
||||
} else if (wposf.z as f32) < height + 0.9
|
||||
&& temp < CONFIG.desert_temp
|
||||
&& (wposf.z as f32 > water_height + 3.0)
|
||||
&& marble > 0.68
|
||||
&& marble_small > 0.65
|
||||
&& (marble * 3173.7).fract() < 0.5
|
||||
{
|
||||
let flowers = [
|
||||
BlockKind::BlueFlower,
|
||||
BlockKind::PinkFlower,
|
||||
BlockKind::PurpleFlower,
|
||||
BlockKind::RedFlower,
|
||||
BlockKind::WhiteFlower,
|
||||
BlockKind::YellowFlower,
|
||||
BlockKind::Sunflower,
|
||||
];
|
||||
|
||||
let grasses = [
|
||||
BlockKind::LongGrass,
|
||||
BlockKind::MediumGrass,
|
||||
BlockKind::ShortGrass,
|
||||
];
|
||||
|
||||
Some(Block::new(
|
||||
if (height * 1271.0).fract() < 0.15 {
|
||||
flowers[(height * 0.2) as usize % flowers.len()]
|
||||
} else {
|
||||
grasses[(height * 0.3) as usize % grasses.len()]
|
||||
},
|
||||
Rgb::broadcast(0),
|
||||
))
|
||||
} else if (wposf.z as f32) < height + 0.9
|
||||
&& temp > CONFIG.desert_temp
|
||||
&& (marble * 4423.5).fract() < 0.0005
|
||||
{
|
||||
Some(Block::new(
|
||||
if (height * 1271.0).fract() < 0.5 {
|
||||
BlockKind::LargeCactus
|
||||
} else {
|
||||
BlockKind::BarrelCactus
|
||||
},
|
||||
Rgb::broadcast(0),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -504,11 +549,7 @@ fn block_from_structure(
|
||||
)
|
||||
.map(|e| e as u8),
|
||||
)),
|
||||
StructureBlock::Fruit => Some(Block::new(
|
||||
BlockKind::Normal,
|
||||
Lerp::lerp(Rgb::new(237.0, 0.0, 0.0), Rgb::new(200.0, 237.0, 0.0), lerp)
|
||||
.map(|e| e as u8),
|
||||
)),
|
||||
StructureBlock::Fruit => Some(Block::new(BlockKind::Apple, Rgb::new(194, 30, 37))),
|
||||
StructureBlock::Hollow => Some(Block::empty()),
|
||||
StructureBlock::Normal(color) => {
|
||||
Some(Block::new(default_kind, color)).filter(|block| !block.is_empty())
|
||||
|
@ -366,11 +366,11 @@ lazy_static! {
|
||||
pub static ref FRUIT_TREES: Vec<Arc<Structure>> = vec![
|
||||
// fruit trees
|
||||
st_asset("world.tree.fruit.1", (5, 5, 7)),
|
||||
st_asset("world.tree.fruit.2", (5, 5, 7)),
|
||||
st_asset("world.tree.fruit.3", (5, 5, 7)),
|
||||
st_asset("world.tree.fruit.4", (5, 5, 7)),
|
||||
st_asset("world.tree.fruit.5", (5, 5, 7)),
|
||||
st_asset("world.tree.fruit.6", (5, 5, 7)),
|
||||
st_asset("world.tree.fruit.2", (6, 6, 7)),
|
||||
st_asset("world.tree.fruit.3", (6, 7, 7)),
|
||||
st_asset("world.tree.fruit.4", (3, 3, 7)),
|
||||
st_asset("world.tree.fruit.5", (6, 8, 7)),
|
||||
st_asset("world.tree.fruit.6", (7, 7, 7)),
|
||||
];
|
||||
|
||||
/*
|
||||
|
@ -359,6 +359,8 @@ impl<'a> Sampler for ColumnGen<'a> {
|
||||
close_structures: self.gen_close_structures(wpos),
|
||||
cave_xy,
|
||||
cave_alt,
|
||||
marble,
|
||||
marble_small,
|
||||
rock,
|
||||
is_cliffs,
|
||||
near_cliffs,
|
||||
@ -384,6 +386,8 @@ pub struct ColumnSample<'a> {
|
||||
pub close_structures: [Option<StructureData>; 9],
|
||||
pub cave_xy: f32,
|
||||
pub cave_alt: f32,
|
||||
pub marble: f32,
|
||||
pub marble_small: f32,
|
||||
pub rock: f32,
|
||||
pub is_cliffs: bool,
|
||||
pub near_cliffs: bool,
|
||||
|
Loading…
Reference in New Issue
Block a user