mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Temporary noise solution
This commit is contained in:
parent
67683f315f
commit
273c5ed2f0
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6635,6 +6635,7 @@ dependencies = [
|
|||||||
"humantime",
|
"humantime",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"noise",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"portpicker",
|
"portpicker",
|
||||||
"prometheus",
|
"prometheus",
|
||||||
|
@ -102,7 +102,7 @@ void main() {
|
|||||||
#ifdef EXPERIMENTAL_RAIN
|
#ifdef EXPERIMENTAL_RAIN
|
||||||
vec3 old_color = color.rgb;
|
vec3 old_color = color.rgb;
|
||||||
|
|
||||||
float fall_rate = 20.0;
|
float fall_rate = 40.0;
|
||||||
|
|
||||||
dir.xy += wind_vel * dir.z / fall_rate;
|
dir.xy += wind_vel * dir.z / fall_rate;
|
||||||
dir = normalize(dir);
|
dir = normalize(dir);
|
||||||
@ -126,7 +126,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float drop_density = 3;
|
float drop_density = 3;
|
||||||
vec2 drop_size = vec2(0.0025, 0.17);
|
vec2 drop_size = vec2(0.0015, 0.17);
|
||||||
|
|
||||||
vec2 rain_pos = (view_pos * rain_dist);
|
vec2 rain_pos = (view_pos * rain_dist);
|
||||||
rain_pos += vec2(0, tick.x * fall_rate + cam_wpos.z);
|
rain_pos += vec2(0, tick.x * fall_rate + cam_wpos.z);
|
||||||
|
@ -61,13 +61,16 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission, out float not_underground
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float cloud_alt = CLOUD_AVG_ALT + alt * 0.5;
|
||||||
|
|
||||||
//vec2 cloud_attr = get_cloud_heights(wind_pos.xy);
|
//vec2 cloud_attr = get_cloud_heights(wind_pos.xy);
|
||||||
float sun_access = 0.0;
|
float sun_access = 0.0;
|
||||||
float moon_access = 0.0;
|
float moon_access = 0.0;
|
||||||
float cloud_sun_access = 0.0;
|
float cloud_sun_access = clamp((pos.z - cloud_alt) / 1500 + 0.5, 0, 1);
|
||||||
float cloud_moon_access = 0.0;
|
float cloud_moon_access = 0.0;
|
||||||
float cloud_broad_a = 0.0;
|
float cloud_broad_a = 0.0;
|
||||||
float cloud_broad_b = 0.0;
|
float cloud_broad_b = 0.0;
|
||||||
|
|
||||||
// This is a silly optimisation but it actually nets us a fair few fps by skipping quite a few expensive calcs
|
// This is a silly optimisation but it actually nets us a fair few fps by skipping quite a few expensive calcs
|
||||||
if ((pos.z < CLOUD_AVG_ALT + 15000.0 && cloud_tendency > 0.0)) {
|
if ((pos.z < CLOUD_AVG_ALT + 15000.0 && cloud_tendency > 0.0)) {
|
||||||
// Turbulence (small variations in clouds/mist)
|
// Turbulence (small variations in clouds/mist)
|
||||||
@ -78,11 +81,10 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission, out float not_underground
|
|||||||
const float CLOUD_DENSITY = 10000.0;
|
const float CLOUD_DENSITY = 10000.0;
|
||||||
const float CLOUD_ALT_VARI_WIDTH = 100000.0;
|
const float CLOUD_ALT_VARI_WIDTH = 100000.0;
|
||||||
const float CLOUD_ALT_VARI_SCALE = 5000.0;
|
const float CLOUD_ALT_VARI_SCALE = 5000.0;
|
||||||
float cloud_alt = CLOUD_AVG_ALT + alt * 0.5;
|
|
||||||
|
|
||||||
cloud_broad_a = cloud_broad(wind_pos + sun_dir.xyz * 250);
|
cloud_broad_a = cloud_broad(wind_pos + sun_dir.xyz * 250);
|
||||||
cloud_broad_b = cloud_broad(wind_pos - sun_dir.xyz * 250);
|
cloud_broad_b = cloud_broad(wind_pos - sun_dir.xyz * 250);
|
||||||
cloud = cloud_tendency + (0.0
|
cloud = cloud_tendency + cloud_tendency * (0.0
|
||||||
+ 24 * (cloud_broad_a + cloud_broad_b) * 0.5
|
+ 24 * (cloud_broad_a + cloud_broad_b) * 0.5
|
||||||
#if (CLOUD_MODE >= CLOUD_MODE_MINIMAL)
|
#if (CLOUD_MODE >= CLOUD_MODE_MINIMAL)
|
||||||
+ 4 * (noise_3d((wind_pos + turb_offset) / 2000.0 / cloud_scale) - 0.5)
|
+ 4 * (noise_3d((wind_pos + turb_offset) / 2000.0 / cloud_scale) - 0.5)
|
||||||
@ -93,24 +95,30 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission, out float not_underground
|
|||||||
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
||||||
+ 0.75 * (noise_3d(wind_pos / 500.0 / cloud_scale) - 0.5)
|
+ 0.75 * (noise_3d(wind_pos / 500.0 / cloud_scale) - 0.5)
|
||||||
#endif
|
#endif
|
||||||
) * 0.01;
|
) * 0.1;
|
||||||
cloud = pow(max(cloud, 0), 3) * sign(cloud);
|
cloud = pow(max(cloud, 0), 3) * sign(cloud);
|
||||||
cloud *= CLOUD_DENSITY * sqrt(cloud_tendency) * falloff(abs(pos.z - cloud_alt) / CLOUD_DEPTH);
|
cloud *= CLOUD_DENSITY * sqrt(cloud_tendency + 0.001) * falloff(abs(pos.z - cloud_alt) / CLOUD_DEPTH);
|
||||||
|
|
||||||
// What proportion of sunlight is *not* being blocked by nearby cloud? (approximation)
|
// What proportion of sunlight is *not* being blocked by nearby cloud? (approximation)
|
||||||
// Basically, just throw together a few values that roughly approximate this term and come up with an average
|
// Basically, just throw together a few values that roughly approximate this term and come up with an average
|
||||||
cloud_sun_access = exp((
|
cloud_sun_access = mix(cloud_sun_access, exp((
|
||||||
// Cloud density gradient
|
// Cloud density gradient
|
||||||
0.25 * (cloud_broad_a - cloud_broad_b + (0.25 * (noise_3d(wind_pos / 4000 / cloud_scale) - 0.5) + 0.1 * (noise_3d(wind_pos / 1000 / cloud_scale) - 0.5)))
|
0.25 * (cloud_broad_a - cloud_broad_b + (0.25 * (noise_3d(wind_pos / 4000 / cloud_scale) - 0.5) + 0.1 * (noise_3d(wind_pos / 1000 / cloud_scale) - 0.5)))
|
||||||
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
||||||
// More noise
|
// More noise
|
||||||
+ 0.01 * (noise_3d(wind_pos / 500) / cloud_scale - 0.5)
|
+ 0.01 * (noise_3d(wind_pos / 500) / cloud_scale - 0.5)
|
||||||
#endif
|
#endif
|
||||||
) * 15.0 - 1.5) * 1.5;
|
) * 15.0 - 1.5) * 1.5, min(cloud_tendency * 10, 1));
|
||||||
// Since we're assuming the sun/moon is always above (not always correct) it's the same for the moon
|
// Since we're assuming the sun/moon is always above (not always correct) it's the same for the moon
|
||||||
cloud_moon_access = 1.0 - cloud_sun_access;
|
cloud_moon_access = 1.0 - cloud_sun_access;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (CLOUD_MODE >= CLOUD_MODE_LOW)
|
||||||
|
cloud += max(noise_3d((wind_pos) / 25000.0 / cloud_scale) - 0.75 + noise_3d((wind_pos) / 2500.0 / cloud_scale) * 0.1, 0)
|
||||||
|
* 0.1
|
||||||
|
/ (abs(pos.z - cloud_alt) / 500.0 + 0.1);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Keeping this because it's something I'm likely to reenable later
|
// Keeping this because it's something I'm likely to reenable later
|
||||||
/*
|
/*
|
||||||
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
||||||
@ -238,10 +246,12 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
|||||||
float min_dist = clamp(max_dist / 4, 0.25, 24);
|
float min_dist = clamp(max_dist / 4, 0.25, 24);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// TODO: Make it a double rainbow
|
#if (CLOUD_MODE >= CLOUD_MODE_MEDIUM)
|
||||||
float rainbow_t = (0.7 - dot(sun_dir.xyz, dir)) * 8 / 0.05;
|
// TODO: Make it a double rainbow
|
||||||
int rainbow_c = int(floor(rainbow_t));
|
float rainbow_t = (0.7 - dot(sun_dir.xyz, dir)) * 8 / 0.05;
|
||||||
rainbow_t = fract(rainbow_t);
|
int rainbow_c = int(floor(rainbow_t));
|
||||||
|
rainbow_t = fract(rainbow_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; cdist > min_dist && i < 250; i ++) {
|
for (i = 0; cdist > min_dist && i < 250; i ++) {
|
||||||
ldist = cdist;
|
ldist = cdist;
|
||||||
@ -276,21 +286,27 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
|||||||
emission * density_integrals.y * step;
|
emission * density_integrals.y * step;
|
||||||
|
|
||||||
// Rainbow
|
// Rainbow
|
||||||
if (rainbow_c >= 0 && rainbow_c < 8) {
|
#if (CLOUD_MODE >= CLOUD_MODE_MEDIUM)
|
||||||
float rain = rain_density_at(pos.xy);
|
if (rainbow_c >= 0 && rainbow_c < 8) {
|
||||||
vec3 colors[9] = {
|
float rain = rain_density_at(pos.xy);
|
||||||
surf_color,
|
vec3 colors[9] = {
|
||||||
vec3(0.9, 0.5, 0.9),
|
surf_color,
|
||||||
vec3(0.25, 0.0, 0.5),
|
vec3(0.9, 0.5, 0.9),
|
||||||
vec3(0.0, 0.0, 1.0),
|
vec3(0.25, 0.0, 0.5),
|
||||||
vec3(0.0, 0.5, 0.0),
|
vec3(0.0, 0.0, 1.0),
|
||||||
vec3(1.0, 1.0, 0.0),
|
vec3(0.0, 0.5, 0.0),
|
||||||
vec3(1.0, 0.6, 0.0),
|
vec3(1.0, 1.0, 0.0),
|
||||||
vec3(1.0, 0.0, 0.0),
|
vec3(1.0, 0.6, 0.0),
|
||||||
surf_color,
|
vec3(1.0, 0.0, 0.0),
|
||||||
};
|
surf_color,
|
||||||
surf_color = mix(surf_color, mix(colors[rainbow_c], colors[rainbow_c + 1], rainbow_t), rain * sun_access * sun_access * get_sun_brightness() * pow(min(cdist / 500.0, 1.0), 2.0));
|
};
|
||||||
}
|
surf_color = mix(
|
||||||
|
surf_color,
|
||||||
|
mix(colors[rainbow_c], colors[rainbow_c + 1], rainbow_t),
|
||||||
|
rain * sun_access * sun_access * get_sun_brightness() * pow(min(cdist / 500.0, 1.0), 2.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef IS_POSTPROCESS
|
#ifdef IS_POSTPROCESS
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ authc = { git = "https://gitlab.com/veloren/auth.git", rev = "fb3dcbc4962b367253
|
|||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
rand_distr = "0.4.0"
|
rand_distr = "0.4.0"
|
||||||
enumset = "1.0.8"
|
enumset = "1.0.8"
|
||||||
|
noise = { version = "0.7", default-features = false }
|
||||||
|
|
||||||
rusqlite = { version = "0.24.2", features = ["array", "vtab", "bundled", "trace"] }
|
rusqlite = { version = "0.24.2", features = ["array", "vtab", "bundled", "trace"] }
|
||||||
refinery = { git = "https://gitlab.com/veloren/refinery.git", rev = "8ecf4b4772d791e6c8c0a3f9b66a7530fad1af3e", features = ["rusqlite"] }
|
refinery = { git = "https://gitlab.com/veloren/refinery.git", rev = "8ecf4b4772d791e6c8c0a3f9b66a7530fad1af3e", features = ["rusqlite"] }
|
||||||
|
@ -6,6 +6,7 @@ use common::{
|
|||||||
weather::{Weather, CHUNKS_PER_CELL},
|
weather::{Weather, CHUNKS_PER_CELL},
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use noise::{NoiseFn, SuperSimplex, Turbulence};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use world::World;
|
use world::World;
|
||||||
|
|
||||||
@ -46,10 +47,13 @@ pub struct WeatherSim {
|
|||||||
info: Grid<WeatherInfo>,
|
info: Grid<WeatherInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const WATER_BOILING_POINT: f32 = 2.5;
|
/*
|
||||||
const MAX_WIND_SPEED: f32 = 128.0;
|
const MAX_WIND_SPEED: f32 = 128.0;
|
||||||
pub(crate) const CELL_SIZE: f32 = (CHUNKS_PER_CELL * TerrainChunkSize::RECT_SIZE.x) as f32;
|
*/
|
||||||
pub(crate) const DT: f32 = CELL_SIZE / MAX_WIND_SPEED;
|
pub(crate) const CELL_SIZE: u32 = CHUNKS_PER_CELL * TerrainChunkSize::RECT_SIZE.x;
|
||||||
|
|
||||||
|
/// How often the weather is updated, in seconds
|
||||||
|
pub(crate) const DT: f32 = 5.0; // CELL_SIZE as f32 / MAX_WIND_SPEED;
|
||||||
|
|
||||||
fn sample_plane_normal(points: &[Vec3<f32>]) -> Option<Vec3<f32>> {
|
fn sample_plane_normal(points: &[Vec3<f32>]) -> Option<Vec3<f32>> {
|
||||||
if points.len() < 3 {
|
if points.len() < 3 {
|
||||||
@ -88,6 +92,8 @@ fn sample_plane_normal(points: &[Vec3<f32>]) -> Option<Vec3<f32>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cell_to_wpos(p: Vec2<i32>) -> Vec2<i32> { p * CELL_SIZE as i32 }
|
||||||
|
|
||||||
impl WeatherSim {
|
impl WeatherSim {
|
||||||
pub fn new(size: Vec2<u32>, world: &World) -> Self {
|
pub fn new(size: Vec2<u32>, world: &World) -> Self {
|
||||||
let size = size.as_();
|
let size = size.as_();
|
||||||
@ -146,14 +152,44 @@ impl WeatherSim {
|
|||||||
|
|
||||||
pub fn get_weather(&self) -> &Grid<Weather> { &self.weather }
|
pub fn get_weather(&self) -> &Grid<Weather> { &self.weather }
|
||||||
|
|
||||||
|
/*
|
||||||
fn get_cell(&self, p: Vec2<i32>, time: f64) -> Cell {
|
fn get_cell(&self, p: Vec2<i32>, time: f64) -> Cell {
|
||||||
*self.cells.get(p).unwrap_or(&sample_cell(p, time))
|
*self.cells.get(p).unwrap_or(&sample_cell(p, time))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// https://minds.wisconsin.edu/bitstream/handle/1793/66950/LitzauSpr2013.pdf
|
// https://minds.wisconsin.edu/bitstream/handle/1793/66950/LitzauSpr2013.pdf
|
||||||
// Time step is cell size / maximum wind speed
|
// Time step is cell size / maximum wind speed
|
||||||
pub fn tick(&mut self, time_of_day: &TimeOfDay) {
|
pub fn tick(&mut self, time_of_day: &TimeOfDay) {
|
||||||
let time = time_of_day.0;
|
let time = time_of_day.0;
|
||||||
|
|
||||||
|
let base_nz = Turbulence::new(
|
||||||
|
Turbulence::new(SuperSimplex::new())
|
||||||
|
.set_frequency(0.2)
|
||||||
|
.set_power(1.5),
|
||||||
|
)
|
||||||
|
.set_frequency(2.0)
|
||||||
|
.set_power(0.2);
|
||||||
|
|
||||||
|
let rain_nz = SuperSimplex::new();
|
||||||
|
|
||||||
|
for (point, cell) in self.weather.iter_mut() {
|
||||||
|
let wpos = cell_to_wpos(point);
|
||||||
|
|
||||||
|
let space_scale = 7500.0;
|
||||||
|
let time_scale = 25000.0;
|
||||||
|
let spos = (wpos.as_::<f64>() / space_scale).with_z(time as f64 / time_scale);
|
||||||
|
|
||||||
|
let pressure = (base_nz.get(spos.into_array()) * 0.5 + 1.0).clamped(0.0, 1.0) as f32;
|
||||||
|
|
||||||
|
cell.cloud = 1.0 - pressure;
|
||||||
|
cell.rain = (1.0 - pressure - 0.2).max(0.0).powf(1.5);
|
||||||
|
cell.wind = Vec2::new(
|
||||||
|
rain_nz.get(spos.into_array()) as f32,
|
||||||
|
rain_nz.get((spos + 1.0).into_array()) as f32,
|
||||||
|
) * 250.0 * (1.0 - pressure);
|
||||||
|
}
|
||||||
|
/*
|
||||||
let mut swap = Grid::new(self.cells.size(), Cell::default());
|
let mut swap = Grid::new(self.cells.size(), Cell::default());
|
||||||
// Dissipate wind, humidty and pressure
|
// Dissipate wind, humidty and pressure
|
||||||
// Dissipation is represented by the target cell expanding into the 8 adjacent
|
// Dissipation is represented by the target cell expanding into the 8 adjacent
|
||||||
@ -349,8 +385,6 @@ impl WeatherSim {
|
|||||||
* (self.weather[point].rain * 0.9 + 0.1)
|
* (self.weather[point].rain * 0.9 + 0.1)
|
||||||
* temp_part;
|
* temp_part;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Maybe moisture condenses to clouds, which if they have a certain
|
|
||||||
// amount they will release rain.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,9 +152,9 @@ impl LodData {
|
|||||||
|
|
||||||
let sampler_info = wgpu::SamplerDescriptor {
|
let sampler_info = wgpu::SamplerDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
address_mode_u: wgpu::AddressMode::ClampToBorder,
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
address_mode_v: wgpu::AddressMode::ClampToBorder,
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
address_mode_w: wgpu::AddressMode::ClampToBorder,
|
||||||
mag_filter: wgpu::FilterMode::Linear,
|
mag_filter: wgpu::FilterMode::Linear,
|
||||||
min_filter: wgpu::FilterMode::Linear,
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use noise::{Seedable, SuperSimplex};
|
use noise::{NoiseFn, Seedable, SuperSimplex, Turbulence};
|
||||||
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -8,32 +8,40 @@ const H: usize = 640;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let mut win = minifb::Window::new("Turb", W, H, minifb::WindowOptions::default()).unwrap();
|
let mut win = minifb::Window::new("Turb", W, H, minifb::WindowOptions::default()).unwrap();
|
||||||
|
|
||||||
|
let nz = Turbulence::new(
|
||||||
|
Turbulence::new(SuperSimplex::new())
|
||||||
|
.set_frequency(0.2)
|
||||||
|
.set_power(1.5),
|
||||||
|
)
|
||||||
|
.set_frequency(2.0)
|
||||||
|
.set_power(0.2);
|
||||||
|
|
||||||
let _nz_x = SuperSimplex::new().set_seed(0);
|
let _nz_x = SuperSimplex::new().set_seed(0);
|
||||||
let _nz_y = SuperSimplex::new().set_seed(1);
|
let _nz_y = SuperSimplex::new().set_seed(1);
|
||||||
|
|
||||||
let mut _time = 0.0f64;
|
let mut _time = 0.0f64;
|
||||||
|
|
||||||
|
let mut scale = 50.0;
|
||||||
|
|
||||||
while win.is_open() {
|
while win.is_open() {
|
||||||
let mut buf = vec![0; W * H];
|
let mut buf = vec![0; W * H];
|
||||||
|
|
||||||
for i in 0..W {
|
for i in 0..W {
|
||||||
for j in 0..H {
|
for j in 0..H {
|
||||||
let pos = Vec2::new(i as f64 / W as f64, j as f64 / H as f64) * 0.5 - 0.25;
|
let pos = Vec2::new(i as f64, j as f64) / scale;
|
||||||
|
|
||||||
let pos = pos * 10.0;
|
let val = nz.get(pos.into_array());
|
||||||
|
|
||||||
let pos = (0..10).fold(pos, |pos, _| pos.map(|e| e.powi(3) - 1.0));
|
|
||||||
|
|
||||||
let val = if pos.map(|e| e.abs() < 0.5).reduce_and() {
|
|
||||||
1.0f32
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
|
|
||||||
buf[j * W + i] = u32::from_le_bytes([(val.max(0.0).min(1.0) * 255.0) as u8; 4]);
|
buf[j * W + i] = u32::from_le_bytes([(val.max(0.0).min(1.0) * 255.0) as u8; 4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if win.is_key_pressed(minifb::Key::Right, minifb::KeyRepeat::No) {
|
||||||
|
scale *= 1.5;
|
||||||
|
} else if win.is_key_pressed(minifb::Key::Left, minifb::KeyRepeat::No) {
|
||||||
|
scale /= 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
win.update_with_buffer(&buf, W, H).unwrap();
|
win.update_with_buffer(&buf, W, H).unwrap();
|
||||||
|
|
||||||
_time += 1.0 / 60.0;
|
_time += 1.0 / 60.0;
|
||||||
|
Loading…
Reference in New Issue
Block a user