Fixed uniform alignment & starfield flicker
parent
cd6537f971
commit
67f10c940a
|
@ -11,23 +11,33 @@ pub struct GlobalData {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Debug, Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
// Uniforms require uniform alignment.
|
||||||
|
// Since the largest value in this array is a [f32; 2],
|
||||||
|
// all smaller values must be padded.
|
||||||
|
// also, [f32; 3] are aligned as [f32; 4]
|
||||||
|
// (since alignments must be powers of two)
|
||||||
pub struct GlobalDataContent {
|
pub struct GlobalDataContent {
|
||||||
/// Camera position, in game units
|
/// Camera position, in game units
|
||||||
pub camera_position: [f32; 2],
|
pub camera_position: [f32; 2],
|
||||||
|
|
||||||
/// Camera zoom value, in game units
|
/// Camera zoom value, in game units.
|
||||||
pub camera_zoom: f32,
|
/// Only first component has meaning.
|
||||||
|
pub camera_zoom: [f32; 2],
|
||||||
|
|
||||||
/// Aspect ratio of window (width / height)
|
/// Size ratio of window, in physical pixels
|
||||||
pub window_aspect: f32,
|
pub window_size: [f32; 2],
|
||||||
|
|
||||||
|
// Aspect ration of window
|
||||||
|
/// Only first component has meaning.
|
||||||
|
pub window_aspect: [f32; 2],
|
||||||
|
|
||||||
/// Texture index of starfield sprites
|
/// Texture index of starfield sprites
|
||||||
pub starfield_texture: u32,
|
/// Only first component has meaning.
|
||||||
|
pub starfield_texture: [u32; 2],
|
||||||
|
|
||||||
// Size of (square) starfield tile, in game units
|
// Size of (square) starfield tiles, in game units
|
||||||
pub starfield_tile_size: f32,
|
/// Only first component has meaning.
|
||||||
|
pub starfield_tile_size: [f32; 2],
|
||||||
pub padding: [f32; 3],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalDataContent {
|
impl GlobalDataContent {
|
||||||
|
|
|
@ -362,11 +362,14 @@ impl GPUState {
|
||||||
0,
|
0,
|
||||||
bytemuck::cast_slice(&[GlobalDataContent {
|
bytemuck::cast_slice(&[GlobalDataContent {
|
||||||
camera_position: game.camera.pos.into(),
|
camera_position: game.camera.pos.into(),
|
||||||
camera_zoom: game.camera.zoom,
|
camera_zoom: [game.camera.zoom, 0.0],
|
||||||
window_aspect: self.window_aspect,
|
window_size: [
|
||||||
starfield_texture: 1,
|
self.window_size.width as f32,
|
||||||
starfield_tile_size: STARFIELD_SIZE as f32,
|
self.window_size.height as f32,
|
||||||
padding: Default::default(),
|
],
|
||||||
|
window_aspect: [self.window_aspect, 0.0],
|
||||||
|
starfield_texture: [1, 0],
|
||||||
|
starfield_tile_size: [STARFIELD_SIZE as f32, 0.0],
|
||||||
}]),
|
}]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,11 @@ struct VertexOutput {
|
||||||
var<uniform> global: GlobalUniform;
|
var<uniform> global: GlobalUniform;
|
||||||
struct GlobalUniform {
|
struct GlobalUniform {
|
||||||
camera_position: vec2<f32>,
|
camera_position: vec2<f32>,
|
||||||
camera_zoom: f32,
|
camera_zoom: vec2<f32>,
|
||||||
window_aspect: f32,
|
window_size: vec2<f32>,
|
||||||
starfield_texture: u32,
|
window_aspect: vec2<f32>,
|
||||||
starfield_tile_size: f32
|
starfield_texture: vec2<u32>,
|
||||||
|
starfield_tile_size: vec2<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ fn vertex_shader_main(
|
||||||
|
|
||||||
// Apply sprite aspect ratio & scale factor
|
// Apply sprite aspect ratio & scale factor
|
||||||
// This must be done *before* rotation.
|
// This must be done *before* rotation.
|
||||||
let scale = instance.height / global.camera_zoom;
|
let scale = instance.height / global.camera_zoom.x;
|
||||||
var pos: vec2<f32> = vec2<f32>(
|
var pos: vec2<f32> = vec2<f32>(
|
||||||
vertex.position.x * instance.aspect * scale,
|
vertex.position.x * instance.aspect * scale,
|
||||||
vertex.position.y * scale
|
vertex.position.y * scale
|
||||||
|
@ -53,13 +54,13 @@ fn vertex_shader_main(
|
||||||
|
|
||||||
// Apply screen aspect ratio, again preserving height.
|
// Apply screen aspect ratio, again preserving height.
|
||||||
// This must be done AFTER rotation... think about it!
|
// This must be done AFTER rotation... think about it!
|
||||||
pos = pos / vec2<f32>(global.window_aspect, 1.0);
|
pos = pos / vec2<f32>(global.window_aspect.x, 1.0);
|
||||||
|
|
||||||
// Translate
|
// Translate
|
||||||
pos = pos + (
|
pos = pos + (
|
||||||
// Don't forget to correct distance for screen aspect ratio too!
|
// Don't forget to correct distance for screen aspect ratio too!
|
||||||
(instance.position / global.camera_zoom)
|
(instance.position / global.camera_zoom.x)
|
||||||
/ vec2<f32>(global.window_aspect, 1.0)
|
/ vec2<f32>(global.window_aspect.x, 1.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
|
|
|
@ -19,10 +19,11 @@ struct VertexOutput {
|
||||||
var<uniform> global: GlobalUniform;
|
var<uniform> global: GlobalUniform;
|
||||||
struct GlobalUniform {
|
struct GlobalUniform {
|
||||||
camera_position: vec2<f32>,
|
camera_position: vec2<f32>,
|
||||||
camera_zoom: f32,
|
camera_zoom: vec2<f32>,
|
||||||
window_aspect: f32,
|
window_size: vec2<f32>,
|
||||||
starfield_texture: u32,
|
window_aspect: vec2<f32>,
|
||||||
starfield_tile_size: f32
|
starfield_texture: vec2<u32>,
|
||||||
|
starfield_tile_size: vec2<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,33 +40,41 @@ fn vertex_shader_main(
|
||||||
// Center of the tile the camera is currently in, in game coordinates.
|
// Center of the tile the camera is currently in, in game coordinates.
|
||||||
// x div y = x - (x mod y)
|
// x div y = x - (x mod y)
|
||||||
let tile_center = (
|
let tile_center = (
|
||||||
global.camera_position
|
global.camera_position.xy
|
||||||
- (
|
- (
|
||||||
fmod(
|
fmod(
|
||||||
global.camera_position + global.starfield_tile_size / 2.0,
|
global.camera_position.xy + global.starfield_tile_size.x / 2.0,
|
||||||
global.starfield_tile_size
|
global.starfield_tile_size.x
|
||||||
) - global.starfield_tile_size / 2.0
|
) - global.starfield_tile_size.x / 2.0
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Apply sprite aspect ratio & scale factor
|
// Apply sprite aspect ratio & scale factor
|
||||||
// also applies screen aspect ratio
|
// also applies screen aspect ratio
|
||||||
let scale = instance.height / global.camera_zoom;
|
var scale: f32 = instance.height / global.camera_zoom.x;
|
||||||
|
|
||||||
|
// Minimum scale to prevent flicker at large zoom levels
|
||||||
|
var real_size = scale * global.window_size.xy;
|
||||||
|
if (real_size.x < 2.0 || real_size.y < 2.0) {
|
||||||
|
scale = 2.0 / min(global.window_size.x, global.window_size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var pos: vec2<f32> = vec2<f32>(
|
var pos: vec2<f32> = vec2<f32>(
|
||||||
vertex.position.x * scale / global.window_aspect,
|
vertex.position.x * scale / global.window_aspect.x,
|
||||||
vertex.position.y * scale
|
vertex.position.y * scale
|
||||||
);
|
);
|
||||||
|
|
||||||
// World position relative to camera
|
// World position relative to camera
|
||||||
// (Note that instance position is in a different
|
// (Note that instance position is in a different
|
||||||
// coordinate system than usual)
|
// coordinate system than usual)
|
||||||
let camera_pos = (instance.position + tile_center) - global.camera_position;
|
let camera_pos = (instance.position + tile_center) - global.camera_position.xy;
|
||||||
|
|
||||||
// Translate
|
// Translate
|
||||||
pos = pos + (
|
pos = pos + (
|
||||||
// Don't forget to correct distance for screen aspect ratio too!
|
// Don't forget to correct distance for screen aspect ratio too!
|
||||||
(camera_pos / (global.camera_zoom * (instance.parallax)))
|
(camera_pos / (global.camera_zoom.x * (instance.parallax)))
|
||||||
/ vec2<f32>(global.window_aspect, 1.0)
|
/ vec2<f32>(global.window_aspect.x, 1.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
|
@ -84,8 +93,8 @@ var sampler_array: binding_array<sampler>;
|
||||||
@fragment
|
@fragment
|
||||||
fn fragment_shader_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
fn fragment_shader_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
return textureSampleLevel(
|
return textureSampleLevel(
|
||||||
texture_array[1],
|
texture_array[global.starfield_texture.x],
|
||||||
sampler_array[1],
|
sampler_array[global.starfield_texture.x],
|
||||||
in.texture_coords,
|
in.texture_coords,
|
||||||
0.0
|
0.0
|
||||||
).rgba * vec4<f32>(0.5, 0.5, 0.5, 1.0);
|
).rgba * vec4<f32>(0.5, 0.5, 0.5, 1.0);
|
||||||
|
|
Loading…
Reference in New Issue