A public/fiery-dreams-1x.png => public/fiery-dreams-1x.png +0 -0
M src/blobs/Cube.js => src/blobs/Cube.js +4 -7
@@ 3,6 3,7 @@ import {
Color,
Mesh,
MeshBasicMaterial,
+ MeshLambertMaterial,
MeshNormalMaterial,
} from "three";
import { Blob } from "./blob";
@@ 54,12 55,8 @@ export function ThrowingCube(position) {
const cube = new Cube(
position,
new BoxGeometry(0.1, 0.1, 0.1),
- new MeshBasicMaterial({
- color: new Color(
- Math.random() * 1.0,
- Math.random() * 1.0,
- Math.random() * 1.0,
- ),
+ new MeshLambertMaterial({
+ color: new Color(0.2, 0.2, 0.2),
}),
);
@@ 76,7 73,7 @@ export function BasicSpinningCube(position) {
const cube = new Cube(
position,
new BoxGeometry(0.2, 0.2, 0.2),
- new MeshNormalMaterial(),
+ new MeshLambertMaterial({ color: new Color(0.2, 0.2, 0.2) }),
);
cube.OnTick = (_) => {
M src/blobs/EmptyCube.js => src/blobs/EmptyCube.js +2 -2
@@ 1,4 1,4 @@
-import { Color, Mesh, MeshBasicMaterial } from "three";
+import { Color, Mesh, MeshBasicMaterial, MeshLambertMaterial } from "three";
import { Blob } from "./blob";
import { ColliderDesc, RigidBodyDesc, TriMeshFlags } from "@dimforge/rapier3d";
@@ 20,7 20,7 @@ export class EmptyCube extends Blob {
this.mesh = new Mesh(
mesh.geometry,
- new MeshBasicMaterial({ color: new Color(0, 0, 0) }),
+ new MeshLambertMaterial({ color: new Color(0.1, 0.1, 0.1) }),
);
this.mesh.position.set(
M src/engine/engine.js => src/engine/engine.js +117 -2
@@ 1,6 1,7 @@
import { RawIntegrationParameters } from "@dimforge/rapier3d/rapier_wasm3d";
import {
BoxGeometry,
+ Color,
// BufferAttribute,
// BufferGeometry,
Euler,
@@ 8,6 9,7 @@ import {
Mesh,
MeshNormalMaterial,
Quaternion,
+ ShaderMaterial,
Vector3,
WebGLRenderer,
} from "three";
@@ 17,6 19,7 @@ import { RenderPixelatedPass } from "three/addons/postprocessing/RenderPixelated
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { ColliderDesc, World } from "@dimforge/rapier3d";
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
+import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
// import { LineBasicNodeMaterial } from "three/examples/jsm/nodes/Nodes.js";
export class Engine {
@@ 63,8 66,8 @@ export class Engine {
this.renderer = new WebGLRenderer({
powerPreference: "high-performance",
antialias: false,
- stencil: false,
- depth: false,
+ // stencil: false,
+ // depth: false,
});
this.renderer.setSize(this.width, this.height);
@@ 75,6 78,14 @@ export class Engine {
this.renderPass.depthEdgeStrength = 0.1;
this.renderPass.normalEdgeStrength = 0.1;
+ this.loadPaletteShader(
+ // "https://i.postimg.cc/7hSv4jBg/dynasty38-1x.png",
+ "./fiery-dreams-1x.png",
+ (shaderPass) => {
+ this.composer.addPass(shaderPass);
+ },
+ );
+
this.composer.addPass(this.renderPass);
// this.outputPass = new OutputPass();
@@ 124,6 135,110 @@ export class Engine {
});
}
+ // Using code from: https://nas.sr/text/yesterdays-pixels-today/
+ paletteShader(palette) {
+ console.log(palette.length);
+ return new ShaderMaterial({
+ uniforms: {
+ tDiffuse: { value: null },
+ palette: { value: palette },
+ threshold: { value: 0.1 },
+ },
+ vertexShader: [
+ "out vec2 vUv;",
+ "void main() {",
+ "vUv = uv;",
+ "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
+ "}",
+ ].join("\n"),
+ fragmentShader: [
+ "uniform vec3 palette[" + palette.length + "];",
+ "uniform sampler2D tDiffuse;",
+ "uniform float threshold;",
+ "in vec2 vUv;",
+ "void main() {",
+ "vec3 color = texture2D(tDiffuse, vUv).rgb;",
+ "float total = gl_FragCoord.x + gl_FragCoord.y;",
+ "bool isEven = mod(total, 2.0)==0.0;",
+ "float closestDistance = 1.0;",
+ "vec3 closestColor = palette[0];",
+ "int firstIndex = 0;",
+ "int secondIndex = 0;",
+ "float secondClosestDistance = 1.0;",
+ "vec3 secondClosestColor = palette[0];",
+ /*
+ * loop through the palette colors and compute the two closest colors
+ * to the input pixel color
+ */
+ "for(int i=0;i<" + palette.length + "; i++) {",
+ "float d = distance(color, palette[i]);",
+ "if(d <= closestDistance) {",
+ "secondIndex = firstIndex;",
+ "secondClosestDistance = closestDistance;",
+ "secondClosestColor = closestColor;",
+ "firstIndex = i;",
+ "closestDistance = d;",
+ "closestColor = palette[i];",
+ "} else if (d <= secondClosestDistance) {",
+ "secondIndex = i;",
+ "secondClosestDistance = d;",
+ "secondClosestColor = palette[i];",
+ "}",
+ "}",
+ /*
+ * if the two closest colors are within the threshold of each other
+ * preform a dither
+ */
+ "if(distance(closestDistance, secondClosestDistance) < threshold) {",
+ "vec3 a = firstIndex < secondIndex ? closestColor : secondClosestColor;",
+ "vec3 b = firstIndex < secondIndex ? secondClosestColor : closestColor;",
+ "gl_FragColor = vec4(isEven ? a : b, 1.0);",
+ /* otherwise use the closest color */
+ "} else {",
+ "gl_FragColor = vec4(closestColor, 1.0);",
+ "}",
+ "}",
+ ].join("\n"),
+ });
+ }
+
+ imageData(img) {
+ const canvas = document.createElement("canvas");
+ const context = canvas.getContext("2d");
+ canvas.width = img.naturalWidth;
+ canvas.height = img.naturalHeight;
+ context.drawImage(img, 0, 0);
+
+ return context.getImageData(0, 0, img.naturalWidth, img.naturalHeight);
+ }
+
+ palette(img) {
+ const palette = [];
+ const pixels = this.imageData(img);
+
+ for (let i = 0; i < pixels.data.length; i += 4) {
+ palette.push(
+ new Color(
+ pixels.data[i] / 256.0,
+ pixels.data[i + 1] / 256.0,
+ pixels.data[i + 2] / 256.0,
+ ),
+ );
+ }
+
+ return palette;
+ }
+
+ loadPaletteShader(url, cb) {
+ const image = new Image();
+ image.crossOrigin = "Anonymous";
+ image.src = url;
+ image.addEventListener("load", () => {
+ const pass = new ShaderPass(this.paletteShader(this.palette(image)));
+ cb(pass);
+ });
+ }
+
/** @param {PerspectiveCamera} camera **/
SetCamera(camera) {
this.camera = camera;
M src/playground.js => src/playground.js +32 -2
@@ 1,7 1,19 @@
import { Engine } from "./engine/engine";
-import { ThrowingCube } from "./blobs/Cube";
+import { Cube, ThrowingCube } from "./blobs/Cube";
import { SpinningEmptyCube } from "./blobs/EmptyCube";
-import { Color, PerspectiveCamera, Scene, Vector3 } from "three";
+import {
+ AmbientLight,
+ BoxGeometry,
+ Color,
+ DirectionalLight,
+ HemisphereLight,
+ MeshNormalMaterial,
+ PerspectiveCamera,
+ PointLight,
+ Scene,
+ SpotLight,
+ Vector3,
+} from "three";
import { BlackBar } from "./static/bar";
const engine = new Engine(window.innerWidth, window.innerHeight);
@@ 17,6 29,24 @@ engine.SetCamera(
);
engine.camera.position.z = 1;
+const directionalLight = new DirectionalLight(0xffffff, 1.0);
+directionalLight.position.z += 1;
+home.add(directionalLight);
+
+const pointLight = new PointLight(0xffffff, 10.0, 0, 1.0);
+home.add(pointLight);
+//
+// const lightCube = new Cube(
+// pointLight.position,
+// new BoxGeometry(0.1, 0.1, 0.1),
+// new MeshNormalMaterial(),
+// );
+//
+// home.add(lightCube.mesh);
+
+// const light = new AmbientLight(0x404040, 10);
+// home.add(light);
+
engine.RenderFrame();
SpinningEmptyCube(