003 fucking RENDERS models YAAAAAAAAA
This commit is contained in:
parent
28faa03ac6
commit
23d7810ab6
30 changed files with 16955 additions and 221 deletions
27
README.md
27
README.md
|
@ -24,19 +24,24 @@ https://art.mekanoe.com
|
||||||
|
|
||||||
### Infrastructure
|
### Infrastructure
|
||||||
|
|
||||||
- The "generator" does
|
- **Output generation**
|
||||||
|
|
||||||
- Generates a work list from .js files within `html`
|
- Bun renders TypeScript and GLSL to html/
|
||||||
- Creates this README.md file
|
- src/public/ is copied to html/
|
||||||
- Creates the index.html file
|
- This doubles as an "archival" system to preserve scuffedness
|
||||||
- Creates individual HTML files for each work
|
- .ply files are converted to JS typed arrays and Mesh objects
|
||||||
|
- .html files (and README.md) are generated from rendered TypeScript main.ts files.
|
||||||
|
|
||||||
- The platform supplies
|
- **Platform**
|
||||||
- Shader types
|
|
||||||
- Primitive objects
|
- WebGLApp provides render loop, canvas, and other stuff
|
||||||
- A canvas to draw on
|
- Behavior provides automatic registration of WebGLApp events (like Unity MonoBehaviors)
|
||||||
- WebGL hooks
|
- Shader provides GLSL shader tooling
|
||||||
- Helpers, etc
|
- Mesh is a DTO with vertex position, color, UVs, and faces
|
||||||
|
- MeshRenderer sends WebGL instructions for rendering a Mesh object with a Shader object.
|
||||||
|
- Renderable is a container of a Transform and Renderer (like a Unity GameObject)
|
||||||
|
- Transform is a tuplet of a position vec3, rotation quat, and scale vec3; to be used anywhere needed.
|
||||||
|
- Scene is a group of Renderables
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
@ -11,6 +11,9 @@ mkdirSync("html");
|
||||||
|
|
||||||
const works = globSync("src/*/main.ts");
|
const works = globSync("src/*/main.ts");
|
||||||
|
|
||||||
|
console.log(chalk.green`>> Convert meshes ...`);
|
||||||
|
await convertMeshes();
|
||||||
|
|
||||||
console.log(chalk.green`>> Building ...`);
|
console.log(chalk.green`>> Building ...`);
|
||||||
console.log(chalk.yellow(` Found ${works.length} works.`));
|
console.log(chalk.yellow(` Found ${works.length} works.`));
|
||||||
console.log(chalk.yellow(` Running Bun.build()`));
|
console.log(chalk.yellow(` Running Bun.build()`));
|
||||||
|
@ -44,6 +47,3 @@ const { stdout, stderr, exitCode } = Bun.spawnSync([
|
||||||
"-c",
|
"-c",
|
||||||
"cp -r src/public/* html/",
|
"cp -r src/public/* html/",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log(chalk.green`>> Convert meshes ...`);
|
|
||||||
await convertMeshes();
|
|
||||||
|
|
|
@ -1,6 +1,54 @@
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { globSync } from "glob";
|
import { globSync } from "glob";
|
||||||
|
|
||||||
|
const w = 1;
|
||||||
|
|
||||||
|
type Vertex = {
|
||||||
|
position: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
};
|
||||||
|
color?: {
|
||||||
|
r: number;
|
||||||
|
g: number;
|
||||||
|
b: number;
|
||||||
|
a: number;
|
||||||
|
};
|
||||||
|
uv?: {
|
||||||
|
u: number;
|
||||||
|
v: number;
|
||||||
|
};
|
||||||
|
normal?: {
|
||||||
|
nx: number;
|
||||||
|
ny: number;
|
||||||
|
nz: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type Face = {
|
||||||
|
a: number;
|
||||||
|
b: number;
|
||||||
|
c: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Triangle = {
|
||||||
|
a: Vertex;
|
||||||
|
b: Vertex;
|
||||||
|
c: Vertex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// const vertToArray = ({ x, y, z, w, r, g, b, a, u, v }: Vertex): number[] => {
|
||||||
|
// if (!r) return [x, y, z, u, v];
|
||||||
|
// else return [x, y, z, r, g as number, b as number, a as number, u, v];
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const triangleToArray = (t: Triangle): number[] => [
|
||||||
|
// ...vertToArray(t.a),
|
||||||
|
// ...vertToArray(t.b),
|
||||||
|
// ...vertToArray(t.c),
|
||||||
|
// ];
|
||||||
|
|
||||||
export const convertMeshes = async () => {
|
export const convertMeshes = async () => {
|
||||||
const meshes = globSync("src/meshes/*.ply");
|
const meshes = globSync("src/meshes/*.ply");
|
||||||
|
|
||||||
|
@ -8,8 +56,47 @@ export const convertMeshes = async () => {
|
||||||
const ply = await Bun.file(file).text();
|
const ply = await Bun.file(file).text();
|
||||||
|
|
||||||
const [header, body] = ply.split("end_header");
|
const [header, body] = ply.split("end_header");
|
||||||
const colorSize = header.includes("red") ? 4 : 0;
|
|
||||||
|
const propertyList: [string, "float" | "uchar"][] = [];
|
||||||
|
const vertexConfig = {
|
||||||
|
colors: false,
|
||||||
|
uvs: false,
|
||||||
|
normals: false,
|
||||||
|
};
|
||||||
const headerLines = header.split("\n");
|
const headerLines = header.split("\n");
|
||||||
|
|
||||||
|
for (const property of headerLines.filter((header) =>
|
||||||
|
header.startsWith("property")
|
||||||
|
)) {
|
||||||
|
const [, propType, name] = property.split(" ");
|
||||||
|
|
||||||
|
if (propType === "list") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyList.push([name, propType as any]);
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
case "red":
|
||||||
|
case "green":
|
||||||
|
case "blue":
|
||||||
|
case "alpha":
|
||||||
|
vertexConfig.colors = true;
|
||||||
|
break;
|
||||||
|
case "nx":
|
||||||
|
case "ny":
|
||||||
|
case "nz":
|
||||||
|
vertexConfig.normals = true;
|
||||||
|
break;
|
||||||
|
case "s":
|
||||||
|
case "t":
|
||||||
|
vertexConfig.uvs = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log({ propertyList });
|
||||||
|
|
||||||
const vertexCount = Number(
|
const vertexCount = Number(
|
||||||
headerLines
|
headerLines
|
||||||
.find((header) => header.startsWith("element vertex"))
|
.find((header) => header.startsWith("element vertex"))
|
||||||
|
@ -20,49 +107,152 @@ export const convertMeshes = async () => {
|
||||||
throw new Error("couldn't get vertex count...");
|
throw new Error("couldn't get vertex count...");
|
||||||
}
|
}
|
||||||
|
|
||||||
const values: number[] = [];
|
const vertexes: Vertex[] = [];
|
||||||
|
const faces: Face[] = [];
|
||||||
|
|
||||||
for (const line of body.split("\n")) {
|
for (const line of body.split("\n")) {
|
||||||
// line looks like
|
const components = line.split(" ");
|
||||||
// x y z r g b a u v
|
|
||||||
// We need to convert it to
|
|
||||||
// x y z 1 r g b a u v
|
|
||||||
|
|
||||||
const [x, y, z, r, g, b, a, u, v] = line.split(" ");
|
if (!components || !components[0]) {
|
||||||
|
|
||||||
if (!g) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
values.push(
|
// do we only have 4 components?
|
||||||
parseFloat(x),
|
if (components[0] === "3" || components.length === 4) {
|
||||||
parseFloat(y),
|
const [, a, b, c] = components;
|
||||||
parseFloat(z),
|
|
||||||
1,
|
|
||||||
parseFloat(r),
|
|
||||||
parseFloat(g)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (colorSize > 0) {
|
// We do??!?! 🥺👉👈
|
||||||
values.push(parseFloat(b), parseFloat(a), parseFloat(u), parseFloat(v));
|
faces.push({ a: Number(a), b: Number(b), c: Number(c) });
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vertex: Required<Vertex> = {
|
||||||
|
position: {
|
||||||
|
x: -1,
|
||||||
|
y: -1,
|
||||||
|
z: -1,
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
r: 0,
|
||||||
|
g: 0,
|
||||||
|
b: 0,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
normal: {
|
||||||
|
nx: -1,
|
||||||
|
ny: -1,
|
||||||
|
nz: -1,
|
||||||
|
},
|
||||||
|
uv: {
|
||||||
|
u: -1,
|
||||||
|
v: -1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const idx in components) {
|
||||||
|
const component = components[idx];
|
||||||
|
const [propName, propType] = propertyList[idx];
|
||||||
|
|
||||||
|
const p = parser[propType] ?? parseFloat;
|
||||||
|
|
||||||
|
switch (propName) {
|
||||||
|
case "x":
|
||||||
|
vertex.position.x = p(component);
|
||||||
|
break;
|
||||||
|
case "y":
|
||||||
|
vertex.position.y = p(component);
|
||||||
|
break;
|
||||||
|
case "z":
|
||||||
|
vertex.position.z = p(component);
|
||||||
|
case "s":
|
||||||
|
vertex.uv.u = p(component);
|
||||||
|
break;
|
||||||
|
case "t":
|
||||||
|
vertex.uv.v = p(component);
|
||||||
|
break;
|
||||||
|
case "red":
|
||||||
|
vertex.color.r = p(component);
|
||||||
|
break;
|
||||||
|
case "green":
|
||||||
|
vertex.color.g = p(component);
|
||||||
|
break;
|
||||||
|
case "blue":
|
||||||
|
vertex.color.b = p(component);
|
||||||
|
break;
|
||||||
|
case "nx":
|
||||||
|
vertex.normal.nx = p(component);
|
||||||
|
break;
|
||||||
|
case "ny":
|
||||||
|
vertex.normal.ny = p(component);
|
||||||
|
break;
|
||||||
|
case "nz":
|
||||||
|
vertex.normal.nz = p(component);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertexes.push(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const positions: number[] = vertexes.flatMap((v) => [
|
||||||
|
v.position.x,
|
||||||
|
v.position.y,
|
||||||
|
v.position.z,
|
||||||
|
]);
|
||||||
|
const normals: number[] = vertexConfig.normals
|
||||||
|
? vertexes.flatMap((v: any) => [v.normal.nx, v.normal.ny, v.normal.nz])
|
||||||
|
: [];
|
||||||
|
const colors: number[] = vertexConfig.colors
|
||||||
|
? vertexes.flatMap((v: any) => [
|
||||||
|
v.color.r,
|
||||||
|
v.color.g,
|
||||||
|
v.color.b,
|
||||||
|
v.color.a,
|
||||||
|
])
|
||||||
|
: [];
|
||||||
|
const uvs: number[] = vertexConfig.uvs
|
||||||
|
? vertexes.flatMap((v: any) => [v.uv.u, v.uv.v])
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const facesArray: number[] = faces.flatMap((f) => [f.a, f.b, f.c]);
|
||||||
|
|
||||||
const outFile = file.replace(".ply", ".ts");
|
const outFile = file.replace(".ply", ".ts");
|
||||||
const outString = `
|
const outString = `
|
||||||
import { Mesh } from "../renderer/mesh";
|
import { Mesh } from "../renderer/mesh";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const mesh = new Float32Array(${JSON.stringify(values)});
|
const positions = new Float32Array(${JSON.stringify(positions)});
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const colors = ${
|
||||||
|
vertexConfig.colors ? `new Uint8Array(${JSON.stringify(colors)})` : "null"
|
||||||
|
};
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const uvs = ${
|
||||||
|
vertexConfig.uvs ? `new Float32Array(${JSON.stringify(uvs)})` : "null"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const normals = ${
|
||||||
|
vertexConfig.normals
|
||||||
|
? `new Float32Array(${JSON.stringify(normals)})`
|
||||||
|
: "null"
|
||||||
|
};
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const faces = new Uint32Array(${JSON.stringify(facesArray)});
|
||||||
|
|
||||||
export default new Mesh({
|
export default new Mesh({
|
||||||
mesh,
|
colors,
|
||||||
positionSize: 4,
|
faces,
|
||||||
colorSize: ${colorSize},
|
name: ${JSON.stringify(file)},
|
||||||
uvSize: 2,
|
normals,
|
||||||
vertexCount: ${vertexCount},
|
positions,
|
||||||
stride: ${4 + colorSize + 2},
|
uvs,
|
||||||
name: ${JSON.stringify(file)}
|
vertexCount: ${vertexCount}
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -70,3 +260,8 @@ export default new Mesh({
|
||||||
console.log(chalk.yellow(` -> ${file}...`));
|
console.log(chalk.yellow(` -> ${file}...`));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parser = {
|
||||||
|
float: (x: string) => parseFloat(x),
|
||||||
|
uchar: (x: string) => Number(x),
|
||||||
|
};
|
||||||
|
|
|
@ -22,19 +22,24 @@ https://art.mekanoe.com
|
||||||
|
|
||||||
### Infrastructure
|
### Infrastructure
|
||||||
|
|
||||||
- The "generator" does
|
- **Output generation**
|
||||||
|
|
||||||
- Generates a work list from .js files within `html`
|
- Bun renders TypeScript and GLSL to html/
|
||||||
- Creates this README.md file
|
- src/public/ is copied to html/
|
||||||
- Creates the index.html file
|
- This doubles as an "archival" system to preserve scuffedness
|
||||||
- Creates individual HTML files for each work
|
- .ply files are converted to JS typed arrays and Mesh objects
|
||||||
|
- .html files (and README.md) are generated from rendered TypeScript main.ts files.
|
||||||
|
|
||||||
- The platform supplies
|
- **Platform**
|
||||||
- Shader types
|
|
||||||
- Primitive objects
|
- WebGLApp provides render loop, canvas, and other stuff
|
||||||
- A canvas to draw on
|
- Behavior provides automatic registration of WebGLApp events (like Unity MonoBehaviors)
|
||||||
- WebGL hooks
|
- Shader provides GLSL shader tooling
|
||||||
- Helpers, etc
|
- Mesh is a DTO with vertex position, color, UVs, and faces
|
||||||
|
- MeshRenderer sends WebGL instructions for rendering a Mesh object with a Shader object.
|
||||||
|
- Renderable is a container of a Transform and Renderer (like a Unity GameObject)
|
||||||
|
- Transform is a tuplet of a position vec3, rotation quat, and scale vec3; to be used anywhere needed.
|
||||||
|
- Scene is a group of Renderables
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12
package.json
12
package.json
|
@ -4,13 +4,14 @@
|
||||||
"main": "./hack/build.ts",
|
"main": "./hack/build.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bun $BUNFLAGS .",
|
"build": "bun $BUNFLAGS .",
|
||||||
"build:watch": "BUNFLAGS=--watch bun run build",
|
"build:watch": "nodemon -e ts,js,frag,vert,glsl,ply",
|
||||||
"serve": "serve ./html",
|
"serve": "serve ./html",
|
||||||
"dev": "run-p serve build:watch"
|
"dev": "run-p serve build:watch"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "latest",
|
"bun-types": "latest",
|
||||||
"npm-run-all2": "^6.1.1",
|
"npm-run-all2": "^6.1.1",
|
||||||
|
"nodemon": "^3.0.1",
|
||||||
"prettier": "^3.0.3"
|
"prettier": "^3.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@ -23,5 +24,14 @@
|
||||||
"glob": "^10.3.10",
|
"glob": "^10.3.10",
|
||||||
"serve": "^14.2.1",
|
"serve": "^14.2.1",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
|
},
|
||||||
|
"nodemonConfig": {
|
||||||
|
"ignore": [
|
||||||
|
"html/",
|
||||||
|
"README.md",
|
||||||
|
"src/meshes/*.ts"
|
||||||
|
],
|
||||||
|
"delay": 1000,
|
||||||
|
"exec": "bun run . --"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
// This one is archived.
|
// // This one is archived.
|
||||||
|
|
||||||
import { Shader } from "./shader";
|
// import { Shader } from "./shader";
|
||||||
import { BasicPlane } from "./basic-plane";
|
// import { BasicPlane } from "./basic-plane";
|
||||||
import { App } from "./app";
|
// import { App } from "./app";
|
||||||
import fragment from "./fragment.glsl";
|
// import fragment from "./fragment.glsl";
|
||||||
import vertex from "./vertex.glsl";
|
// import vertex from "./vertex.glsl";
|
||||||
|
|
||||||
const app = new App({ fov: 20 });
|
// const app = new App({ fov: 20 });
|
||||||
const gl = app.gl;
|
// const gl = app.gl;
|
||||||
|
|
||||||
const shader = new Shader(app)
|
// const shader = new Shader(app)
|
||||||
.attach(gl.VERTEX_SHADER, vertex)
|
// .attach(gl.VERTEX_SHADER, vertex)
|
||||||
.attach(gl.FRAGMENT_SHADER, fragment)
|
// .attach(gl.FRAGMENT_SHADER, fragment)
|
||||||
.link();
|
// .link();
|
||||||
|
|
||||||
const plane = new BasicPlane(app);
|
// const plane = new BasicPlane(app);
|
||||||
plane.attachShader(shader);
|
// plane.attachShader(shader);
|
||||||
|
|
||||||
app.loop();
|
// app.loop();
|
||||||
|
|
|
@ -1,42 +1,43 @@
|
||||||
// This one is archived.
|
// // This one is archived.
|
||||||
import { MeshRenderer } from "../renderer/mesh-renderer";
|
|
||||||
import plane from "../meshes/plane";
|
|
||||||
import { WebGLApp } from "../renderer/webgl";
|
|
||||||
import { Renderable } from "../renderer/renderable";
|
|
||||||
import { Transform } from "../renderer/transform";
|
|
||||||
import { uvRainbow } from "../common-shaders/uv-rainbow";
|
|
||||||
import { quat } from "gl-matrix";
|
|
||||||
import torus from "../meshes/torus";
|
|
||||||
|
|
||||||
const app = new WebGLApp({ fov: 45 });
|
// import { MeshRenderer } from "../renderer/mesh-renderer";
|
||||||
|
// import plane from "../meshes/plane";
|
||||||
|
// import { WebGLApp } from "../renderer/webgl";
|
||||||
|
// import { Renderable } from "../renderer/renderable";
|
||||||
|
// import { Transform } from "../renderer/transform";
|
||||||
|
// import { uvRainbow } from "../common-shaders/uv-rainbow";
|
||||||
|
// import { quat } from "gl-matrix";
|
||||||
|
// import torus from "../meshes/torus";
|
||||||
|
|
||||||
const camera = new Transform(
|
// const app = new WebGLApp({ fov: 45 });
|
||||||
[0, 0, -6],
|
|
||||||
quat.fromEuler(quat.create(), 15, 0, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
const modelTransform = new Transform([0, 0, 4]);
|
// const camera = new Transform(
|
||||||
|
// [0, 0, -6],
|
||||||
|
// quat.fromEuler(quat.create(), 15, 0, 0)
|
||||||
|
// );
|
||||||
|
|
||||||
app.onUpdate((time: number) => {
|
// const modelTransform = new Transform([0, 0, 4]);
|
||||||
const cameraStride = 3;
|
|
||||||
const x = Math.sin(time * 0.0001) * (cameraStride * 2 - cameraStride * 0.5);
|
|
||||||
|
|
||||||
camera.rotation = quat.fromEuler(quat.create(), x, 0, 0);
|
// app.onUpdate((time: number) => {
|
||||||
// modelTransform.rotation = quat.fromEuler(quat.create(), x, 0, 0);
|
// const cameraStride = 3;
|
||||||
});
|
// const x = Math.sin(time * 0.0001) * (cameraStride * 2 - cameraStride * 0.5);
|
||||||
|
|
||||||
new Renderable(
|
// camera.rotation = quat.fromEuler(quat.create(), x, 0, 0);
|
||||||
app,
|
// // modelTransform.rotation = quat.fromEuler(quat.create(), x, 0, 0);
|
||||||
modelTransform,
|
// });
|
||||||
new MeshRenderer(app, torus, uvRainbow(app), camera, {
|
|
||||||
drawMode: app.gl.TRIANGLE_FAN,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// new Renderable(
|
// new Renderable(
|
||||||
// app,
|
// app,
|
||||||
// new Transform([1, 0, 0]),
|
// modelTransform,
|
||||||
// new MeshRenderer(app, plane, uvRainbow(app))
|
// new MeshRenderer(app, torus, uvRainbow(app), camera, {
|
||||||
|
// drawMode: app.gl.TRIANGLE_FAN,
|
||||||
|
// })
|
||||||
// );
|
// );
|
||||||
|
|
||||||
app.start();
|
// // new Renderable(
|
||||||
|
// // app,
|
||||||
|
// // new Transform([1, 0, 0]),
|
||||||
|
// // new MeshRenderer(app, plane, uvRainbow(app))
|
||||||
|
// // );
|
||||||
|
|
||||||
|
// app.start();
|
||||||
|
|
|
@ -4,13 +4,27 @@ import { Renderable } from "../renderer/renderable";
|
||||||
import { Transform } from "../renderer/transform";
|
import { Transform } from "../renderer/transform";
|
||||||
import torus from "../meshes/torus";
|
import torus from "../meshes/torus";
|
||||||
import { errorShader } from "../common-shaders/error";
|
import { errorShader } from "../common-shaders/error";
|
||||||
|
import plane from "../meshes/plane";
|
||||||
|
import { uvRainbow } from "../common-shaders/uv-rainbow";
|
||||||
|
import uvsphere from "../meshes/uvsphere";
|
||||||
|
import { quat } from "gl-matrix";
|
||||||
|
import trianglething from "../meshes/trianglething";
|
||||||
|
import teapot from "../meshes/teapot";
|
||||||
|
|
||||||
const app = new WebGLApp({ fov: 45 });
|
const app = new WebGLApp({ fov: 45 });
|
||||||
|
|
||||||
|
const camera = new Transform([0, -2, -6]);
|
||||||
|
|
||||||
new Renderable(
|
new Renderable(
|
||||||
app,
|
app,
|
||||||
new Transform(),
|
new Transform(),
|
||||||
new MeshRenderer(app, torus, errorShader(app))
|
new MeshRenderer(app, trianglething, uvRainbow(app), camera).configure({})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// new Renderable(
|
||||||
|
// app,
|
||||||
|
// new Transform(),
|
||||||
|
// new MeshRenderer(app, torus, uvRainbow(app), camera).configure({})
|
||||||
|
// );
|
||||||
|
|
||||||
app.start();
|
app.start();
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
#version 300 es
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform float uTime;
|
uniform float uTime;
|
||||||
uniform float uSinTime;
|
uniform float uSinTime;
|
||||||
uniform float uCosTime;
|
uniform float uCosTime;
|
||||||
|
|
||||||
varying highp vec2 vTextureCoord;
|
in vec2 vTextureCoord;
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
vec3 rgb2hsv(vec3 c) {
|
vec3 rgb2hsv(vec3 c) {
|
||||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||||
|
@ -30,6 +32,6 @@ void main() {
|
||||||
hsv.z = 1.0;
|
hsv.z = 1.0;
|
||||||
vec3 rgb = hsv2rgb(hsv);
|
vec3 rgb = hsv2rgb(hsv);
|
||||||
|
|
||||||
gl_FragColor = vec4(rgb, 1.0);
|
fragColor = vec4(rgb, 1.0);
|
||||||
gl_FragColor = clamp(gl_FragColor, 0.0, 1.0);
|
fragColor = clamp(fragColor, 0.0, 1.0);
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
attribute vec4 aVertexPosition;
|
#version 300 es
|
||||||
attribute vec2 aTextureCoord;
|
layout(location = 0) in vec4 aVertexPosition;
|
||||||
|
layout(location = 1) in vec2 aTextureCoord;
|
||||||
|
|
||||||
uniform mat4 uModelViewMatrix;
|
uniform mat4 uModelViewMatrix;
|
||||||
uniform mat4 uProjectionMatrix;
|
uniform mat4 uProjectionMatrix;
|
||||||
|
|
||||||
varying highp vec2 vTextureCoord;
|
out vec2 vTextureCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
|
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
|
||||||
|
|
18
src/meshes/plane.ply
Normal file
18
src/meshes/plane.ply
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
ply
|
||||||
|
format ascii 1.0
|
||||||
|
comment Created in Blender version 3.6.4
|
||||||
|
element vertex 4
|
||||||
|
property float x
|
||||||
|
property float y
|
||||||
|
property float z
|
||||||
|
property float s
|
||||||
|
property float t
|
||||||
|
element face 2
|
||||||
|
property list uchar uint vertex_indices
|
||||||
|
end_header
|
||||||
|
1 -1 0 1 0
|
||||||
|
-1 1 0 0 1
|
||||||
|
-1 -1 0 0 0
|
||||||
|
1 1 0 1 1
|
||||||
|
3 0 1 2
|
||||||
|
3 0 3 1
|
|
@ -1,20 +1,28 @@
|
||||||
|
|
||||||
import { Mesh } from "../renderer/mesh";
|
import { Mesh } from "../renderer/mesh";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const mesh = new Float32Array([
|
const positions = new Float32Array([1,-1,0,-1,1,0,-1,-1,0,1,1,0]);
|
||||||
// f4 position, f4 color, f2 uv
|
|
||||||
-1, -1, 0, 1, 1, 1, 1, 1, 0, 0,
|
// prettier-ignore
|
||||||
1, -1, 0, 1, 1, 1, 1, 1, 1, 0,
|
const colors = null;
|
||||||
-1, 1, 0, 1, 1, 1, 1, 1, 0, 1,
|
|
||||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
|
// prettier-ignore
|
||||||
]);
|
const uvs = new Float32Array([1,0,0,1,0,0,1,1]);
|
||||||
|
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const normals = null;
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const faces = new Uint32Array([0,1,2,0,3,1]);
|
||||||
|
|
||||||
export default new Mesh({
|
export default new Mesh({
|
||||||
mesh,
|
colors,
|
||||||
positionSize: 4,
|
faces,
|
||||||
colorSize: 4,
|
name: "src/meshes/plane.ply",
|
||||||
uvSize: 2,
|
normals,
|
||||||
vertexCount: 4,
|
positions,
|
||||||
stride: 10,
|
uvs,
|
||||||
name: "plane",
|
vertexCount: 4
|
||||||
});
|
});
|
||||||
|
|
2028
src/meshes/teapot.ply
Normal file
2028
src/meshes/teapot.ply
Normal file
File diff suppressed because it is too large
Load diff
28
src/meshes/teapot.ts
Normal file
28
src/meshes/teapot.ts
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
76
src/meshes/trianglething.ply
Normal file
76
src/meshes/trianglething.ply
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
ply
|
||||||
|
format ascii 1.0
|
||||||
|
comment Created in Blender version 3.6.4
|
||||||
|
element vertex 31
|
||||||
|
property float x
|
||||||
|
property float y
|
||||||
|
property float z
|
||||||
|
property float nx
|
||||||
|
property float ny
|
||||||
|
property float nz
|
||||||
|
property uchar red
|
||||||
|
property uchar green
|
||||||
|
property uchar blue
|
||||||
|
property uchar alpha
|
||||||
|
property float s
|
||||||
|
property float t
|
||||||
|
element face 26
|
||||||
|
property list uchar uint vertex_indices
|
||||||
|
end_header
|
||||||
|
0 2.609 0 0 -1 8.3803394e-07 0 1 255 255 0.00013659838 0.8180941
|
||||||
|
-0.368004 2.9959495 0.50652 -0.5257306 -0.44721383 0.723607 0 1 255 255 0.15755458 0.7272099
|
||||||
|
-0.595448 2.9959495 -0.19346951 -0.8506533 -0.44721213 -0.2763879 0 1 255 255 0.1575546 0.9089782
|
||||||
|
0 2.609 0 0 -1 8.3803394e-07 0 1 255 255 0.00013659043 0.6363257
|
||||||
|
0.368004 2.9959495 0.50652 0.5257306 -0.4472139 0.723607 0 1 255 255 0.15755458 0.54544157
|
||||||
|
0 2.609 0 0 -1 8.3803394e-07 0 1 255 255 0.0001365666 0.09102075
|
||||||
|
-0.595448 2.9959495 -0.19346951 -0.8506533 -0.44721213 -0.2763879 0 1 255 255 0.15755455 0.00013656964
|
||||||
|
0 2.9959495 -0.6260975 0 -0.44721153 -0.89442825 0 1 255 255 0.15755457 0.18190491
|
||||||
|
0 2.609 0 0 -1 8.3803394e-07 0 1 255 255 0.00013657454 0.2727891
|
||||||
|
0.595448 2.9959495 -0.19346951 0.8506533 -0.4472122 -0.27638793 0 1 255 255 0.15755457 0.36367324
|
||||||
|
0 2.609 0 0 -1 8.3803394e-07 0 1 255 255 0.00013658249 0.45455742
|
||||||
|
0 3.6220505 0.6260975 0 0.44721153 0.89442825 0 1 255 255 0.31497157 0.6363257
|
||||||
|
-0.595448 3.6220505 0.19346951 -0.8506533 0.44721216 0.27638793 0 1 255 255 0.31497157 0.8180941
|
||||||
|
-0.368004 3.6220505 -0.50652 -0.5257306 0.4472139 -0.72360694 0 1 255 255 0.31497154 0.09102073
|
||||||
|
0.368004 3.6220505 -0.50652 0.5257306 0.4472139 -0.72360694 0 1 255 255 0.31497154 0.27278906
|
||||||
|
0.595448 3.6220505 0.19346951 0.85065323 0.4472122 0.2763879 0 1 255 255 0.31497154 0.45455742
|
||||||
|
-0.368004 3.6220505 -0.50652 -0.5257306 0.4472139 -0.72360694 0 1 255 255 0.31497157 0.9998634
|
||||||
|
0 4.0090003 0 0 1 -8.165459e-07 0 1 255 255 0.47238955 0.72720987
|
||||||
|
0 4.0090003 0 0 1 -8.165459e-07 0 1 255 255 0.47238958 0.9089782
|
||||||
|
0 4.0090003 0 0 1 -8.165459e-07 0 1 255 255 0.47238955 0.1819049
|
||||||
|
0 4.0090003 0 0 1 -8.165459e-07 0 1 255 255 0.47238955 0.36367324
|
||||||
|
0 4.0090003 0 0 1 -8.165459e-07 0 1 255 255 0.47238955 0.54544157
|
||||||
|
1 0 0 0.8999471 -0.43599886 2.4163015e-07 0 1 255 255 0.8119813 0.33945516
|
||||||
|
0 2.5 0 -5.150958e-08 1 0 0 1 255 255 0.642322 0.16979587
|
||||||
|
-4.3711392e-08 0 1 -3.0203772e-08 -0.4359989 0.8999472 0 1 255 255 0.8119813 0.00013659486
|
||||||
|
-1 0 -8.7422784e-08 -0.8999471 -0.4359989 -2.4291313e-07 0 1 255 255 0.47266275 0.00013660162
|
||||||
|
-4.3711392e-08 0 1 -3.0203772e-08 -0.4359989 0.8999472 0 1 255 255 0.81198126 0.6790469
|
||||||
|
1.19248815e-08 0 -1 0 -0.43599886 -0.8999471 0 1 255 255 0.47266275 0.33972836
|
||||||
|
1 0 0 0.8999471 -0.43599886 2.4163015e-07 0 1 255 255 0.47266272 0.6790469
|
||||||
|
1.19248815e-08 0 -1 0 -0.43599886 -0.8999471 0 1 255 255 0.47266275 0.33945513
|
||||||
|
-1 0 -8.7422784e-08 -0.8999471 -0.4359989 -2.4291313e-07 0 1 255 255 0.81198126 0.3397284
|
||||||
|
3 0 1 2
|
||||||
|
3 1 3 4
|
||||||
|
3 5 6 7
|
||||||
|
3 8 7 9
|
||||||
|
3 10 9 4
|
||||||
|
3 1 4 11
|
||||||
|
3 2 1 12
|
||||||
|
3 7 6 13
|
||||||
|
3 9 7 14
|
||||||
|
3 4 9 15
|
||||||
|
3 1 11 12
|
||||||
|
3 2 12 16
|
||||||
|
3 7 13 14
|
||||||
|
3 9 14 15
|
||||||
|
3 4 15 11
|
||||||
|
3 12 11 17
|
||||||
|
3 16 12 18
|
||||||
|
3 14 13 19
|
||||||
|
3 15 14 20
|
||||||
|
3 11 15 21
|
||||||
|
3 22 23 24
|
||||||
|
3 24 23 25
|
||||||
|
3 26 27 28
|
||||||
|
3 25 23 29
|
||||||
|
3 29 23 22
|
||||||
|
3 26 30 27
|
28
src/meshes/trianglething.ts
Normal file
28
src/meshes/trianglething.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
import { Mesh } from "../renderer/mesh";
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const positions = new Float32Array([0,2.609,0,-0.368004,2.9959495,0.50652,-0.595448,2.9959495,-0.19346951,0,2.609,0,0.368004,2.9959495,0.50652,0,2.609,0,-0.595448,2.9959495,-0.19346951,0,2.9959495,-0.6260975,0,2.609,0,0.595448,2.9959495,-0.19346951,0,2.609,0,0,3.6220505,0.6260975,-0.595448,3.6220505,0.19346951,-0.368004,3.6220505,-0.50652,0.368004,3.6220505,-0.50652,0.595448,3.6220505,0.19346951,-0.368004,3.6220505,-0.50652,0,4.0090003,0,0,4.0090003,0,0,4.0090003,0,0,4.0090003,0,0,4.0090003,0,1,0,0,0,2.5,0,-4.3711392e-8,0,1,-1,0,-8.7422784e-8,-4.3711392e-8,0,1,1.19248815e-8,0,-1,1,0,0,1.19248815e-8,0,-1,-1,0,-8.7422784e-8]);
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const colors = new Uint8Array([0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255,0,1,255,255]);
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const uvs = new Float32Array([0.00013659838,0.8180941,0.15755458,0.7272099,0.1575546,0.9089782,0.00013659043,0.6363257,0.15755458,0.54544157,0.0001365666,0.09102075,0.15755455,0.00013656964,0.15755457,0.18190491,0.00013657454,0.2727891,0.15755457,0.36367324,0.00013658249,0.45455742,0.31497157,0.6363257,0.31497157,0.8180941,0.31497154,0.09102073,0.31497154,0.27278906,0.31497154,0.45455742,0.31497157,0.9998634,0.47238955,0.72720987,0.47238958,0.9089782,0.47238955,0.1819049,0.47238955,0.36367324,0.47238955,0.54544157,0.8119813,0.33945516,0.642322,0.16979587,0.8119813,0.00013659486,0.47266275,0.00013660162,0.81198126,0.6790469,0.47266275,0.33972836,0.47266272,0.6790469,0.47266275,0.33945513,0.81198126,0.3397284]);
|
||||||
|
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const normals = new Float32Array([0,-1,8.3803394e-7,-0.5257306,-0.44721383,0.723607,-0.8506533,-0.44721213,-0.2763879,0,-1,8.3803394e-7,0.5257306,-0.4472139,0.723607,0,-1,8.3803394e-7,-0.8506533,-0.44721213,-0.2763879,0,-0.44721153,-0.89442825,0,-1,8.3803394e-7,0.8506533,-0.4472122,-0.27638793,0,-1,8.3803394e-7,0,0.44721153,0.89442825,-0.8506533,0.44721216,0.27638793,-0.5257306,0.4472139,-0.72360694,0.5257306,0.4472139,-0.72360694,0.85065323,0.4472122,0.2763879,-0.5257306,0.4472139,-0.72360694,0,1,-8.165459e-7,0,1,-8.165459e-7,0,1,-8.165459e-7,0,1,-8.165459e-7,0,1,-8.165459e-7,0.8999471,-0.43599886,2.4163015e-7,-5.150958e-8,1,0,-3.0203772e-8,-0.4359989,0.8999472,-0.8999471,-0.4359989,-2.4291313e-7,-3.0203772e-8,-0.4359989,0.8999472,0,-0.43599886,-0.8999471,0.8999471,-0.43599886,2.4163015e-7,0,-0.43599886,-0.8999471,-0.8999471,-0.4359989,-2.4291313e-7]);
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const faces = new Uint32Array([0,1,2,1,3,4,5,6,7,8,7,9,10,9,4,1,4,11,2,1,12,7,6,13,9,7,14,4,9,15,1,11,12,2,12,16,7,13,14,9,14,15,4,15,11,12,11,17,16,12,18,14,13,19,15,14,20,11,15,21,22,23,24,24,23,25,26,27,28,25,23,29,29,23,22,26,30,27]);
|
||||||
|
|
||||||
|
export default new Mesh({
|
||||||
|
colors,
|
||||||
|
faces,
|
||||||
|
name: "src/meshes/trianglething.ply",
|
||||||
|
normals,
|
||||||
|
positions,
|
||||||
|
uvs,
|
||||||
|
vertexCount: 31
|
||||||
|
});
|
14234
src/meshes/uvsphere.ply
Normal file
14234
src/meshes/uvsphere.ply
Normal file
File diff suppressed because it is too large
Load diff
28
src/meshes/uvsphere.ts
Normal file
28
src/meshes/uvsphere.ts
Normal file
File diff suppressed because one or more lines are too long
|
@ -5,10 +5,12 @@ export abstract class Behavior {
|
||||||
onBeforeUpdate?(...args: any[]): void;
|
onBeforeUpdate?(...args: any[]): void;
|
||||||
onUpdate?(...args: any[]): void;
|
onUpdate?(...args: any[]): void;
|
||||||
onAfterUpdate?(...args: any[]): void;
|
onAfterUpdate?(...args: any[]): void;
|
||||||
|
onDraw?(...args: any[]): void;
|
||||||
constructor(public app: WebGLApp) {
|
constructor(public app: WebGLApp) {
|
||||||
this.onStart && app.onStart(this.onStart.bind(this));
|
this.onStart && app.onStart(this.onStart.bind(this));
|
||||||
this.onUpdate && app.onUpdate(this.onUpdate.bind(this));
|
this.onUpdate && app.onUpdate(this.onUpdate.bind(this));
|
||||||
this.onAfterUpdate && app.onAfterUpdate(this.onAfterUpdate.bind(this));
|
this.onAfterUpdate && app.onAfterUpdate(this.onAfterUpdate.bind(this));
|
||||||
this.onBeforeUpdate && app.onBeforeUpdate(this.onBeforeUpdate.bind(this));
|
this.onBeforeUpdate && app.onBeforeUpdate(this.onBeforeUpdate.bind(this));
|
||||||
|
this.onDraw && app.onDraw(this.onDraw.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,22 @@ import { Mesh } from "./mesh";
|
||||||
import { Shader } from "./shader";
|
import { Shader } from "./shader";
|
||||||
import { WebGLApp } from "./webgl";
|
import { WebGLApp } from "./webgl";
|
||||||
import { Transform } from "./transform";
|
import { Transform } from "./transform";
|
||||||
import { errorShader } from "../common-shaders/error";
|
|
||||||
|
|
||||||
export type MeshRendererConfig = {
|
export type MeshRendererConfig = {
|
||||||
drawMode?: number;
|
drawMode?: number;
|
||||||
|
cullMode?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class MeshRenderer extends Behavior {
|
export class MeshRenderer extends Behavior {
|
||||||
private modelMatrix = mat4.create();
|
private modelMatrix = mat4.create();
|
||||||
private projectionMatrix = mat4.create();
|
private projectionMatrix = mat4.create();
|
||||||
private _meshBuffer?: WebGLBuffer;
|
private buffers: {
|
||||||
|
position?: WebGLBuffer;
|
||||||
|
uv?: WebGLBuffer;
|
||||||
|
normal?: WebGLBuffer;
|
||||||
|
color?: WebGLBuffer;
|
||||||
|
faces?: WebGLBuffer;
|
||||||
|
} = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public app: WebGLApp,
|
public app: WebGLApp,
|
||||||
|
@ -25,106 +31,130 @@ export class MeshRenderer extends Behavior {
|
||||||
super(app);
|
super(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
get meshBuffer() {
|
configure(config: MeshRendererConfig) {
|
||||||
if (this._meshBuffer) {
|
this.config = config;
|
||||||
return this._meshBuffer;
|
return this;
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("mesh buffer not ready");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeMeshBuffer() {
|
makeBuffer(data: TypedArray, target: number = 34962) {
|
||||||
const gl = this.app.gl;
|
const gl = this.app.gl;
|
||||||
const buffer = gl.createBuffer();
|
const buffer = gl.createBuffer();
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
throw new Error("failed to create mesh buffer");
|
throw new Error("failed to create a buffer");
|
||||||
}
|
}
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
||||||
gl.bufferData(gl.ARRAY_BUFFER, this.mesh.config.mesh, gl.STATIC_DRAW);
|
|
||||||
|
|
||||||
this._meshBuffer = buffer;
|
gl.bindBuffer(target, buffer);
|
||||||
|
gl.bufferData(target, data, gl.STATIC_DRAW);
|
||||||
|
gl.bindBuffer(target, null);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeAttributes() {
|
initializeBuffers() {
|
||||||
const gl = this.app.gl;
|
this.buffers.faces = this.makeBuffer(
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.meshBuffer);
|
this.mesh.config.faces,
|
||||||
|
this.app.gl.ELEMENT_ARRAY_BUFFER
|
||||||
|
);
|
||||||
|
|
||||||
const positionLocation = this.shader.attrib("aVertexPosition");
|
this.buffers.position = this.makeBuffer(this.mesh.config.positions);
|
||||||
if (positionLocation !== -1) {
|
this.bindAttrib(this.buffers.position, 0, 3, this.app.gl.FLOAT);
|
||||||
|
|
||||||
|
if (this.mesh.config.normals) {
|
||||||
|
this.buffers.normal = this.makeBuffer(this.mesh.config.normals);
|
||||||
|
this.bindAttrib(
|
||||||
|
this.buffers.normal,
|
||||||
|
"aVertexNormals",
|
||||||
|
3,
|
||||||
|
this.app.gl.FLOAT,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mesh.config.colors) {
|
||||||
|
this.buffers.color = this.makeBuffer(this.mesh.config.colors);
|
||||||
|
this.bindAttrib(
|
||||||
|
this.buffers.color,
|
||||||
|
"aVertexColors",
|
||||||
|
4,
|
||||||
|
this.app.gl.UNSIGNED_BYTE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mesh.config.uvs) {
|
||||||
|
this.buffers.uv = this.makeBuffer(this.mesh.config.uvs);
|
||||||
|
this.bindAttrib(this.buffers.uv, 1, 2, this.app.gl.FLOAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bindAttrib(
|
||||||
|
buffer: WebGLBuffer,
|
||||||
|
attribute: string | number,
|
||||||
|
elements: number,
|
||||||
|
glType: number,
|
||||||
|
normalized: boolean = false
|
||||||
|
) {
|
||||||
|
const gl = this.app.gl;
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||||
|
|
||||||
|
const attributePosition = Number.isSafeInteger(attribute)
|
||||||
|
? (attribute as number)
|
||||||
|
: this.shader.attrib(attribute as string);
|
||||||
|
if (attributePosition !== -1) {
|
||||||
gl.vertexAttribPointer(
|
gl.vertexAttribPointer(
|
||||||
positionLocation,
|
attributePosition,
|
||||||
this.mesh.config.positionSize,
|
elements,
|
||||||
gl.FLOAT,
|
glType,
|
||||||
false,
|
normalized,
|
||||||
4 * this.mesh.config.stride,
|
0,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
gl.enableVertexAttribArray(positionLocation);
|
gl.enableVertexAttribArray(attributePosition);
|
||||||
this.shader.bindAttrib(positionLocation, "aVertexPosition");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mesh.config.colorSize !== 0) {
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||||
const colorLocation = this.shader.attrib("aVertexColor");
|
|
||||||
if (colorLocation !== -1) {
|
|
||||||
gl.vertexAttribPointer(
|
|
||||||
colorLocation,
|
|
||||||
this.mesh.config.colorSize,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
4 * this.mesh.config.stride,
|
|
||||||
4 * this.mesh.config.positionSize
|
|
||||||
);
|
|
||||||
gl.enableVertexAttribArray(colorLocation);
|
|
||||||
this.shader.bindAttrib(colorLocation, "aVertexColor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uvLocation = this.shader.attrib("aTextureCoord");
|
|
||||||
if (uvLocation !== -1) {
|
|
||||||
gl.vertexAttribPointer(
|
|
||||||
uvLocation,
|
|
||||||
this.mesh.config.uvSize,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
4 * this.mesh.config.stride,
|
|
||||||
4 * (this.mesh.config.positionSize + this.mesh.config.colorSize)
|
|
||||||
);
|
|
||||||
gl.enableVertexAttribArray(uvLocation);
|
|
||||||
this.shader.bindAttrib(uvLocation, "aTextureCoord");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onStart() {
|
onStart() {
|
||||||
mat4.perspective(
|
mat4.perspective(
|
||||||
this.projectionMatrix,
|
this.projectionMatrix,
|
||||||
this.app.config.fov || 45,
|
this.app.config.fov || 45,
|
||||||
this.app.canvas.width / this.app.canvas.height,
|
this.app.aspect,
|
||||||
this.app.config.zNear || 0.1,
|
this.app.config.zNear || 0.1,
|
||||||
this.app.config.zFar || 100
|
this.app.config.zFar || 100
|
||||||
);
|
);
|
||||||
|
|
||||||
this.shader.compile();
|
this.shader.compile();
|
||||||
this.initializeMeshBuffer();
|
this.initializeBuffers();
|
||||||
this.initializeAttributes();
|
|
||||||
this.shader.link();
|
this.shader.link();
|
||||||
}
|
}
|
||||||
|
|
||||||
onRenderableUpdate(time: number, transform: Transform) {
|
onRenderableUpdate(time: number, transform: Transform) {
|
||||||
const gl = this.app.gl;
|
const gl = this.app.gl;
|
||||||
|
|
||||||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.buffers.faces || null);
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffers.position || null);
|
||||||
|
|
||||||
this.shader.use();
|
this.shader.use();
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.meshBuffer);
|
|
||||||
this.shader.setupUniforms(
|
this.shader.setupUniforms(
|
||||||
time,
|
time,
|
||||||
this.projectionMatrix,
|
this.projectionMatrix,
|
||||||
transform,
|
transform,
|
||||||
this.camera
|
this.camera
|
||||||
);
|
);
|
||||||
gl.drawArrays(
|
|
||||||
this.config.drawMode ?? gl.TRIANGLE_STRIP,
|
gl.drawElements(
|
||||||
0,
|
this.config.drawMode ?? gl.TRIANGLES,
|
||||||
this.mesh.config.vertexCount
|
this.mesh.config.faces.length,
|
||||||
|
gl.UNSIGNED_INT,
|
||||||
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// gl.drawArrays(
|
||||||
|
// 0,
|
||||||
|
// this.mesh.config.vertexCount
|
||||||
|
// );
|
||||||
|
|
||||||
const err = gl.getError();
|
const err = gl.getError();
|
||||||
if (err !== 0) {
|
if (err !== 0) {
|
||||||
console.log({ err });
|
console.log({ err });
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
export type MeshConfig = {
|
export type MeshConfig = {
|
||||||
mesh: Float32Array;
|
colors: Uint8Array | null;
|
||||||
positionSize: number;
|
faces: Uint32Array;
|
||||||
colorSize: number;
|
|
||||||
uvSize: number;
|
|
||||||
vertexCount: number;
|
|
||||||
stride: number;
|
|
||||||
name: string;
|
name: string;
|
||||||
|
normals: Float32Array | null;
|
||||||
|
positions: Float32Array;
|
||||||
|
uvs: Float32Array | null;
|
||||||
|
vertexCount: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Mesh {
|
export class Mesh {
|
||||||
|
|
|
@ -12,7 +12,7 @@ export class Renderable extends Behavior {
|
||||||
super(app);
|
super(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdate(time: number) {
|
onDraw(time: number) {
|
||||||
this.renderer.onRenderableUpdate(time, this.transform);
|
this.renderer.onRenderableUpdate(time, this.transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,6 @@ export class Shader {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
this.attach(gl.FRAGMENT_SHADER, this.fragmentCode);
|
this.attach(gl.FRAGMENT_SHADER, this.fragmentCode);
|
||||||
this.attach(gl.VERTEX_SHADER, this.vertexCode);
|
this.attach(gl.VERTEX_SHADER, this.vertexCode);
|
||||||
this.link();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
link() {
|
link() {
|
||||||
|
@ -100,6 +99,9 @@ export class Shader {
|
||||||
model: Transform,
|
model: Transform,
|
||||||
view: Transform
|
view: Transform
|
||||||
) {
|
) {
|
||||||
|
const viewMatrix = view.toMat4();
|
||||||
|
mat4.invert(viewMatrix, viewMatrix);
|
||||||
|
|
||||||
const { gl } = this._app as WebGLApp;
|
const { gl } = this._app as WebGLApp;
|
||||||
gl.useProgram(this._program as WebGLProgram);
|
gl.useProgram(this._program as WebGLProgram);
|
||||||
gl.uniformMatrix4fv(this.uniform("uProjectionMatrix"), false, projection);
|
gl.uniformMatrix4fv(this.uniform("uProjectionMatrix"), false, projection);
|
||||||
|
|
|
@ -7,12 +7,19 @@ export class Transform {
|
||||||
public scale = vec3.fromValues(1, 1, 1)
|
public scale = vec3.fromValues(1, 1, 1)
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
rotateEuler(x: number, y: number, z: number) {
|
||||||
|
quat.fromEuler(this.rotation, x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
toMat4() {
|
toMat4() {
|
||||||
return mat4.fromRotationTranslationScale(
|
const mat = mat4.create();
|
||||||
mat4.create(),
|
mat4.fromRotationTranslationScale(
|
||||||
|
mat,
|
||||||
this.rotation,
|
this.rotation,
|
||||||
this.position,
|
this.position,
|
||||||
this.scale
|
this.scale
|
||||||
);
|
);
|
||||||
|
return mat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,13 @@ export class WebGLApp {
|
||||||
onAfterUpdate: RenderHandle[];
|
onAfterUpdate: RenderHandle[];
|
||||||
onUpdate: RenderHandle[];
|
onUpdate: RenderHandle[];
|
||||||
onStart: RenderHandle[];
|
onStart: RenderHandle[];
|
||||||
|
onDraw: RenderHandle[];
|
||||||
} = {
|
} = {
|
||||||
onBeforeUpdate: [],
|
onBeforeUpdate: [],
|
||||||
onAfterUpdate: [],
|
onAfterUpdate: [],
|
||||||
onUpdate: [],
|
onUpdate: [],
|
||||||
onStart: [],
|
onStart: [],
|
||||||
|
onDraw: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(public config: WebGPUAppConfig = {}) {
|
constructor(public config: WebGPUAppConfig = {}) {
|
||||||
|
@ -36,7 +38,10 @@ export class WebGLApp {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error("Canvas was unable to get a webgl2 context");
|
throw new Error("Canvas was unable to get a webgl2 context");
|
||||||
}
|
}
|
||||||
this.gl = context;
|
const gl = (this.gl = context);
|
||||||
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||||
|
|
||||||
|
// this.gl.getExtension("OES_element_index_uint"); // default
|
||||||
|
|
||||||
if (location.search.includes("telemetry")) {
|
if (location.search.includes("telemetry")) {
|
||||||
this.telemetry = new Telemetry(this);
|
this.telemetry = new Telemetry(this);
|
||||||
|
@ -53,6 +58,10 @@ export class WebGLApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get aspect() {
|
||||||
|
return this.canvas.clientWidth / this.canvas.clientHeight;
|
||||||
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
|
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
|
||||||
|
@ -78,16 +87,16 @@ export class WebGLApp {
|
||||||
this.registry.onStart.push(handle);
|
this.registry.onStart.push(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
doUpdate(time: number) {
|
onDraw(handle: RenderHandle) {
|
||||||
// this.jobsToSubmitThisFrame = [];
|
this.registry.onDraw.push(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
doUpdate(time: number) {
|
||||||
this.registry.onBeforeUpdate.forEach((handle) => handle(time, this));
|
this.registry.onBeforeUpdate.forEach((handle) => handle(time, this));
|
||||||
this.registry.onUpdate.forEach((handle) => handle(time, this));
|
this.registry.onUpdate.forEach((handle) => handle(time, this));
|
||||||
this.registry.onAfterUpdate.forEach((handle) => handle(time, this));
|
this.registry.onAfterUpdate.forEach((handle) => handle(time, this));
|
||||||
|
|
||||||
// if (this.jobsToSubmitThisFrame.length !== 0) {
|
this.registry.onDraw.forEach((handle) => handle(time, this));
|
||||||
// this.device.queue.submit(this.jobsToSubmitThisFrame);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doStart(time: number = 0) {
|
doStart(time: number = 0) {
|
||||||
|
@ -96,15 +105,11 @@ export class WebGLApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
async oneShot(time: number = 0) {
|
async oneShot(time: number = 0) {
|
||||||
// await this.awaitRendererReady();
|
|
||||||
|
|
||||||
this.doStart(time);
|
this.doStart(time);
|
||||||
this.doUpdate(time);
|
this.doUpdate(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
// await this.awaitRendererReady();
|
|
||||||
|
|
||||||
this.doStart();
|
this.doStart();
|
||||||
|
|
||||||
const run = (time: number) => {
|
const run = (time: number) => {
|
||||||
|
@ -113,8 +118,4 @@ export class WebGLApp {
|
||||||
};
|
};
|
||||||
requestAnimationFrame(run);
|
requestAnimationFrame(run);
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit(commandEncoder: GPUCommandBuffer) {
|
|
||||||
// this.jobsToSubmitThisFrame.push(commandEncoder);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue