From 25626984412dfb70a6a9567d0aa395fb88277c9f Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Tue, 30 Jan 2024 08:19:10 +0100 Subject: [PATCH 01/10] Implement basic DistanceField class The distance fields are not being calculated, yet. --- src/game/util/Matrix3d.ts | 4 ++ src/game/world/raymarcher/DistanceField.ts | 68 ++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/game/world/raymarcher/DistanceField.ts diff --git a/src/game/util/Matrix3d.ts b/src/game/util/Matrix3d.ts index 38bd683..ce0fd25 100644 --- a/src/game/util/Matrix3d.ts +++ b/src/game/util/Matrix3d.ts @@ -12,6 +12,10 @@ export class Matrix3d { this.data = new Uint8Array(width * height * depth).fill(defaultValue) } + fill(value: number) { + this.data.fill(value) + } + get(x: number, y: number, z: number) { return this.data[this.getIndex(x, y, z)] } diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts new file mode 100644 index 0000000..fd69753 --- /dev/null +++ b/src/game/world/raymarcher/DistanceField.ts @@ -0,0 +1,68 @@ +import { Matrix3d } from "../../util/Matrix3d" + +export class DistanceField extends Matrix3d { + static sweepDirections = [ + { dx: 1, dy: 0, dz: 0 }, + { dx: -1, dy: 0, dz: 0 }, + { dx: 0, dy: 1, dz: 0 }, + { dx: 0, dy: -1, dz: 0 }, + { dx: 0, dy: 0, dz: 1 }, + { dx: 0, dy: 0, dz: -1 }, + ] + + constructor(public voxelData: Matrix3d, public resolutionFactor: number) { + super(voxelData.width * resolutionFactor, voxelData.height * resolutionFactor, voxelData.depth * resolutionFactor) + } + + calculateDistanceField() { + this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) + + // DistanceField.sweepDirections.forEach(direction => { + // const { dx, dy, dz } = direction + // }) + + const y = 16 + + let steps = 0 + for (let z = 0; z < this.depth; z++) { + for (let x = 0; x < this.width; x++) { + steps++ + + if (this.isVoxelEmpty(x, y, z)) { + // TODO: fix + } + } + } + } + + isVoxelEmpty(x: number, y: number, z: number) { + return this.getVoxelAt(x, y, z) === 0 + } + + getVoxelAt(x: number, y: number, z: number) { + return this.voxelData.get( + Math.floor(x / this.resolutionFactor), + Math.floor(y / this.resolutionFactor), + Math.floor(z / this.resolutionFactor), + ) + } + + + getTexture() { + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') + if (!ctx) throw new Error('Ctx could not be retrieved') + + for (let x = 0; x < this.width; x++) { + for (let y = 0; y < this.height; y++) { + for (let z = 0; z < this.depth; z++) { + const value = this.get(x, y, z) + ctx.fillStyle = `rgba(${value}, ${value}, ${value})` + ctx.fillRect(x, y, 1, 1) + } + } + } + + return canvas.toDataURL() + } +} From b586546919eaa1c33c0cc98e6cf73fe93ccdf452 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Tue, 30 Jan 2024 20:52:07 +0100 Subject: [PATCH 02/10] Prepare test chunk --- src/game/main.ts | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/game/main.ts b/src/game/main.ts index 6f70561..1ec359f 100644 --- a/src/game/main.ts +++ b/src/game/main.ts @@ -14,34 +14,25 @@ export default class Game implements Experience { @Benchmark init(): void { const terrainGenerator = new TerrainGenerator(69420) - const chunkManager = new ChunkManager(terrainGenerator, 8, 2, 8) + const chunkManager = new ChunkManager(terrainGenerator, 0, 0, 0) - const chunks = chunkManager.createChunksAroundOrigin(0, 0, 0) + const chunks = chunkManager.createChunksAroundOrigin(0, -1, 0) const workerPath = './src/game/world/workers/TerrainGenerationWorker.ts' - const workerCount = navigator.hardwareConcurrency + const workerManager = new WorkerManager(workerPath, 1) - const workerManager = new WorkerManager(workerPath, workerCount) + const chunk = chunks[0] + this.engine.scene.add(chunk.mesh) - chunks.forEach((chunk) => { - this.engine.scene.add(chunk.mesh) + const task = chunk.prepareGeneratorWorkerData() - const task = chunk.prepareGeneratorWorkerData() - - workerManager.enqueueTask({ - payload: task.payload, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - callback: (args: any) => { - task.callback(args) - requestAnimationFrame(() => chunk.updateMeshGeometry()) - } - }) - }) - - chunks.forEach((chunk) => { - setTimeout(() => { + workerManager.enqueueTask({ + payload: task.payload, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + callback: (args: any) => { + task.callback(args) chunk.updateMeshGeometry() - }, Math.random()) + } }) } From 94f0a6d6776f74abc0fdd8491bba4410d890305b Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Tue, 30 Jan 2024 21:10:49 +0100 Subject: [PATCH 03/10] Implement visualization of chunk layer --- src/game/main.ts | 11 ++++++++++ src/game/world/raymarcher/DistanceField.ts | 25 ++++++++++++---------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/game/main.ts b/src/game/main.ts index 1ec359f..b00fa40 100644 --- a/src/game/main.ts +++ b/src/game/main.ts @@ -4,6 +4,7 @@ import { Resource } from '../engine/Resources' import { Benchmark } from './utilities/Benchmark' import { ChunkManager } from './world/ChunkManager' import { TerrainGenerator } from './world/TerrainGenerator' +import { DistanceField } from './world/raymarcher/DistanceField' import { WorkerManager } from './world/workers/WorkerManager' export default class Game implements Experience { @@ -32,6 +33,16 @@ export default class Game implements Experience { callback: (args: any) => { task.callback(args) chunk.updateMeshGeometry() + + const distanceField = new DistanceField(chunk.chunkData.data, 1, 20) + distanceField.calculateDistanceField() + + const src = distanceField.getTexture() + const image = new Image() + image.src = src + + document.body.appendChild(image) + image.setAttribute('style', 'position: absolute; height: 50%; left: 0; top: 0; border: 1px solid red;') } }) } diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index fd69753..52e6f31 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -10,26 +10,27 @@ export class DistanceField extends Matrix3d { { dx: 0, dy: 0, dz: -1 }, ] - constructor(public voxelData: Matrix3d, public resolutionFactor: number) { + constructor(public voxelData: Matrix3d, public resolutionFactor: number, public yLevel: number) { super(voxelData.width * resolutionFactor, voxelData.height * resolutionFactor, voxelData.depth * resolutionFactor) } calculateDistanceField() { - this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) + // this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) // DistanceField.sweepDirections.forEach(direction => { // const { dx, dy, dz } = direction // }) - const y = 16 + const y = this.yLevel let steps = 0 for (let z = 0; z < this.depth; z++) { for (let x = 0; x < this.width; x++) { - steps++ - if (this.isVoxelEmpty(x, y, z)) { + this.set(x, y, z, 0) // TODO: fix + } else { + this.set(x, y, z, 1) } } } @@ -50,16 +51,18 @@ export class DistanceField extends Matrix3d { getTexture() { const canvas = document.createElement('canvas') + canvas.width = this.width + canvas.height = this.depth const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Ctx could not be retrieved') + const y = this.yLevel + for (let x = 0; x < this.width; x++) { - for (let y = 0; y < this.height; y++) { - for (let z = 0; z < this.depth; z++) { - const value = this.get(x, y, z) - ctx.fillStyle = `rgba(${value}, ${value}, ${value})` - ctx.fillRect(x, y, 1, 1) - } + for (let z = 0; z < this.depth; z++) { + const value = this.get(x, y, z) * 255 + ctx.fillStyle = `rgba(${value}, ${value}, ${value})` + ctx.fillRect(x, z, 1, 1) } } From 9fb4d01d5da01d741c2707eba354aa44f8d31cc9 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Tue, 30 Jan 2024 21:29:41 +0100 Subject: [PATCH 04/10] Implement distance field for +x direction --- src/game/main.ts | 6 +++--- src/game/world/raymarcher/DistanceField.ts | 25 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/game/main.ts b/src/game/main.ts index b00fa40..ea9e3a5 100644 --- a/src/game/main.ts +++ b/src/game/main.ts @@ -32,9 +32,9 @@ export default class Game implements Experience { // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (args: any) => { task.callback(args) - chunk.updateMeshGeometry() + // chunk.updateMeshGeometry() - const distanceField = new DistanceField(chunk.chunkData.data, 1, 20) + const distanceField = new DistanceField(chunk.chunkData.data, 4, 20) distanceField.calculateDistanceField() const src = distanceField.getTexture() @@ -42,7 +42,7 @@ export default class Game implements Experience { image.src = src document.body.appendChild(image) - image.setAttribute('style', 'position: absolute; height: 50%; left: 0; top: 0; border: 1px solid red;') + image.setAttribute('style', 'position: absolute; height: 50%; left: 0; top: 0; border: 1px solid red; image-rendering: pixelated; ') } }) } diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 52e6f31..4f52157 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -17,20 +17,21 @@ export class DistanceField extends Matrix3d { calculateDistanceField() { // this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) - // DistanceField.sweepDirections.forEach(direction => { - // const { dx, dy, dz } = direction - // }) + const y = this.yLevel * this.resolutionFactor - const y = this.yLevel - - let steps = 0 for (let z = 0; z < this.depth; z++) { + let steps = 0 for (let x = 0; x < this.width; x++) { if (this.isVoxelEmpty(x, y, z)) { - this.set(x, y, z, 0) - // TODO: fix - } else { + steps++ this.set(x, y, z, 1) + } else { + this.set(x, y, z, 0) + for (let dx = 0; dx < steps; dx++) { + this.set(x - dx, y, z, dx) + } + + steps = 0 } } } @@ -56,12 +57,12 @@ export class DistanceField extends Matrix3d { const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Ctx could not be retrieved') - const y = this.yLevel + const y = this.yLevel * this.resolutionFactor for (let x = 0; x < this.width; x++) { for (let z = 0; z < this.depth; z++) { - const value = this.get(x, y, z) * 255 - ctx.fillStyle = `rgba(${value}, ${value}, ${value})` + const value = this.get(x, y, z) / this.resolutionFactor * 10 + ctx.fillStyle = `rgba(${value}, ${value}, ${value}, ${value})` ctx.fillRect(x, z, 1, 1) } } From 2c67e0ce6ed6f304699c7181014fd181d6b87761 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Fri, 2 Feb 2024 07:58:26 +0100 Subject: [PATCH 05/10] Implmenet loop constructor --- src/game/world/raymarcher/DistanceField.ts | 54 +++++++++++++++------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 4f52157..17429f3 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -10,31 +10,51 @@ export class DistanceField extends Matrix3d { { dx: 0, dy: 0, dz: -1 }, ] - constructor(public voxelData: Matrix3d, public resolutionFactor: number, public yLevel: number) { + static readonly directionDimensions = { + dx: 'width', + dy: 'height', + dz: 'depth', + } as const + + constructor(public voxelData: Matrix3d, public resolutionFactor: number) { super(voxelData.width * resolutionFactor, voxelData.height * resolutionFactor, voxelData.depth * resolutionFactor) } calculateDistanceField() { // this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) - const y = this.yLevel * this.resolutionFactor + DistanceField.sweepDirections.forEach((direction) => { + const { dx, dy, dz } = direction - for (let z = 0; z < this.depth; z++) { - let steps = 0 - for (let x = 0; x < this.width; x++) { - if (this.isVoxelEmpty(x, y, z)) { - steps++ - this.set(x, y, z, 1) - } else { - this.set(x, y, z, 0) - for (let dx = 0; dx < steps; dx++) { - this.set(x - dx, y, z, dx) - } + const constructLoop = (key: keyof typeof direction, callback: (value: number) => void) => { + const maxValue = this[DistanceField.directionDimensions[key]] - steps = 0 + if (direction[key] === -1) { + for (let i = maxValue; i >= 0; i--) callback(i) + } else { + for (let i = 0; i < maxValue; i++) callback(i) } } - } + + constructLoop('dx', (x: number) => { + constructLoop('dy', (y: number) => { + let steps = 0 + constructLoop('dz', (z: number) => { + if (this.isVoxelEmpty(x, y, z)) { + steps++ + this.set(x, y, z, 1) + } else { + this.set(x, y, z, 0) + for (let dz = 0; dz < steps; dz++) { + this.set(z - dz, y, z, dz) + } + + steps = 0 + } + }) + }) + }) + }) } isVoxelEmpty(x: number, y: number, z: number) { @@ -50,14 +70,14 @@ export class DistanceField extends Matrix3d { } - getTexture() { + getTexture(yLevel: number) { const canvas = document.createElement('canvas') canvas.width = this.width canvas.height = this.depth const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Ctx could not be retrieved') - const y = this.yLevel * this.resolutionFactor + const y = yLevel * this.resolutionFactor for (let x = 0; x < this.width; x++) { for (let z = 0; z < this.depth; z++) { From 763d49770496491d477f35f44a4c716d79b70dc4 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sat, 3 Feb 2024 23:39:24 +0100 Subject: [PATCH 06/10] Refactor DistanceField class and update constructor parameters --- src/game/main.ts | 17 +++--- src/game/world/raymarcher/DistanceField.ts | 65 +++++++++++----------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/game/main.ts b/src/game/main.ts index ea9e3a5..91229ee 100644 --- a/src/game/main.ts +++ b/src/game/main.ts @@ -10,7 +10,7 @@ import { WorkerManager } from './world/workers/WorkerManager' export default class Game implements Experience { resources: Resource[] = [] - constructor(private engine: Engine) { } + constructor(private engine: Engine) {} @Benchmark init(): void { @@ -32,23 +32,26 @@ export default class Game implements Experience { // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (args: any) => { task.callback(args) - // chunk.updateMeshGeometry() + chunk.updateMeshGeometry() - const distanceField = new DistanceField(chunk.chunkData.data, 4, 20) + const distanceField = new DistanceField(chunk.chunkData, 1) distanceField.calculateDistanceField() - const src = distanceField.getTexture() + const src = distanceField.getTexture(20) const image = new Image() image.src = src document.body.appendChild(image) - image.setAttribute('style', 'position: absolute; height: 50%; left: 0; top: 0; border: 1px solid red; image-rendering: pixelated; ') + image.setAttribute( + 'style', + 'position: absolute; height: 50%; left: 0; top: 0; border: 1px solid red; image-rendering: pixelated; ' + ) } }) } // eslint-disable-next-line @typescript-eslint/no-unused-vars - update(delta: number): void { } + update(delta: number): void {} - resize?(): void { } + resize?(): void {} } diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 17429f3..64bf8e6 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -1,4 +1,6 @@ -import { Matrix3d } from "../../util/Matrix3d" +import { Vector3 } from 'three' +import { Matrix3d } from '../../util/Matrix3d' +import { ChunkData } from '../ChunkData' export class DistanceField extends Matrix3d { static sweepDirections = [ @@ -7,53 +9,53 @@ export class DistanceField extends Matrix3d { { dx: 0, dy: 1, dz: 0 }, { dx: 0, dy: -1, dz: 0 }, { dx: 0, dy: 0, dz: 1 }, - { dx: 0, dy: 0, dz: -1 }, + { dx: 0, dy: 0, dz: -1 } ] static readonly directionDimensions = { dx: 'width', dy: 'height', - dz: 'depth', + dz: 'depth' } as const - constructor(public voxelData: Matrix3d, public resolutionFactor: number) { - super(voxelData.width * resolutionFactor, voxelData.height * resolutionFactor, voxelData.depth * resolutionFactor) + constructor(public voxelData: ChunkData, public resolutionFactor: number) { + super( + voxelData.width * resolutionFactor, + voxelData.height * resolutionFactor, + voxelData.depth * resolutionFactor + ) } calculateDistanceField() { - // this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) + this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) DistanceField.sweepDirections.forEach((direction) => { const { dx, dy, dz } = direction - const constructLoop = (key: keyof typeof direction, callback: (value: number) => void) => { - const maxValue = this[DistanceField.directionDimensions[key]] - - if (direction[key] === -1) { - for (let i = maxValue; i >= 0; i--) callback(i) - } else { - for (let i = 0; i < maxValue; i++) callback(i) - } - } + const directionVector = new Vector3(dx, dy, dz) + const dimensionVector = new Vector3(this.width, this.height, this.depth) - constructLoop('dx', (x: number) => { - constructLoop('dy', (y: number) => { + for (let y = 0; y < dimensionVector.y; y++) { + for (let x = 0; x < dimensionVector.x; x++) { let steps = 0 - constructLoop('dz', (z: number) => { - if (this.isVoxelEmpty(x, y, z)) { + for (let z = 0; z < dimensionVector.z; z++) { + if (this.isVoxelEmpty(x, y, z) && z < dimensionVector.z - 1) { steps++ - this.set(x, y, z, 1) - } else { - this.set(x, y, z, 0) - for (let dz = 0; dz < steps; dz++) { - this.set(z - dz, y, z, dz) - } + continue + } - steps = 0 + for (let delta = 1; delta <= steps; delta++) { + const position = directionVector + .clone() + .multiplyScalar(delta) + .add(new Vector3(x, y, z)) + const value = Math.min(delta, this.get(position.x, position.y, position.z)) + this.set(position.x, position.y, position.z, value) } - }) - }) - }) + steps = 0 + } + } + } }) } @@ -65,11 +67,10 @@ export class DistanceField extends Matrix3d { return this.voxelData.get( Math.floor(x / this.resolutionFactor), Math.floor(y / this.resolutionFactor), - Math.floor(z / this.resolutionFactor), + Math.floor(z / this.resolutionFactor) ) } - getTexture(yLevel: number) { const canvas = document.createElement('canvas') canvas.width = this.width @@ -81,7 +82,7 @@ export class DistanceField extends Matrix3d { for (let x = 0; x < this.width; x++) { for (let z = 0; z < this.depth; z++) { - const value = this.get(x, y, z) / this.resolutionFactor * 10 + const value = (this.get(x, y, z) / this.resolutionFactor) * 10 ctx.fillStyle = `rgba(${value}, ${value}, ${value}, ${value})` ctx.fillRect(x, z, 1, 1) } From efdc987f3d5b52f67497d471b912dca6da3d2134 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 4 Feb 2024 18:32:26 +0100 Subject: [PATCH 07/10] Fix issues for 2d distance field --- src/game/world/raymarcher/DistanceField.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 64bf8e6..5955086 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -24,12 +24,19 @@ export class DistanceField extends Matrix3d { voxelData.height * resolutionFactor, voxelData.depth * resolutionFactor ) + const maxDimension = Math.max(this.width, this.height, this.depth) + const maxFieldValue = 255 + if (resolutionFactor * maxDimension >= maxFieldValue) { + throw new Error('Resolution factor is too high') + } } calculateDistanceField() { this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) - DistanceField.sweepDirections.forEach((direction) => { + DistanceField.sweepDirections.forEach((direction, index) => { + if (index > 0) return + const { dx, dy, dz } = direction const directionVector = new Vector3(dx, dy, dz) @@ -39,12 +46,13 @@ export class DistanceField extends Matrix3d { for (let x = 0; x < dimensionVector.x; x++) { let steps = 0 for (let z = 0; z < dimensionVector.z; z++) { - if (this.isVoxelEmpty(x, y, z) && z < dimensionVector.z - 1) { + if (this.isVoxelEmpty(x, y, z) || z == dimensionVector.z - 1) { steps++ + this.set(x, y, z, steps * this.resolutionFactor) continue } - for (let delta = 1; delta <= steps; delta++) { + for (let delta = 0; delta <= steps; delta++) { const position = directionVector .clone() .multiplyScalar(delta) From 64a5e507792f5c30beaf6cb99983984d44909d1b Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 4 Feb 2024 19:08:41 +0100 Subject: [PATCH 08/10] Refactor DistanceField --- src/game/main.ts | 2 +- src/game/world/raymarcher/DistanceField.ts | 50 ++++++++++------------ 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/game/main.ts b/src/game/main.ts index 91229ee..c255ec5 100644 --- a/src/game/main.ts +++ b/src/game/main.ts @@ -37,7 +37,7 @@ export default class Game implements Experience { const distanceField = new DistanceField(chunk.chunkData, 1) distanceField.calculateDistanceField() - const src = distanceField.getTexture(20) + const src = distanceField.generateTexture(20) const image = new Image() image.src = src diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 5955086..1b998cc 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -32,39 +32,35 @@ export class DistanceField extends Matrix3d { } calculateDistanceField() { - this.fill(Math.min(this.width, this.height, this.depth) * this.resolutionFactor) + this.fill(255) - DistanceField.sweepDirections.forEach((direction, index) => { - if (index > 0) return + const directionVector = new Vector3(0, 0, 1) + const dimensionVector = new Vector3(this.width, this.height, this.depth) - const { dx, dy, dz } = direction + for (let y = 0; y < dimensionVector.y; y++) { + for (let x = 0; x < dimensionVector.x; x++) { + let steps = 0 + for (let z = 0; z < dimensionVector.z; z++) { + const empty = this.isVoxelEmpty(x, y, z) + const onEdge = z == dimensionVector.z - 1 - const directionVector = new Vector3(dx, dy, dz) - const dimensionVector = new Vector3(this.width, this.height, this.depth) - - for (let y = 0; y < dimensionVector.y; y++) { - for (let x = 0; x < dimensionVector.x; x++) { - let steps = 0 - for (let z = 0; z < dimensionVector.z; z++) { - if (this.isVoxelEmpty(x, y, z) || z == dimensionVector.z - 1) { - steps++ - this.set(x, y, z, steps * this.resolutionFactor) - continue - } + if (empty && !onEdge) { + steps++ + continue + } - for (let delta = 0; delta <= steps; delta++) { - const position = directionVector - .clone() - .multiplyScalar(delta) - .add(new Vector3(x, y, z)) - const value = Math.min(delta, this.get(position.x, position.y, position.z)) - this.set(position.x, position.y, position.z, value) - } - steps = 0 + for (let delta = 0; delta <= steps; delta++) { + const position = directionVector + .clone() + .multiplyScalar(-delta) + .add(new Vector3(x, y, z)) + const value = Math.min(delta, this.get(position.x, position.y, position.z)) + this.set(position.x, position.y, position.z, value) } + steps = 0 } } - }) + } } isVoxelEmpty(x: number, y: number, z: number) { @@ -79,7 +75,7 @@ export class DistanceField extends Matrix3d { ) } - getTexture(yLevel: number) { + generateTexture(yLevel: number) { const canvas = document.createElement('canvas') canvas.width = this.width canvas.height = this.depth From f30597df90cf2a5a961cd95d97b597b822879e88 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 4 Feb 2024 19:11:54 +0100 Subject: [PATCH 09/10] Implement DistanceField for -z --- src/game/world/raymarcher/DistanceField.ts | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 1b998cc..7bb94d9 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -61,6 +61,33 @@ export class DistanceField extends Matrix3d { } } } + + directionVector.multiplyScalar(-1) + + for (let y = 0; y < dimensionVector.y; y++) { + for (let x = 0; x < dimensionVector.x; x++) { + let steps = 0 + for (let z = dimensionVector.z - 1; z >= 0; z--) { + const empty = this.isVoxelEmpty(x, y, z) + const onEdge = z == 0 + + if (empty && !onEdge) { + steps++ + continue + } + + for (let delta = 0; delta <= steps; delta++) { + const position = directionVector + .clone() + .multiplyScalar(-delta) + .add(new Vector3(x, y, z)) + const value = Math.min(delta, this.get(position.x, position.y, position.z)) + this.set(position.x, position.y, position.z, value) + } + steps = 0 + } + } + } } isVoxelEmpty(x: number, y: number, z: number) { From cb558440b722c6431aa12e9a60e0e396f8c79a73 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Sun, 4 Feb 2024 19:22:48 +0100 Subject: [PATCH 10/10] Implement DistanceField for +x,-y --- src/game/world/raymarcher/DistanceField.ts | 56 +++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/game/world/raymarcher/DistanceField.ts b/src/game/world/raymarcher/DistanceField.ts index 7bb94d9..d3ae3ab 100644 --- a/src/game/world/raymarcher/DistanceField.ts +++ b/src/game/world/raymarcher/DistanceField.ts @@ -34,8 +34,8 @@ export class DistanceField extends Matrix3d { calculateDistanceField() { this.fill(255) - const directionVector = new Vector3(0, 0, 1) const dimensionVector = new Vector3(this.width, this.height, this.depth) + let directionVector = new Vector3(0, 0, 1) for (let y = 0; y < dimensionVector.y; y++) { for (let x = 0; x < dimensionVector.x; x++) { @@ -88,6 +88,60 @@ export class DistanceField extends Matrix3d { } } } + + directionVector = new Vector3(1, 0, 0) + + for (let y = 0; y < dimensionVector.y; y++) { + for (let z = 0; z < dimensionVector.z; z++) { + let steps = 0 + for (let x = 0; x < dimensionVector.x; x++) { + const empty = this.isVoxelEmpty(x, y, z) + const onEdge = x == dimensionVector.x - 1 + + if (empty && !onEdge) { + steps++ + continue + } + + for (let delta = 0; delta <= steps; delta++) { + const position = directionVector + .clone() + .multiplyScalar(-delta) + .add(new Vector3(x, y, z)) + const value = Math.min(delta, this.get(position.x, position.y, position.z)) + this.set(position.x, position.y, position.z, value) + } + steps = 0 + } + } + } + + directionVector.multiplyScalar(-1) + + for (let y = 0; y < dimensionVector.y; y++) { + for (let z = 0; z < dimensionVector.z; z++) { + let steps = 0 + for (let x = dimensionVector.x - 1; x >= 0; x--) { + const empty = this.isVoxelEmpty(x, y, z) + const onEdge = x == 0 + + if (empty && !onEdge) { + steps++ + continue + } + + for (let delta = 0; delta <= steps; delta++) { + const position = directionVector + .clone() + .multiplyScalar(-delta) + .add(new Vector3(x, y, z)) + const value = Math.min(delta, this.get(position.x, position.y, position.z)) + this.set(position.x, position.y, position.z, value) + } + steps = 0 + } + } + } } isVoxelEmpty(x: number, y: number, z: number) {