fix palette
parent
264eab0308
commit
60ca4de7cf
|
@ -1,3 +1,6 @@
|
||||||
|
// https://github.com/Rudranil-Sarkar/Ordered-Dithering-Shader-GLSL/blob/master/Dither8x8.frag
|
||||||
|
// http://alex-charlton.com/posts/Dithering_on_the_GPU/
|
||||||
|
|
||||||
#import bevy_pbr::mesh_view_bindings
|
#import bevy_pbr::mesh_view_bindings
|
||||||
|
|
||||||
@group(1) @binding(0)
|
@group(1) @binding(0)
|
||||||
|
@ -10,15 +13,173 @@ var noise: texture_2d<f32>;
|
||||||
@group(1) @binding(3)
|
@group(1) @binding(3)
|
||||||
var noise_sampler: sampler;
|
var noise_sampler: sampler;
|
||||||
|
|
||||||
|
@group(1) @binding(4)
|
||||||
|
var<uniform> palette: array<vec3<f32>, 16>;
|
||||||
|
|
||||||
|
let dither_table = array<i32, 64>(
|
||||||
|
0, 48, 12, 60, 3, 51, 15, 63,
|
||||||
|
32, 16, 44, 28, 35, 19, 47, 31,
|
||||||
|
8, 56, 4, 52, 11, 59, 7, 55,
|
||||||
|
40, 24, 36, 20, 43, 27, 39, 23,
|
||||||
|
2, 50, 14, 62, 1, 49, 13, 61,
|
||||||
|
34, 18, 46, 30, 33, 17, 45, 29,
|
||||||
|
10, 58, 6, 54, 9, 57, 5, 53,
|
||||||
|
42, 26, 38, 22, 41, 25, 37, 21
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
fn hsl2rgb(c: vec3<f32>) -> vec3<f32> {
|
||||||
|
let rgb = clamp(
|
||||||
|
abs(
|
||||||
|
((c.x * 6.0 + vec3<f32>(0.0,4.0,2.0)) % 6.0)
|
||||||
|
- 3.0
|
||||||
|
) - 1.0,
|
||||||
|
vec3<f32>(0.0),
|
||||||
|
vec3<f32>(1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
return c.z + c.y * (rgb - .5) * (1. - abs(2. * c.z - 1.));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rgb2hsl(c: vec3<f32>) -> vec3<f32> {
|
||||||
|
var h = 0.;
|
||||||
|
var s = 0.;
|
||||||
|
var l = 0.;
|
||||||
|
var r = c.r;
|
||||||
|
var g = c.g;
|
||||||
|
var b = c.b;
|
||||||
|
var cMin = min(r, min(g, b));
|
||||||
|
var cMax = max(r, max(g, b));
|
||||||
|
|
||||||
|
l = (cMax + cMin) / 2.;
|
||||||
|
if (cMax > cMin) {
|
||||||
|
var cDelta = cMax - cMin;
|
||||||
|
|
||||||
|
if (l < 0.0) {
|
||||||
|
s = cDelta / (cMax+cMin);
|
||||||
|
} else {
|
||||||
|
s = cDelta / (2. - (cMax + cMin));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r == cMax) {
|
||||||
|
h = (g - b) / cDelta;
|
||||||
|
} else if (g == cMax) {
|
||||||
|
h = 2. + (b - r) / cDelta;
|
||||||
|
} else {
|
||||||
|
h = 4. + (r - g) / cDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h < 0.) {
|
||||||
|
h += 6.;
|
||||||
|
}
|
||||||
|
h = h / 6.;
|
||||||
|
}
|
||||||
|
return vec3<f32>(h, s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hueDistance(h1: f32, h2: f32) -> f32 {
|
||||||
|
let diff = abs(h1 - h2);
|
||||||
|
|
||||||
|
return min(abs(1. - diff), diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lightnessSteps: f32 = 4.;
|
||||||
|
|
||||||
|
// SOURCE: http://alex-charlton.com/posts/Dithering_on_the_GPU/
|
||||||
|
fn lightnessStep(l: f32) -> f32 {
|
||||||
|
return floor((.5 + l * lightnessSteps)) / lightnessSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
let SaturationSteps: f32 = 4.;
|
||||||
|
|
||||||
|
fn SaturationStep(s: f32) -> f32 {
|
||||||
|
/* Quantize the saturation to one of SaturationSteps values */
|
||||||
|
return floor((.5 + s * SaturationSteps)) / SaturationSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Closest_color(hue: f32) -> array<vec3<f32>, 2> {
|
||||||
|
var closest = vec3<f32>(-2., 0., 0.);
|
||||||
|
var secondClosest = vec3<f32>(-2., 0., 0.);
|
||||||
|
|
||||||
|
var temp: vec3<f32>;
|
||||||
|
|
||||||
|
var p: array<vec3<f32>, 16> = palette;
|
||||||
|
for(var i: i32 = 0; i < 16; i++) {
|
||||||
|
temp = p[i];
|
||||||
|
|
||||||
|
let tempDistance = hueDistance(temp.x, hue);
|
||||||
|
|
||||||
|
if(tempDistance < hueDistance(closest.x, hue)) {
|
||||||
|
secondClosest = closest;
|
||||||
|
closest = temp;
|
||||||
|
} else if(tempDistance < hueDistance(secondClosest.x, hue)){
|
||||||
|
secondClosest = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result: array<vec3<f32>, 2>;
|
||||||
|
result[0] = closest;
|
||||||
|
result[1] = secondClosest;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dither(pos: vec2<f32>, color: vec3<f32>) -> vec3<f32> {
|
||||||
|
let x = floor(pos.x % 8.);
|
||||||
|
let y = floor(pos.y % 8.);
|
||||||
|
|
||||||
|
let index = i32(x + y * 8.);
|
||||||
|
|
||||||
|
// This variable can be adjusted in range of -1 to 1 for more desirable result
|
||||||
|
let bias = 0.0;
|
||||||
|
|
||||||
|
var p: array<i32, 64> = dither_table;
|
||||||
|
let limit = (f32(p[index]) + 1.) / 64. + bias;
|
||||||
|
|
||||||
|
let Colors: array<vec3<f32>, 2> = Closest_color(color.x);
|
||||||
|
|
||||||
|
let hueDiff = hueDistance(color.x, Colors[0].x) / hueDistance(Colors[1].x, Colors[0].x);
|
||||||
|
|
||||||
|
let l1 = lightnessStep(max((color.z - .125), 0.));
|
||||||
|
let l2 = lightnessStep(min((color.z + .124), 1.));
|
||||||
|
let lightnessDiff = (color.z - l1) / (l2 - l1);
|
||||||
|
|
||||||
|
var resultColor: vec3<f32>;
|
||||||
|
if (hueDiff < limit) {
|
||||||
|
resultColor = Colors[0];
|
||||||
|
} else {
|
||||||
|
resultColor = Colors[1];
|
||||||
|
}
|
||||||
|
if (lightnessDiff < limit) {
|
||||||
|
resultColor.z = l1;
|
||||||
|
} else {
|
||||||
|
resultColor.z = l2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let s1 = SaturationStep(max((color.y - .125), 0.));
|
||||||
|
let s2 = SaturationStep(min((color.y + .124), 1.));
|
||||||
|
let SaturationDiff = (color.y - s1) / (s2 - s1);
|
||||||
|
|
||||||
|
if (SaturationDiff < limit) {
|
||||||
|
resultColor.y = s1;
|
||||||
|
} else {
|
||||||
|
resultColor.y = s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hsl2rgb(resultColor);
|
||||||
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fragment(
|
fn fragment(
|
||||||
@builtin(position) position: vec4<f32>,
|
@builtin(position) position: vec4<f32>,
|
||||||
#import bevy_sprite::mesh2d_vertex_output
|
#import bevy_sprite::mesh2d_vertex_output
|
||||||
) -> @location(0) vec4<f32> {
|
) -> @location(0) vec4<f32> {
|
||||||
let uv = position.xy / vec2<f32>(view.width, view.height);
|
let uv = position.xy / vec2<f32>(view.width, view.height);
|
||||||
let uv = floor(uv * 400.0) / 400.0;
|
// let uv = floor(uv * 400.0) / 400.0;
|
||||||
|
|
||||||
let col = textureSample(texture, our_sampler, uv);
|
let col = textureSample(texture, our_sampler, uv);
|
||||||
|
|
||||||
return round(col * 50.0) / 50.0;
|
return vec4<f32>(dither(position.xy / 2.0, rgb2hsl(col.rgb)), col.a);
|
||||||
|
|
||||||
|
// return round(col * 50.0) / 50.0;
|
||||||
|
// return col;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
cbd1be
|
||||||
|
8f9389
|
||||||
|
52534c
|
||||||
|
26201d
|
||||||
|
e0a46e
|
||||||
|
91a47a
|
||||||
|
5d7643
|
||||||
|
4d533a
|
||||||
|
a93130
|
||||||
|
7a1338
|
||||||
|
834664
|
||||||
|
917692
|
||||||
|
160712
|
||||||
|
593084
|
||||||
|
3870be
|
||||||
|
579fb4
|
|
@ -14,7 +14,7 @@ use bevy::{
|
||||||
};
|
};
|
||||||
use bevy_mod_raycast::{RayCastMethod, RayCastSource};
|
use bevy_mod_raycast::{RayCastMethod, RayCastSource};
|
||||||
|
|
||||||
use crate::{pillar::UnlitPillar, player::*};
|
use crate::{pillar::UnlitPillar, player::*, PALETTE};
|
||||||
|
|
||||||
pub struct MyRaycastSet;
|
pub struct MyRaycastSet;
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ pub fn spawn_camera(
|
||||||
let material_handle = post_processing_materials.add(PostProcessingMaterial {
|
let material_handle = post_processing_materials.add(PostProcessingMaterial {
|
||||||
source_image: image_handle,
|
source_image: image_handle,
|
||||||
noise,
|
noise,
|
||||||
|
palette: PALETTE,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Post processing 2d quad, with material using the render texture done by the main camera, with a custom shader.
|
// Post processing 2d quad, with material using the render texture done by the main camera, with a custom shader.
|
||||||
|
@ -125,6 +126,8 @@ pub struct PostProcessingMaterial {
|
||||||
#[texture(2)]
|
#[texture(2)]
|
||||||
#[sampler(3)]
|
#[sampler(3)]
|
||||||
noise: Handle<Image>,
|
noise: Handle<Image>,
|
||||||
|
#[uniform(4)]
|
||||||
|
palette: [Vec3; 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material2d for PostProcessingMaterial {
|
impl Material2d for PostProcessingMaterial {
|
||||||
|
|
31
src/main.rs
31
src/main.rs
|
@ -1,6 +1,8 @@
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
use bevy::{pbr::AmbientLight, prelude::*, sprite::Material2dPlugin, window::close_on_esc};
|
use bevy::{
|
||||||
|
math::vec3, pbr::AmbientLight, prelude::*, sprite::Material2dPlugin, window::close_on_esc,
|
||||||
|
};
|
||||||
use bevy_mod_raycast::{DefaultRaycastingPlugin, RayCastMesh, RaycastSystem};
|
use bevy_mod_raycast::{DefaultRaycastingPlugin, RayCastMesh, RaycastSystem};
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
|
@ -24,6 +26,33 @@ pub enum AppState {
|
||||||
Game,
|
Game,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// color palette in hsl
|
||||||
|
/// from https://lospec.com/palette-list/urbex-16
|
||||||
|
pub const PALETTE: [Vec3; 16] = [
|
||||||
|
vec3(0.2193, 0.1712, 0.7824),
|
||||||
|
vec3(0.2333, 0.0442, 0.5569),
|
||||||
|
vec3(0.1905, 0.0440, 0.3118),
|
||||||
|
vec3(0.0556, 0.1343, 0.1314),
|
||||||
|
vec3(0.0789, 0.6477, 0.6549),
|
||||||
|
vec3(0.2421, 0.1875, 0.5608),
|
||||||
|
vec3(0.2484, 0.2757, 0.3627),
|
||||||
|
vec3(0.2067, 0.1773, 0.2765),
|
||||||
|
vec3(0.0014, 0.5576, 0.4255),
|
||||||
|
vec3(0.9401, 0.7305, 0.2765),
|
||||||
|
vec3(0.9180, 0.3035, 0.3941),
|
||||||
|
vec3(0.8274, 0.1138, 0.5176),
|
||||||
|
vec3(0.8778, 0.5172, 0.0569),
|
||||||
|
vec3(0.7480, 0.4667, 0.3529),
|
||||||
|
vec3(0.5970, 0.5447, 0.4824),
|
||||||
|
vec3(0.5376, 0.3827, 0.523),
|
||||||
|
];
|
||||||
|
pub const PALETTE_HEX: [&str; 16] = [
|
||||||
|
"cbd1be", "8f9389", "52534c", "26201d", "e0a46e", "91a47a", "5d7643", "4d533a", "a93130",
|
||||||
|
"7a1338", "834664", "917692", "160712", "593084", "3870be", "579fb4",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const LIGHT_FRIEND_COLOR_INDICES: [usize; 6] = [0, 4, 7, 8, 11, 14];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(Msaa { samples: 1 })
|
.insert_resource(Msaa { samples: 1 })
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use bevy::{prelude::*, render::view::NoFrustumCulling};
|
use bevy::{prelude::*, render::view::NoFrustumCulling};
|
||||||
|
|
||||||
use crate::{camera::MouseCoords, illumination::Illumination, pillar::PillarActivationProgress};
|
use crate::{
|
||||||
|
camera::MouseCoords, illumination::Illumination, pillar::PillarActivationProgress,
|
||||||
|
LIGHT_FRIEND_COLOR_INDICES, PALETTE_HEX,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Player;
|
pub struct Player;
|
||||||
|
@ -47,11 +50,25 @@ pub fn spawn_player(
|
||||||
.with_children(|children| {
|
.with_children(|children| {
|
||||||
let count = 6;
|
let count = 6;
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let color = Color::hsl(360.0 * i as f32 / count as f32, 0.5, 0.5);
|
// let color = Color::hsl(360.0 * i as f32 / count as f32, 0.5, 0.5);
|
||||||
|
let color = PALETTE_HEX[LIGHT_FRIEND_COLOR_INDICES[i]];
|
||||||
|
|
||||||
|
let color = Color::hex(color).unwrap();
|
||||||
|
|
||||||
|
// let c = color.as_rgba_f32();
|
||||||
|
// println!(
|
||||||
|
// "\x1b[38;2;{};{};{}2m {} {} {} \x1b[m",
|
||||||
|
// (c[0] * 255.0) as u8,
|
||||||
|
// (c[1] * 255.0) as u8,
|
||||||
|
// (c[2] * 255.0) as u8,
|
||||||
|
// (c[0] * 255.0) as u8,
|
||||||
|
// (c[1] * 255.0) as u8,
|
||||||
|
// (c[2] * 255.0) as u8,
|
||||||
|
// );
|
||||||
|
|
||||||
let mut light_material: StandardMaterial = color.into();
|
let mut light_material: StandardMaterial = color.into();
|
||||||
light_material.metallic = 0.5;
|
light_material.metallic = 0.0;
|
||||||
light_material.reflectance = 0.5;
|
light_material.reflectance = 0.0;
|
||||||
light_material.emissive = color.as_rgba() * 10.0;
|
light_material.emissive = color.as_rgba() * 10.0;
|
||||||
let light_material = materials.add(light_material);
|
let light_material = materials.add(light_material);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue