Skip to content

Commit 1208493

Browse files
Add ASCIITexture and ASCIIEffect (#688)
* created ASCIIEffect | created ASCIITexture | created demo * fix some types in ascii files * refactor ascii effect * Created ASCIITexture | Created ASCIIEffect | Created ascii demo in manual | Added unit test | #685 * fixed formatting, typos, errors and commented ASCIIEffect test * refactor ASCII demo settings and improve ASCIITexture constructor formatting * refactor ASCII demo rendering loop for improved readability
1 parent 3b2a8b1 commit 1208493

File tree

9 files changed

+561
-0
lines changed

9 files changed

+561
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import {
2+
CubeTextureLoader,
3+
LoadingManager,
4+
PerspectiveCamera,
5+
SRGBColorSpace,
6+
Scene,
7+
Texture,
8+
WebGLRenderer
9+
} from "three";
10+
11+
import {
12+
ClearPass,
13+
EffectPass,
14+
GeometryPass,
15+
MixBlendFunction,
16+
RenderPipeline,
17+
ToneMappingEffect,
18+
ASCIIEffect,
19+
ASCIITexture
20+
} from "postprocessing";
21+
22+
import { Pane } from "tweakpane";
23+
import { SpatialControls } from "spatial-controls";
24+
import * as DefaultEnvironment from "../objects/DefaultEnvironment.js";
25+
import * as Utils from "../utils/index.js";
26+
27+
function load(): Promise<Map<string, Texture>> {
28+
29+
const assets = new Map<string, Texture>();
30+
const loadingManager = new LoadingManager();
31+
const cubeTextureLoader = new CubeTextureLoader(loadingManager);
32+
33+
return new Promise<Map<string, Texture>>((resolve, reject) => {
34+
35+
loadingManager.onLoad = () => resolve(assets);
36+
loadingManager.onError = (url) => reject(new Error(`Failed to load ${url}`));
37+
38+
cubeTextureLoader.load(Utils.getSkyboxUrls("space", ".jpg"), (t) => {
39+
40+
t.colorSpace = SRGBColorSpace;
41+
assets.set("sky", t);
42+
43+
});
44+
45+
});
46+
47+
}
48+
49+
window.addEventListener("load", () => void load().then((assets) => {
50+
51+
// Renderer
52+
53+
const renderer = new WebGLRenderer({
54+
powerPreference: "high-performance",
55+
antialias: false,
56+
stencil: false,
57+
depth: false
58+
});
59+
60+
renderer.setPixelRatio(window.devicePixelRatio);
61+
renderer.debug.checkShaderErrors = Utils.isLocalhost;
62+
63+
// Camera & Controls
64+
65+
const camera = new PerspectiveCamera();
66+
const controls = new SpatialControls(camera.position, camera.quaternion, renderer.domElement);
67+
const settings = controls.settings;
68+
settings.rotation.sensitivity = 2.2;
69+
settings.rotation.damping = 0.05;
70+
settings.translation.damping = 0.1;
71+
controls.position.set(0, 1.5, 10);
72+
controls.lookAt(0, 1.35, 0);
73+
74+
// Scene, Lights, Objects
75+
76+
const scene = new Scene();
77+
const skyMap = assets.get("sky")!;
78+
scene.background = skyMap;
79+
scene.environment = skyMap;
80+
scene.fog = DefaultEnvironment.createFog();
81+
scene.add(DefaultEnvironment.createEnvironment());
82+
83+
// Post Processing
84+
85+
const effect = new ASCIIEffect({
86+
asciiTexture: new ASCIITexture({
87+
characters: " .:,'-^=*+?!|0#X%WM@",
88+
font: "Arial",
89+
fontSize: 35,
90+
size: 1024,
91+
cellCount: 16
92+
}),
93+
cellSize: 16,
94+
color: 0xffffff,
95+
inverted: false
96+
});
97+
effect.blendMode.blendFunction = new MixBlendFunction();
98+
99+
const pipeline = new RenderPipeline(renderer);
100+
pipeline.add(
101+
new ClearPass(),
102+
new GeometryPass(scene, camera, { samples: 4 }),
103+
new EffectPass(effect, new ToneMappingEffect())
104+
);
105+
106+
// Settings
107+
108+
const params = {
109+
useSceneColor: true
110+
};
111+
112+
const container = document.getElementById("viewport")!;
113+
const pane = new Pane({ container: container.querySelector<HTMLElement>(".tp")! });
114+
const fpsGraph = Utils.createFPSGraph(pane);
115+
116+
const folder = pane.addFolder({ title: "Settings" });
117+
folder.addBinding(effect, "inverted");
118+
folder.addBinding(effect, "cellSize", { min: 2, max: 24, step: 2 });
119+
folder.addBinding(effect, "color", { color: { type: "float" } });
120+
folder.addBinding(params, "useSceneColor").on("change",
121+
(e) => void (effect.color = e.value ? null : effect.color.getHex()));
122+
123+
Utils.addBlendModeBindings(folder, effect.blendMode);
124+
125+
// Resize Handler
126+
127+
function onResize(): void {
128+
129+
const width = container.clientWidth;
130+
const height = container.clientHeight;
131+
camera.aspect = width / height;
132+
camera.fov = Utils.calculateVerticalFoV(90, Math.max(camera.aspect, 16 / 9));
133+
camera.updateProjectionMatrix();
134+
pipeline.setSize(width, height);
135+
136+
}
137+
138+
window.addEventListener("resize", onResize);
139+
onResize();
140+
141+
// Render Loop
142+
143+
pipeline.compile().then(() => {
144+
145+
container.prepend(renderer.domElement);
146+
147+
renderer.setAnimationLoop((timestamp) => {
148+
149+
fpsGraph.begin();
150+
controls.update(timestamp);
151+
pipeline.render(timestamp);
152+
fpsGraph.end();
153+
154+
});
155+
156+
})
157+
.catch((e) => console.error(e));
158+
159+
})
160+
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
layout: single
3+
collection: sections
4+
title: ASCII
5+
draft: false
6+
menu:
7+
demos:
8+
parent: special-effects
9+
script: ascii
10+
---
11+
12+
# ASCII
13+
14+
### External Resources

0 commit comments

Comments
 (0)