Skip to content

Commit c219424

Browse files
committed
Load assets from url, add textures pane
1 parent f2f6ec0 commit c219424

File tree

6 files changed

+146
-136
lines changed

6 files changed

+146
-136
lines changed

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@
1111
"format": "prettier --write ."
1212
},
1313
"dependencies": {
14-
"byte-base64": "^1.1.0",
1514
"gl-matrix": "^3.3.0",
1615
"regl": "^2.1.0",
17-
"resl": "^1.0.3",
1816
"tweakpane": "^2.2.1"
1917
},
2018
"devDependencies": {

src/index.js

Lines changed: 134 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,99 +2,155 @@ import Regl from "regl";
22
import { mat4 } from "gl-matrix";
33
import Tweakpane from "tweakpane";
44

5+
import { loadMesh } from "./geometry";
6+
import { generatePencilTextures } from "./texture";
7+
import { saveImage, loadImage } from "./utils";
58
import fragmentShader from "./frag.glsl?raw";
69
import vertexShader from "./vert.glsl?raw";
7-
import rawTexture from "../textures/texture_256_64_64.json";
8-
import bunny from "../models/bunny_1k_2_sub.json";
9-
import { loadMesh } from "./geometry";
10-
import {
11-
TextureData,
12-
displayImageData,
13-
generatePencilTextures,
14-
} from "./texture";
15-
16-
const pane = new Tweakpane({ title: "Parameters" });
17-
const params = {
18-
scale: 15,
19-
zoom: 0.5,
20-
height: 0.2,
21-
rotate: true,
22-
speed: 0.5,
23-
angle: 0,
24-
};
25-
pane.addInput(params, "scale", { min: 0, max: 50 });
26-
pane.addInput(params, "zoom", { min: -5, max: 5 });
27-
pane.addInput(params, "height", { min: -1, max: 1 });
28-
pane.addSeparator();
29-
pane.addInput(params, "rotate");
30-
pane.addInput(params, "speed", { min: -1.0, max: 1.0 });
31-
pane.addInput(params, "angle", { min: 0, max: 2 * Math.PI });
10+
import pencilTexturesUrl from "../textures/texture_256_64_64.png";
11+
import bunnyUrl from "../models/bunny_1k_2_sub.json?url";
3212

3313
const regl = Regl({ extensions: ["OES_standard_derivatives"] });
3414

35-
const width = rawTexture.width;
36-
const height = rawTexture.height;
37-
const numTextures = rawTexture.numTextures;
38-
//const texture = generatePencilTextures(numTextures, width, height);
39-
//console.log(JSON.stringify(texture));
40-
const texture = new TextureData(rawTexture.data, width, height, numTextures);
41-
//displayImageData(texture);
42-
43-
const pencilTextures = regl.texture({
44-
data: texture.data,
45-
width: width,
46-
height: height * numTextures,
47-
mag: "linear",
48-
min: "mipmap",
49-
mipmap: true,
50-
});
15+
class Renderer {
16+
async start() {
17+
this.initPane();
18+
await Promise.all([this.initTextures(), this.loadMesh(bunnyUrl)]);
19+
20+
regl.frame(() => {
21+
if (this.params.rotate) {
22+
this.params.angle =
23+
(this.params.angle + this.params.speed / 100.0) % (2 * Math.PI);
24+
this.pane.refresh();
25+
}
26+
const t = this.params.angle;
27+
const radius = Math.pow(2, -this.params.zoom);
28+
const height = this.params.height;
29+
30+
regl.clear({ color: [1, 1, 1, 1] });
31+
this.draw({
32+
eye: [radius * Math.cos(t), height, radius * Math.sin(t)],
33+
center: [0, height, 0],
34+
});
35+
});
36+
}
37+
38+
initPane() {
39+
const pane = new Tweakpane({ title: "Parameters" });
40+
const params = {
41+
scale: 15,
42+
zoom: 0.8,
43+
height: 0.2,
44+
rotate: true,
45+
speed: 0.5,
46+
angle: 0,
47+
};
48+
49+
pane.addInput(params, "scale", { min: 0, max: 50 });
50+
51+
const camera = pane.addFolder({ title: "Camera" });
52+
camera.addInput(params, "zoom", { min: -5, max: 5 });
53+
camera.addInput(params, "height", { min: -1, max: 1 });
54+
camera.addSeparator();
55+
camera.addInput(params, "rotate");
56+
camera.addInput(params, "speed", { min: -1.0, max: 1.0 });
57+
camera.addInput(params, "angle", { min: 0, max: 2 * Math.PI });
58+
59+
const textures = pane.addFolder({ title: "Textures" });
60+
const texParams = {
61+
number: 64,
62+
width: 64,
63+
height: 64,
64+
save: false,
65+
};
66+
textures.addInput(texParams, "number", { min: 8, max: 256, step: 8 });
67+
textures.addInput(texParams, "width", { min: 16, max: 128, step: 8 });
68+
textures.addInput(texParams, "height", { min: 16, max: 128, step: 8 });
69+
textures.addInput(texParams, "save");
70+
textures.addButton({ title: "Generate" }).on("click", () => {
71+
this.generateTextures(texParams);
72+
});
73+
74+
this.pane = pane;
75+
this.params = params;
76+
}
5177

52-
const { elements, attributes } = loadMesh(bunny);
78+
async initTextures() {
79+
const textures = regl.texture({
80+
data: await loadImage(pencilTexturesUrl),
81+
mag: "linear",
82+
min: "mipmap",
83+
mipmap: true,
84+
});
85+
this.setTextures(256, textures);
86+
}
87+
88+
setTextures(numTextures, pencilTextures) {
89+
this.numTextures = numTextures;
90+
this.pencilTextures = pencilTextures;
91+
}
92+
93+
generateTextures(texParams) {
94+
const img = generatePencilTextures(
95+
texParams.number,
96+
texParams.width,
97+
texParams.height
98+
);
99+
const textures = regl.texture({
100+
data: img.data,
101+
width: texParams.width,
102+
height: texParams.height * texParams.number,
103+
mag: "linear",
104+
min: "mipmap",
105+
mipmap: true,
106+
});
107+
if (texParams.save) {
108+
saveImage("textures.png", img);
109+
}
110+
this.setTextures(texParams.number, textures);
111+
}
112+
113+
async loadMesh(url) {
114+
const resp = await fetch(url);
115+
const mesh = await resp.json();
116+
const { attributes, elements } = loadMesh(mesh);
117+
this.attributes = attributes;
118+
this.elements = elements;
119+
}
120+
}
53121

54-
const draw = regl({
122+
Renderer.prototype.draw = regl({
55123
frag: fragmentShader,
56124
vert: vertexShader,
57-
attributes,
58-
elements,
125+
attributes: {
126+
position: regl.this("attributes.position"),
127+
normal: regl.this("attributes.normal"),
128+
indexInTriangle: regl.this("attributes.indexInTriangle"),
129+
curvature: regl.this("attributes.curvature"),
130+
},
131+
elements: regl.this("elements"),
59132
uniforms: {
60133
eye: regl.prop("eye"),
61-
view: (context, props) => {
134+
view: (_, props) => {
62135
return mat4.lookAt([], props.eye, props.center, [0, 1, 0]);
63136
},
64-
projection: ({ viewportWidth, viewportHeight }) =>
65-
mat4.perspective(
66-
[],
67-
Math.PI / 4,
68-
viewportWidth / viewportHeight,
69-
0.01,
70-
1000
71-
),
72-
resolution: (c) => [
73-
c.drawingBufferWidth,
74-
c.drawingBufferHeight,
75-
Math.min(c.drawingBufferWidth, c.drawingBufferHeight),
137+
projection: ({ viewportWidth, viewportHeight }) => {
138+
const ratio = viewportWidth / viewportHeight;
139+
return mat4.perspective([], Math.PI / 4, ratio, 0.01, 1000);
140+
},
141+
resolution: ({ drawingBufferWidth, drawingBufferHeight }) => [
142+
drawingBufferWidth,
143+
drawingBufferHeight,
144+
Math.min(drawingBufferWidth, drawingBufferHeight),
76145
],
77146
pixelRatio: regl.context("pixelRatio"),
78-
scale: () => params.scale, // How large the textures are scaled in world space
79-
numTextures: () => 1.0 * numTextures,
80-
pencilTextures: () => pencilTextures,
147+
scale: regl.this("params.scale"), // How large the textures are scaled in world space
148+
numTextures: regl.this("numTextures"),
149+
pencilTextures: regl.this("pencilTextures"),
150+
},
151+
cull: {
152+
enable: true,
81153
},
82154
});
83155

84-
regl.frame(() => {
85-
if (params.rotate) {
86-
params.angle = (params.angle + params.speed / 100.0) % (2 * Math.PI);
87-
pane.refresh();
88-
}
89-
const t = params.angle;
90-
const radius = Math.pow(2, -params.zoom);
91-
const height = params.height;
92-
93-
regl.clear({
94-
color: [1, 1, 1, 1],
95-
});
96-
draw({
97-
eye: [radius * Math.cos(t), height, radius * Math.sin(t)],
98-
center: [0, height, 0],
99-
});
100-
});
156+
new Renderer().start();

src/texture.js

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,3 @@
1-
import * as base64 from "byte-base64";
2-
3-
export class TextureData {
4-
constructor(data, width, height, numTextures) {
5-
if (typeof data === "string") {
6-
this.data = new Uint8ClampedArray(base64.base64ToBytes(data));
7-
} else {
8-
this.data = data;
9-
}
10-
this.width = width;
11-
this.height = height;
12-
this.numTextures = numTextures;
13-
}
14-
toJSON() {
15-
return {
16-
numTextures: this.numTextures,
17-
width: this.width,
18-
height: this.height,
19-
data: base64.bytesToBase64(this.data),
20-
};
21-
}
22-
}
23-
241
export function generatePencilTextures(numTextures, width, height) {
252
const paper = new Paper(width, height);
263
const textures = new Uint8ClampedArray(4 * width * height * numTextures);
@@ -36,24 +13,7 @@ export function generatePencilTextures(numTextures, width, height) {
3613
}
3714
paper.clear();
3815
}
39-
return new TextureData(textures, width, height, numTextures);
40-
}
41-
42-
//for debugging purposes
43-
export function displayImageData(textureData) {
44-
const imgData = new ImageData(
45-
textureData.data,
46-
textureData.width,
47-
textureData.height * textureData.numTextures
48-
);
49-
let canvas = document.createElement("canvas");
50-
let ctx = canvas.getContext("2d");
51-
ctx.canvas.width = imgData.width;
52-
ctx.canvas.height = imgData.height;
53-
ctx.putImageData(imgData, 0, 0);
54-
let img = document.createElement("img");
55-
img.src = canvas.toDataURL("image/png");
56-
document.body.appendChild(img);
16+
return new ImageData(textures, width, height * numTextures);
5717
}
5818

5919
class Paper {

src/utils.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export function saveImage(imageData) {
1+
export function saveImage(filepath, imageData) {
22
const canvas = document.createElement("canvas");
33
document.body.appendChild(canvas);
4-
canvas.width = this.width;
5-
canvas.height = this.height;
4+
canvas.width = imageData.width;
5+
canvas.height = imageData.height;
66
canvas.getContext("2d").putImageData(imageData, 0, 0);
77
const dataUrl = canvas.toDataURL();
88
canvas.remove();
@@ -13,3 +13,11 @@ export function saveImage(imageData) {
1313
textureLink.click();
1414
textureLink.remove();
1515
}
16+
17+
export function loadImage(url) {
18+
const img = document.createElement("img");
19+
img.src = url;
20+
return new Promise((resolve) => {
21+
img.onload = () => resolve(img);
22+
});
23+
}

textures/texture_128_64_64.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

textures/texture_256_64_64.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)