This commit is contained in:
Tony Garnock-Jones 2023-01-10 22:04:38 +01:00
parent b82fdea3c4
commit a03269603a
4 changed files with 120 additions and 32 deletions

View File

@ -42,10 +42,13 @@ Touchable = <touchable @shape Shape> .
CSG = <csg @expr CSGExpr> .
CSGExpr =
/ <mesh @shape Shape>
/ <subtract @base CSGExpr @more [CSGExpr ...]>
/ <union @shapes [CSGExpr ...]>
/ <intersect @shapes [CSGExpr ...]>
/ <mesh @shape Mesh>
/ <scale @v Vector3 @shape CSGExpr>
/ <move @v Vector3 @shape CSGExpr>
/ <rotate @v Vector3 @shape CSGExpr>
/ <subtract [@base CSGExpr @more CSGExpr ...]>
/ <union [@base CSGExpr @more CSGExpr ...]>
/ <intersect [@base CSGExpr @more CSGExpr ...]>
/ <invert @shape CSGExpr>
.

View File

@ -66,7 +66,28 @@
<color 0.5 0.5 0.0
<box>>>>>>>
<sprite "house"
<scale <v 10.0 4.0 15.0>
<floor
<move <v 1.5 0.5 -0.5> <box>>>>>
<sprite "x"
<move <v 10.0 1.6 -5.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 1.0 3.0 1.0>
<v 0.0 0.0 0.0>]
<csg
<subtract [
<move <v 0.0 0.0 0.5> <scale <v 1.1 3.1 1.1> <mesh <box>>>>
<move <v 0.0 0.0 0.5> <scale <v 1.0 3.0 1.0> <mesh <box>>>>
]>
>
>>>
<sprite "y"
<move <v 12.0 0.75 -5.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 1.0 1.0 1.0>
<v 0.0 0.0 0.0>]
<csg
<intersect [
<scale <v 0.5 1.0 0.5> <mesh <box>>>
<mesh <sphere>>
]>
>
>>>

View File

@ -17,3 +17,16 @@
<touchable <move <v 0.0 0.5 0.0> <plane>>>>>
<scale <v 1.0 2.11 0.1> <move <v 0.0 0.5 0.6> <box>>>
]>>>
<sprite "x"
<move <v 0.0 0.0 10.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 1.0 3.0 1.0>
<v 0.0 0.0 0.0>]
<csg
<subtract [
<move <v 0.0 0.0 0.5> <scale <v 1.1 3.1 1.1> <mesh <box>>>>
<move <v 0.0 0.0 0.5> <scale <v 1.0 3.0 1.0> <mesh <box>>>>
]>
>
>>>

View File

@ -4,6 +4,7 @@ import {
CSG,
HemisphericLight,
Material,
Matrix,
Mesh,
MeshBuilder,
Node,
@ -177,32 +178,22 @@ function releaseTexture(entry: CachedTexture) {
}
}
export function buildMesh(name: string, scene: Scene | null, meshSpec: Shapes.Mesh): Mesh {
switch (meshSpec._variant) {
case "Sphere": return MeshBuilder.CreateSphere(name, {}, scene);
case "Box": return MeshBuilder.CreateBox(name, {}, scene);
case "Ground": {
const v = v2(meshSpec.value.size);
return MeshBuilder.CreateGround(name, { width: v.x, height: v.y }, scene ?? void 0);
}
case "Plane": return MeshBuilder.CreatePlane(name, {}, scene);
}
}
export function build(name: string, scene: Scene, shape: Shapes.Shape, customize: MeshCustomizer): ShapeTree {
switch (shape._variant) {
case "Mesh": {
const mesh = shape.value;
let t: ShapeTree<Mesh>;
switch (mesh._variant) {
case "Sphere":
t = new ShapeTree<Mesh>(scene, shape, MeshBuilder.CreateSphere(name, {}, scene));
break;
case "Box":
t = new ShapeTree<Mesh>(scene, shape, MeshBuilder.CreateBox(name, {}, scene));
break;
case "Ground": {
const v = v2(mesh.value.size);
t = new ShapeTree(
scene,
shape,
MeshBuilder.CreateGround(name, { width: v.x, height: v.y }, scene));
break;
}
case "Plane":
t = new ShapeTree<Mesh>(scene, shape, MeshBuilder.CreatePlane(name, {}, scene));
break;
}
const t = new ShapeTree<Mesh>(scene, shape, buildMesh(name, scene, shape.value));
applyCustomizer(t, customize);
return t;
}
@ -307,7 +298,10 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
});
case "CSG": {
throw new Error("unimplemented");
const t = new ShapeTree<Mesh>(
scene, shape, buildCSG(shape.value.expr).toMesh(name, null, scene));
applyCustomizer(t, customize);
return t;
}
case "Skybox": {
@ -331,6 +325,63 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
}
}
function emptyCSG(): CSG {
const c = new CSG();
c.matrix = Matrix.Identity();
c.position = Vector3.Zero();
c.rotation = Vector3.Zero();
c.scaling = Vector3.Zero();
c.rotationQuaternion = null;
return c;
}
export function buildCSG(expr: Shapes.CSGExpr): CSG {
function walk(expr: Shapes.CSGExpr, matrix: Matrix): CSG {
switch (expr._variant) {
case "mesh": {
const mesh = buildMesh("", null, expr.shape);
mesh.freezeWorldMatrix(matrix, true);
mesh.unfreezeWorldMatrix();
const c = CSG.FromMesh(mesh);
mesh.dispose();
return c;
}
case "scale":
return walk(expr.shape, matrix.multiply(
Matrix.Scaling(expr.v.x, expr.v.y, expr.v.z)));
case "move":
return walk(expr.shape, matrix.multiply(
Matrix.Translation(expr.v.x, expr.v.y, expr.v.z)));
case "rotate":
return walk(expr.shape, matrix.multiply(
Matrix.RotationYawPitchRoll(expr.v.y * 2 * Math.PI,
expr.v.x * 2 * Math.PI,
expr.v.z * 2 * Math.PI)));
case "subtract": {
let c = walk(expr.base, matrix);
expr.more.forEach(d => c.subtractInPlace(walk(d, matrix)));
return c;
}
case "union": {
let c = walk(expr.base, matrix);
expr.more.forEach(d => c.unionInPlace(walk(d, matrix)));
return c;
}
case "intersect": {
let c = walk(expr.base, matrix);
expr.more.forEach(d => c.intersectInPlace(walk(d, matrix)));
return c;
}
case "invert": {
let c = walk(expr.shape, matrix);
c.inverseInPlace();
return c;
}
}
}
return walk(expr, Matrix.Identity());
}
export const builder: { [key: string]: (... args: any[]) => Shapes.Shape } = {
sphere: () => Shapes.Shape.Mesh(Shapes.Mesh.Sphere(Shapes.Sphere())),
box: () => Shapes.Shape.Mesh(Shapes.Mesh.Box(Shapes.Box())),