diff --git a/src/lib/exports.ts b/src/lib/exports.ts index 86ba9e42..e8369382 100644 --- a/src/lib/exports.ts +++ b/src/lib/exports.ts @@ -1,2 +1,3 @@ export { Terrain } from './terrain/terrain' export type { IVoxelMap, IVoxel, IVoxelMaterial } from './terrain/i-voxel-map' +export { ENeighbour } from './terrain/i-voxel-map' diff --git a/src/lib/terrain/i-voxel-map.ts b/src/lib/terrain/i-voxel-map.ts index 87c2dd8d..1fabc26b 100644 --- a/src/lib/terrain/i-voxel-map.ts +++ b/src/lib/terrain/i-voxel-map.ts @@ -17,12 +17,42 @@ interface IVoxelMaterial { readonly color: Color } +enum ENeighbour { + xMyMzM, // whether or not there is a neighbour voxel at coords { X - 1, Y - 1, Z - 1 } + xMyMz0, // whether or not there is a neighbour voxel at coords { X - 1, Y - 1, Z } + xMyMzP, // whether or not there is a neighbour voxel at coords { X - 1, Y - 1, Z + 1 } + xMy0zM, // whether or not there is a neighbour voxel at coords { X - 1, Y , Z - 1 } + xMy0z0, // whether or not there is a neighbour voxel at coords { X - 1, Y , Z } + xMy0zP, // whether or not there is a neighbour voxel at coords { X - 1, Y , Z + 1 } + xMyPzM, // whether or not there is a neighbour voxel at coords { X - 1, Y + 1, Z - 1 } + xMyPz0, // whether or not there is a neighbour voxel at coords { X - 1, Y + 1, Z } + xMyPzP, // whether or not there is a neighbour voxel at coords { X - 1, Y + 1, Z + 1 } + x0yMzM, // whether or not there is a neighbour voxel at coords { X , Y - 1, Z - 1 } + x0yMz0, // whether or not there is a neighbour voxel at coords { X , Y - 1, Z } + x0yMzP, // whether or not there is a neighbour voxel at coords { X , Y - 1, Z + 1 } + x0y0zM, // whether or not there is a neighbour voxel at coords { X , Y , Z - 1 } + x0y0zP, // whether or not there is a neighbour voxel at coords { X , Y , Z + 1 } + x0yPzM, // whether or not there is a neighbour voxel at coords { X , Y + 1, Z - 1 } + x0yPz0, // whether or not there is a neighbour voxel at coords { X , Y + 1, Z } + x0yPzP, // whether or not there is a neighbour voxel at coords { X , Y + 1, Z + 1 } + xPyMzM, // whether or not there is a neighbour voxel at coords { X + 1, Y - 1, Z - 1 } + xPyMz0, // whether or not there is a neighbour voxel at coords { X + 1, Y - 1, Z } + xPyMzP, // whether or not there is a neighbour voxel at coords { X + 1, Y - 1, Z + 1 } + xPy0zM, // whether or not there is a neighbour voxel at coords { X + 1, Y , Z - 1 } + xPy0z0, // whether or not there is a neighbour voxel at coords { X + 1, Y , Z } + xPy0zP, // whether or not there is a neighbour voxel at coords { X + 1, Y , Z + 1 } + xPyPzM, // whether or not there is a neighbour voxel at coords { X + 1, Y + 1, Z - 1 } + xPyPz0, // whether or not there is a neighbour voxel at coords { X + 1, Y + 1, Z } + xPyPzP, // whether or not there is a neighbour voxel at coords { X + 1, Y + 1, Z + 1 } +} + /** * A representation of a voxel. */ interface IVoxel { readonly position: Uint3 readonly materialId: number + readonly neighbours: Record; } /** @@ -58,11 +88,7 @@ interface IVoxelMap { * @param to End of the subsection (exclusive) */ iterateOnVoxels(from: Uint3, to: Uint3): Generator - - /** - * @returns whether or not a voxel exists at these coordinates. - */ - voxelExists(x: number, y: number, z: number): boolean } -export type { IVoxel, IVoxelMap, IVoxelMaterial } +export type { IVoxel, IVoxelMap, IVoxelMaterial }; +export { ENeighbour }; diff --git a/src/lib/terrain/patch/patch-factory/cube.ts b/src/lib/terrain/patch/patch-factory/cube.ts index 67292d15..cc5b6bec 100644 --- a/src/lib/terrain/patch/patch-factory/cube.ts +++ b/src/lib/terrain/patch/patch-factory/cube.ts @@ -1,4 +1,5 @@ import * as THREE from '../../../three-usage' +import { ENeighbour } from '../../i-voxel-map' const vertices = { ppp: new THREE.Vector3(1, 1, 1), @@ -12,14 +13,10 @@ const vertices = { } type FaceVertex = { readonly vertex: THREE.Vector3 - readonly shadowingNeighbourVoxels: [ - THREE.Vector3, - THREE.Vector3, - THREE.Vector3, - ] + readonly shadowingNeighbourVoxels: [ENeighbour, ENeighbour, ENeighbour] readonly edgeNeighbourVoxels: { - readonly x: [THREE.Vector3, THREE.Vector3] - readonly y: [THREE.Vector3, THREE.Vector3] + readonly x: [ENeighbour, ENeighbour] + readonly y: [ENeighbour, ENeighbour] } } @@ -41,6 +38,7 @@ type Face = { readonly normal: THREE.Vector3 readonly uvUp: THREE.Vector3 readonly uvRight: THREE.Vector3 + readonly facingNeighbour: ENeighbour; } const faceIndices: [number, number, number, number, number, number] = [ @@ -62,6 +60,24 @@ function buildFace( const uvLeft = uvRight.clone().multiplyScalar(-1) const uvDown = uvUp.clone().multiplyScalar(-1) + const getValueCode = (value: number): string => { + if (value === -1) { + return "M"; + } else if (value === 1) { + return "P"; + } + return "0"; + }; + + const getNeighbourCode = (vec3: THREE.Vector3): ENeighbour => { + const key = `x${getValueCode(vec3.x)}y${getValueCode(vec3.y)}z${getValueCode(vec3.z)}`; + const result = ENeighbour[key as any]; + if (typeof result === "undefined"){ + throw new Error("Should not happen"); + } + return result as unknown as ENeighbour; + }; + return { id: iF++, type, @@ -69,55 +85,56 @@ function buildFace( { vertex: v00, shadowingNeighbourVoxels: [ - new THREE.Vector3().subVectors(normal, uvRight), - new THREE.Vector3().subVectors(normal, uvUp), - new THREE.Vector3().subVectors(normal, uvRight).sub(uvUp), + getNeighbourCode(new THREE.Vector3().subVectors(normal, uvRight)), + getNeighbourCode(new THREE.Vector3().subVectors(normal, uvUp)), + getNeighbourCode(new THREE.Vector3().subVectors(normal, uvRight).sub(uvUp)), ], edgeNeighbourVoxels: { - x: [uvLeft, new THREE.Vector3().addVectors(uvLeft, normal)], - y: [uvDown, new THREE.Vector3().addVectors(uvDown, normal)], + x: [getNeighbourCode(uvLeft), getNeighbourCode(new THREE.Vector3().addVectors(uvLeft, normal))], + y: [getNeighbourCode(uvDown), getNeighbourCode(new THREE.Vector3().addVectors(uvDown, normal))], }, }, { vertex: v01, shadowingNeighbourVoxels: [ - new THREE.Vector3().subVectors(normal, uvRight), - new THREE.Vector3().addVectors(normal, uvUp), - new THREE.Vector3().subVectors(normal, uvRight).add(uvUp), + getNeighbourCode(new THREE.Vector3().subVectors(normal, uvRight)), + getNeighbourCode(new THREE.Vector3().addVectors(normal, uvUp)), + getNeighbourCode(new THREE.Vector3().subVectors(normal, uvRight).add(uvUp)), ], edgeNeighbourVoxels: { - x: [uvLeft, new THREE.Vector3().addVectors(uvLeft, normal)], - y: [uvUp, new THREE.Vector3().addVectors(uvUp, normal)], + x: [getNeighbourCode(uvLeft), getNeighbourCode(new THREE.Vector3().addVectors(uvLeft, normal))], + y: [getNeighbourCode(uvUp), getNeighbourCode(new THREE.Vector3().addVectors(uvUp, normal))], }, }, { vertex: v10, shadowingNeighbourVoxels: [ - new THREE.Vector3().addVectors(normal, uvRight), - new THREE.Vector3().subVectors(normal, uvUp), - new THREE.Vector3().addVectors(normal, uvRight).sub(uvUp), + getNeighbourCode(new THREE.Vector3().addVectors(normal, uvRight)), + getNeighbourCode(new THREE.Vector3().subVectors(normal, uvUp)), + getNeighbourCode(new THREE.Vector3().addVectors(normal, uvRight).sub(uvUp)), ], edgeNeighbourVoxels: { - x: [uvRight, new THREE.Vector3().addVectors(uvRight, normal)], - y: [uvDown, new THREE.Vector3().addVectors(uvDown, normal)], + x: [getNeighbourCode(uvRight), getNeighbourCode(new THREE.Vector3().addVectors(uvRight, normal))], + y: [getNeighbourCode(uvDown), getNeighbourCode(new THREE.Vector3().addVectors(uvDown, normal))], }, }, { vertex: v11, shadowingNeighbourVoxels: [ - new THREE.Vector3().addVectors(normal, uvRight), - new THREE.Vector3().addVectors(normal, uvUp), - new THREE.Vector3().addVectors(normal, uvRight).add(uvUp), + getNeighbourCode(new THREE.Vector3().addVectors(normal, uvRight)), + getNeighbourCode(new THREE.Vector3().addVectors(normal, uvUp)), + getNeighbourCode(new THREE.Vector3().addVectors(normal, uvRight).add(uvUp)), ], edgeNeighbourVoxels: { - x: [uvRight, new THREE.Vector3().addVectors(uvRight, normal)], - y: [uvUp, new THREE.Vector3().addVectors(uvUp, normal)], + x: [getNeighbourCode(uvRight), getNeighbourCode(new THREE.Vector3().addVectors(uvRight, normal))], + y: [getNeighbourCode(uvUp), getNeighbourCode(new THREE.Vector3().addVectors(uvUp, normal))], }, }, ], normal, uvUp, uvRight, + facingNeighbour: getNeighbourCode(normal), } } diff --git a/src/lib/terrain/patch/patch-factory/patch-factory-base.ts b/src/lib/terrain/patch/patch-factory/patch-factory-base.ts index 8b49394e..75a067c2 100644 --- a/src/lib/terrain/patch/patch-factory/patch-factory-base.ts +++ b/src/lib/terrain/patch/patch-factory/patch-factory-base.ts @@ -134,13 +134,7 @@ abstract class PatchFactoryBase { ) for (const face of Object.values(Cube.faces)) { - if ( - this.map.voxelExists( - voxelWorldPosition.x + face.normal.x, - voxelWorldPosition.y + face.normal.y, - voxelWorldPosition.z + face.normal.z, - ) - ) { + if (voxel.neighbours[face.facingNeighbour]) { // this face will be hidden -> skip it continue } @@ -155,12 +149,7 @@ abstract class PatchFactoryBase { (faceVertex: Cube.FaceVertex): VertexData => { let ao = 0 const [a, b, c] = faceVertex.shadowingNeighbourVoxels.map( - neighbourVoxel => - this.map.voxelExists( - voxelWorldPosition.x + neighbourVoxel.x, - voxelWorldPosition.y + neighbourVoxel.y, - voxelWorldPosition.z + neighbourVoxel.z, - ), + neighbourVoxel => voxel.neighbours[neighbourVoxel] ) as [boolean, boolean, boolean] if (a && b) { ao = 3 @@ -172,18 +161,10 @@ abstract class PatchFactoryBase { let roundnessY = true if (faceVertex.edgeNeighbourVoxels) { for (const neighbourVoxel of faceVertex.edgeNeighbourVoxels.x) { - roundnessX &&= !this.map.voxelExists( - voxelWorldPosition.x + neighbourVoxel.x, - voxelWorldPosition.y + neighbourVoxel.y, - voxelWorldPosition.z + neighbourVoxel.z, - ) + roundnessX &&= !voxel.neighbours[neighbourVoxel]; } for (const neighbourVoxel of faceVertex.edgeNeighbourVoxels.y) { - roundnessY &&= !this.map.voxelExists( - voxelWorldPosition.x + neighbourVoxel.x, - voxelWorldPosition.y + neighbourVoxel.y, - voxelWorldPosition.z + neighbourVoxel.z, - ) + roundnessY &&= !voxel.neighbours[neighbourVoxel]; } } return { diff --git a/src/test/voxel-map.ts b/src/test/voxel-map.ts index beb803b4..b5ba1092 100644 --- a/src/test/voxel-map.ts +++ b/src/test/voxel-map.ts @@ -94,9 +94,41 @@ class VoxelMap implements AresRpgEngine.IVoxelMap { if (voxel) { position.y = voxel.y if (from.y <= position.y && position.y < to.y) { + const neighbours: Record = [ + this.voxelExists(position.x - 1, position.y - 1, position.z - 1), + this.voxelExists(position.x - 1, position.y - 1, position.z + 0), + this.voxelExists(position.x - 1, position.y - 1, position.z + 1), + this.voxelExists(position.x - 1, position.y + 0, position.z - 1), + this.voxelExists(position.x - 1, position.y + 0, position.z + 0), + this.voxelExists(position.x - 1, position.y + 0, position.z + 1), + this.voxelExists(position.x - 1, position.y + 1, position.z - 1), + this.voxelExists(position.x - 1, position.y + 1, position.z + 0), + this.voxelExists(position.x - 1, position.y + 1, position.z + 1), + + this.voxelExists(position.x + 0, position.y - 1, position.z - 1), + this.voxelExists(position.x + 0, position.y - 1, position.z + 0), + this.voxelExists(position.x + 0, position.y - 1, position.z + 1), + this.voxelExists(position.x + 0, position.y + 0, position.z - 1), + this.voxelExists(position.x + 0, position.y + 0, position.z + 1), + this.voxelExists(position.x + 0, position.y + 1, position.z - 1), + this.voxelExists(position.x + 0, position.y + 1, position.z + 0), + this.voxelExists(position.x + 0, position.y + 1, position.z + 1), + + this.voxelExists(position.x + 1, position.y - 1, position.z - 1), + this.voxelExists(position.x + 1, position.y - 1, position.z + 0), + this.voxelExists(position.x + 1, position.y - 1, position.z + 1), + this.voxelExists(position.x + 1, position.y + 0, position.z - 1), + this.voxelExists(position.x + 1, position.y + 0, position.z + 0), + this.voxelExists(position.x + 1, position.y + 0, position.z + 1), + this.voxelExists(position.x + 1, position.y + 1, position.z - 1), + this.voxelExists(position.x + 1, position.y + 1, position.z + 0), + this.voxelExists(position.x + 1, position.y + 1, position.z + 1), + ]; + yield { position, materialId: voxel.type, + neighbours, } } } @@ -104,7 +136,7 @@ class VoxelMap implements AresRpgEngine.IVoxelMap { } } - public voxelExists(x: number, y: number, z: number): boolean { + private voxelExists(x: number, y: number, z: number): boolean { const voxel = this.getVoxel(x, z) return voxel?.y === y }