003 fucking RENDERS models YAAAAAAAAA
This commit is contained in:
parent
28faa03ac6
commit
23d7810ab6
30 changed files with 16955 additions and 221 deletions
|
@ -11,6 +11,9 @@ mkdirSync("html");
|
|||
|
||||
const works = globSync("src/*/main.ts");
|
||||
|
||||
console.log(chalk.green`>> Convert meshes ...`);
|
||||
await convertMeshes();
|
||||
|
||||
console.log(chalk.green`>> Building ...`);
|
||||
console.log(chalk.yellow(` Found ${works.length} works.`));
|
||||
console.log(chalk.yellow(` Running Bun.build()`));
|
||||
|
@ -44,6 +47,3 @@ const { stdout, stderr, exitCode } = Bun.spawnSync([
|
|||
"-c",
|
||||
"cp -r src/public/* html/",
|
||||
]);
|
||||
|
||||
console.log(chalk.green`>> Convert meshes ...`);
|
||||
await convertMeshes();
|
||||
|
|
|
@ -1,6 +1,54 @@
|
|||
import chalk from "chalk";
|
||||
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 () => {
|
||||
const meshes = globSync("src/meshes/*.ply");
|
||||
|
||||
|
@ -8,8 +56,47 @@ export const convertMeshes = async () => {
|
|||
const ply = await Bun.file(file).text();
|
||||
|
||||
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");
|
||||
|
||||
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(
|
||||
headerLines
|
||||
.find((header) => header.startsWith("element vertex"))
|
||||
|
@ -20,49 +107,152 @@ export const convertMeshes = async () => {
|
|||
throw new Error("couldn't get vertex count...");
|
||||
}
|
||||
|
||||
const values: number[] = [];
|
||||
const vertexes: Vertex[] = [];
|
||||
const faces: Face[] = [];
|
||||
|
||||
for (const line of body.split("\n")) {
|
||||
// line looks like
|
||||
// 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 components = line.split(" ");
|
||||
|
||||
const [x, y, z, r, g, b, a, u, v] = line.split(" ");
|
||||
|
||||
if (!g) {
|
||||
if (!components || !components[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
values.push(
|
||||
parseFloat(x),
|
||||
parseFloat(y),
|
||||
parseFloat(z),
|
||||
1,
|
||||
parseFloat(r),
|
||||
parseFloat(g)
|
||||
);
|
||||
// do we only have 4 components?
|
||||
if (components[0] === "3" || components.length === 4) {
|
||||
const [, a, b, c] = components;
|
||||
|
||||
if (colorSize > 0) {
|
||||
values.push(parseFloat(b), parseFloat(a), parseFloat(u), parseFloat(v));
|
||||
// We do??!?! 🥺👉👈
|
||||
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 outString = `
|
||||
import { Mesh } from "../renderer/mesh";
|
||||
|
||||
// prettier-ignore
|
||||
const mesh = new Float32Array(${JSON.stringify(values)});
|
||||
const positions = new Float32Array(${JSON.stringify(positions)});
|
||||
|
||||
export default new Mesh({
|
||||
mesh,
|
||||
positionSize: 4,
|
||||
colorSize: ${colorSize},
|
||||
uvSize: 2,
|
||||
vertexCount: ${vertexCount},
|
||||
stride: ${4 + colorSize + 2},
|
||||
name: ${JSON.stringify(file)}
|
||||
// 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({
|
||||
colors,
|
||||
faces,
|
||||
name: ${JSON.stringify(file)},
|
||||
normals,
|
||||
positions,
|
||||
uvs,
|
||||
vertexCount: ${vertexCount}
|
||||
});
|
||||
`;
|
||||
|
||||
|
@ -70,3 +260,8 @@ export default new Mesh({
|
|||
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
|
||||
|
||||
- The "generator" does
|
||||
- **Output generation**
|
||||
|
||||
- Generates a work list from .js files within `html`
|
||||
- Creates this README.md file
|
||||
- Creates the index.html file
|
||||
- Creates individual HTML files for each work
|
||||
- Bun renders TypeScript and GLSL to html/
|
||||
- src/public/ is copied to html/
|
||||
- This doubles as an "archival" system to preserve scuffedness
|
||||
- .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
|
||||
- Shader types
|
||||
- Primitive objects
|
||||
- A canvas to draw on
|
||||
- WebGL hooks
|
||||
- Helpers, etc
|
||||
- **Platform**
|
||||
|
||||
- WebGLApp provides render loop, canvas, and other stuff
|
||||
- Behavior provides automatic registration of WebGLApp events (like Unity MonoBehaviors)
|
||||
- Shader provides GLSL shader tooling
|
||||
- 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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue