Skip to content

Commit

Permalink
refactor: allow simplied input object for empty chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
piellardj committed Nov 4, 2024
1 parent 5d74af3 commit 0a8f719
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import * as THREE from '../../../../../libs/three-usage';
import { AsyncTask } from '../../../../../helpers/async/async-task';
import { type VoxelsChunkOrdering, type IVoxelMap, type IVoxelMaterial, type VoxelsChunkSize } from '../../../i-voxelmap';
import * as THREE from '../../../../../libs/three-usage';
import { type IVoxelMap, type IVoxelMaterial, type VoxelsChunkOrdering, type VoxelsChunkSize } from '../../../i-voxelmap';
import { type VoxelsRenderable } from '../../../voxelsRenderable/voxels-renderable';
import { VoxelsRenderableFactoryGpu } from '../../../voxelsRenderable/voxelsRenderableFactory/merged/gpu/voxels-renderable-factory-gpu';
import {
type VoxelsChunkData,
type CheckerboardType,
type GeometryAndMaterial,
} from '../../../voxelsRenderable/voxelsRenderableFactory/voxels-renderable-factory-base';
import { PatchFactoryBase, type LocalMapData } from '../patch-factory-base';
import { PatchFactoryBase } from '../patch-factory-base';

type PatchGenerationJob = {
readonly patchId: number;
cpuTask: AsyncTask<LocalMapData>;
cpuTask: AsyncTask<VoxelsChunkData>;
gpuTask?: Promise<GeometryAndMaterial[]>;
readonly resolve: (value: GeometryAndMaterial[]) => void;
};
Expand Down Expand Up @@ -60,11 +61,11 @@ class PatchFactoryGpuOptimized extends PatchFactoryBase {

this.pendingJobs.push({
patchId,
cpuTask: new AsyncTask<LocalMapData>(async () => {
cpuTask: new AsyncTask<VoxelsChunkData>(() => {
// logger.diagnostic(`CPU ${patchId} start`);
const result = await PatchFactoryBase.buildLocalMapData(patchStart, patchEnd, map);
// const result = await PatchFactoryBase.buildLocalMapData(patchStart, patchEnd, map);
// logger.diagnostic(`CPU ${patchId} end`);
return result;
return PatchFactoryBase.buildLocalMapData(patchStart, patchEnd, map);
}),
resolve: onGeometryAndMaterialsListComputed,
});
Expand All @@ -86,7 +87,11 @@ class PatchFactoryGpuOptimized extends PatchFactoryBase {
if (!currentJob.gpuTask) {
const localMapData = currentJob.cpuTask.getResultSync();

currentJob.gpuTask = this.voxelsRenderableFactory.buildGeometryAndMaterials(localMapData);
if (localMapData.isEmpty) {
currentJob.gpuTask = Promise.resolve([]);
} else {
currentJob.gpuTask = this.voxelsRenderableFactory.buildGeometryAndMaterials(localMapData);
}

currentJob.gpuTask.then(result => {
this.pendingJobs.shift();
Expand Down
22 changes: 8 additions & 14 deletions src/lib/terrain/voxelmap/patch/patch-factory/patch-factory-base.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as THREE from '../../../../libs/three-usage';
import { processAsap } from '../../../../helpers/async/async-sync';
import { vec3ToString } from '../../../../helpers/string';
import { type VoxelsChunkOrdering, type IVoxelMap } from '../../i-voxelmap';
import * as THREE from '../../../../libs/three-usage';
import { type IVoxelMap } from '../../i-voxelmap';
import { type VoxelsRenderable } from '../../voxelsRenderable/voxels-renderable';
import {
type VoxelsChunkDataNotEmpty,
type VoxelsChunkData,
type VoxelsRenderableFactoryBase,
} from '../../voxelsRenderable/voxelsRenderableFactory/voxels-renderable-factory-base';
Expand All @@ -16,13 +17,6 @@ type VertexData = {
readonly roundnessY: boolean;
};

type LocalMapData = {
readonly size: THREE.Vector3;
readonly data: Uint16Array;
readonly dataOrdering: VoxelsChunkOrdering;
readonly isEmpty: boolean;
};

abstract class PatchFactoryBase {
public readonly maxPatchSize: THREE.Vector3;

Expand Down Expand Up @@ -55,7 +49,7 @@ abstract class PatchFactoryBase {
patchId: PatchId,
patchStart: THREE.Vector3,
patchEnd: THREE.Vector3,
voxelsChunkData: VoxelsChunkData
voxelsChunkData: VoxelsChunkDataNotEmpty
): Promise<VoxelsRenderable | null> {
patchStart = patchStart.clone();
patchEnd = patchEnd.clone();
Expand All @@ -76,8 +70,8 @@ abstract class PatchFactoryBase {
return this.finalizePatch(voxelsRenderable, patchId, patchStart);
}

public async buildVoxelsRenderable(voxelsChunkData: VoxelsChunkData): Promise<VoxelsRenderable | null> {
return await this.voxelsRenderableFactory.buildVoxelsRenderable(voxelsChunkData);
public buildVoxelsRenderable(voxelsChunkData: VoxelsChunkData): null | Promise<VoxelsRenderable | null> {
return this.voxelsRenderableFactory.buildVoxelsRenderable(voxelsChunkData);
}

public dispose(): void {
Expand All @@ -90,7 +84,7 @@ abstract class PatchFactoryBase {
map: IVoxelMap
): Promise<VoxelsRenderable | null>;

protected static async buildLocalMapData(patchStart: THREE.Vector3, patchEnd: THREE.Vector3, map: IVoxelMap): Promise<LocalMapData> {
protected static async buildLocalMapData(patchStart: THREE.Vector3, patchEnd: THREE.Vector3, map: IVoxelMap): Promise<VoxelsChunkData> {
const cacheStart = patchStart.clone().subScalar(1);
const cacheEnd = patchEnd.clone().addScalar(1);
const cacheSize = new THREE.Vector3().subVectors(cacheEnd, cacheStart);
Expand Down Expand Up @@ -124,4 +118,4 @@ abstract class PatchFactoryBase {
}
}

export { PatchFactoryBase, type LocalMapData, type VertexData };
export { PatchFactoryBase, type VertexData };
5 changes: 4 additions & 1 deletion src/lib/terrain/voxelmap/viewer/simple/voxelmap-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AsyncTask } from '../../../../helpers/async/async-task';
import { PromisesQueue } from '../../../../helpers/async/promises-queue';
import { vec3ToString } from '../../../../helpers/string';
import * as THREE from '../../../../libs/three-usage';
import { type VoxelsChunkOrdering, type IVoxelMaterial, type VoxelsChunkSize } from '../../i-voxelmap';
import { type IVoxelMaterial, type VoxelsChunkOrdering, type VoxelsChunkSize } from '../../i-voxelmap';
import { PatchFactoryCpu } from '../../patch/patch-factory/merged/patch-factory-cpu';
import { PatchFactoryCpuWorker } from '../../patch/patch-factory/merged/patch-factory-cpu-worker';
import { PatchFactoryGpuSequential } from '../../patch/patch-factory/merged/patch-factory-gpu-sequential';
Expand Down Expand Up @@ -162,6 +162,9 @@ class VoxelmapViewer extends VoxelmapViewerBase {
id: patchId,
status: 'in-queue',
computationTask: new AsyncTask<VoxelsRenderable | null>(async () => {
if (voxelsChunkData.isEmpty) {
return null;
}
const patchStart = new THREE.Vector3().multiplyVectors(patchId, this.patchSize);
const patchEnd = new THREE.Vector3().addVectors(patchStart, this.patchSize);
return await this.patchFactory.buildPatchFromVoxelsChunk(patchId, patchStart, patchEnd, voxelsChunkData);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type WorkerDefinition } from '../../../../../../helpers/async/dedicatedWorkers/dedicated-worker';
import { DedicatedWorkersPool } from '../../../../../../helpers/async/dedicatedWorkers/dedicated-workers-pool';
import { type VoxelsChunkOrdering, type IVoxelMaterial, type VoxelsChunkSize } from '../../../../i-voxelmap';
import { type CheckerboardType, type VoxelsChunkData } from '../../voxels-renderable-factory-base';
import { type IVoxelMaterial, type VoxelsChunkOrdering, type VoxelsChunkSize } from '../../../../i-voxelmap';
import { type CheckerboardType, type VoxelsChunkDataNotEmpty } from '../../voxels-renderable-factory-base';

import { VoxelsRenderableFactoryCpu } from './voxels-renderable-factory-cpu';

Expand All @@ -28,12 +28,12 @@ class VoxelsRenderableFactoryCpuWorker extends VoxelsRenderableFactoryCpu {
this.workersPoolSize = params.workersPoolSize;
}

protected override buildBuffer(voxelsChunkData: VoxelsChunkData): Promise<Uint32Array> {
protected override buildBuffer(voxelsChunkData: VoxelsChunkDataNotEmpty): Promise<Uint32Array> {
if (!this.workersPool) {
const workerDefinition: WorkerDefinition = {
commonCode: `const factory = ${this.serialize()};`,
tasks: {
buildBuffer: (voxelsChunkData: VoxelsChunkData) => {
buildBuffer: (voxelsChunkData: VoxelsChunkDataNotEmpty) => {
// eslint-disable-next-line no-eval
const factory2 = eval('factory') as VoxelsRenderableFactoryCpu['serializableFactory'];
const buffer = factory2.buildBuffer(voxelsChunkData);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type * as THREE from '../../../../../../libs/three-usage';
import { voxelmapDataPacking, type VoxelsChunkOrdering, type IVoxelMaterial, type VoxelsChunkSize } from '../../../../i-voxelmap';
import { voxelmapDataPacking, type IVoxelMaterial, type VoxelsChunkOrdering, type VoxelsChunkSize } from '../../../../i-voxelmap';
import * as Cube from '../../cube';
import {
type CheckerboardType,
type GeometryAndMaterial,
type VertexData,
type VoxelsChunkData,
type VoxelsChunkDataNotEmpty,
} from '../../voxels-renderable-factory-base';
import { type CheckerboardCellId } from '../vertex-data2-encoder';
import { VoxelsRenderableFactory } from '../voxels-renderable-factory';
Expand Down Expand Up @@ -53,7 +54,7 @@ class VoxelsRenderableFactoryCpu extends VoxelsRenderableFactory {
greedyMeshing: true,
voxelsChunkOrdering: 'zyx' as VoxelsChunkOrdering,

buildBuffer(voxelsChunkData: VoxelsChunkData): Uint32Array {
buildBuffer(voxelsChunkData: VoxelsChunkDataNotEmpty): Uint32Array {
if (voxelsChunkData.isEmpty) {
return new Uint32Array();
}
Expand Down Expand Up @@ -187,7 +188,7 @@ class VoxelsRenderableFactoryCpu extends VoxelsRenderableFactory {
return new Uint32Array(bufferData.buffer.subarray(0, uint32PerVertex * bufferData.verticesCount));
},

buildLocalMapCache(voxelsChunkData: VoxelsChunkData): VoxelsChunkCache {
buildLocalMapCache(voxelsChunkData: VoxelsChunkDataNotEmpty): VoxelsChunkCache {
type Component = 'x' | 'y' | 'z';
const buildIndexFactorComponent = (component: Component): number => {
const sanitizeXYZ = (s: string | undefined): Component => {
Expand Down Expand Up @@ -322,11 +323,7 @@ class VoxelsRenderableFactoryCpu extends VoxelsRenderableFactory {
this.serializableFactory.voxelsChunkOrdering = params.voxelsChunkOrdering;
}

public async buildGeometryAndMaterials(voxelsChunkData: VoxelsChunkData): Promise<GeometryAndMaterial[]> {
if (voxelsChunkData.isEmpty) {
return [];
}

public async buildGeometryAndMaterials(voxelsChunkData: VoxelsChunkDataNotEmpty): Promise<GeometryAndMaterial[]> {
if (voxelsChunkData.dataOrdering !== this.serializableFactory.voxelsChunkOrdering) {
throw new Error(
`Invalid data ordering: expected "${this.serializableFactory.voxelsChunkOrdering}" but received "${voxelsChunkData.dataOrdering}".`
Expand All @@ -337,7 +334,7 @@ class VoxelsRenderableFactoryCpu extends VoxelsRenderableFactory {
return this.assembleGeometryAndMaterials(buffer);
}

protected async buildBuffer(voxelsChunkData: VoxelsChunkData): Promise<Uint32Array> {
protected async buildBuffer(voxelsChunkData: VoxelsChunkDataNotEmpty): Promise<Uint32Array> {
return this.serializableFactory.buildBuffer(voxelsChunkData);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/// <reference types="@webgpu/types" />

import type * as THREE from '../../../../../../libs/three-usage';
import { PromisesQueue } from '../../../../../../helpers/async/promises-queue';
import { logger } from '../../../../../../helpers/logger';
import { vec3ToString } from '../../../../../../helpers/string';
import { getGpuDevice } from '../../../../../../helpers/webgpu/webgpu-device';
import type * as THREE from '../../../../../../libs/three-usage';
import { voxelmapDataPacking, type VoxelsChunkOrdering } from '../../../../i-voxelmap';
import * as Cube from '../../cube';
import { type CheckerboardType, type VoxelsChunkData } from '../../voxels-renderable-factory-base';
import { type VoxelsChunkDataNotEmpty, type CheckerboardType } from '../../voxels-renderable-factory-base';
import { type VertexData1Encoder } from '../vertex-data1-encoder';
import { type VertexData2Encoder } from '../vertex-data2-encoder';

Expand Down Expand Up @@ -240,7 +240,7 @@ class VoxelsComputerGpu {
});
}

public async computeBuffer(voxelsChunkData: VoxelsChunkData): Promise<ComputationOutputs> {
public async computeBuffer(voxelsChunkData: VoxelsChunkDataNotEmpty): Promise<ComputationOutputs> {
if (voxelsChunkData.dataOrdering !== this.voxelsChunkOrdering) {
throw new Error(
`Invalid data ordering: expected "${this.voxelsChunkOrdering}" but received "${voxelsChunkData.dataOrdering}".`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type VoxelsChunkOrdering, type IVoxelMaterial, type VoxelsChunkSize } from '../../../../i-voxelmap';
import { type CheckerboardType, type GeometryAndMaterial, type VoxelsChunkData } from '../../voxels-renderable-factory-base';
import { type IVoxelMaterial, type VoxelsChunkOrdering, type VoxelsChunkSize } from '../../../../i-voxelmap';
import { type VoxelsChunkDataNotEmpty, type CheckerboardType, type GeometryAndMaterial } from '../../voxels-renderable-factory-base';
import { VoxelsRenderableFactory } from '../voxels-renderable-factory';

import { VoxelsComputerGpu } from './voxels-computer-gpu';
Expand Down Expand Up @@ -35,11 +35,7 @@ class VoxelsRenderableFactoryGpu extends VoxelsRenderableFactory {
this.voxelsComputerGpuPromise?.then(computer => computer.dispose());
}

public async buildGeometryAndMaterials(voxelsChunkData: VoxelsChunkData): Promise<GeometryAndMaterial[]> {
if (voxelsChunkData.isEmpty) {
return [];
}

public async buildGeometryAndMaterials(voxelsChunkData: VoxelsChunkDataNotEmpty): Promise<GeometryAndMaterial[]> {
const voxelsComputerGpu = await this.getVoxelsComputerGpu();
const buffer = await voxelsComputerGpu.computeBuffer(voxelsChunkData);
return this.assembleGeometryAndMaterials(buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@ type VertexData = {
readonly roundnessY: boolean;
};

type VoxelsChunkData = {
type VoxelsChunkDataEmpty = {
readonly size: THREE.Vector3;
readonly isEmpty: true;
};
type VoxelsChunkDataNotEmpty = {
readonly size: THREE.Vector3;
readonly data: Uint16Array;
readonly dataOrdering: VoxelsChunkOrdering;
readonly isEmpty: boolean;
readonly isEmpty: false;
};
type VoxelsChunkData = VoxelsChunkDataEmpty | VoxelsChunkDataNotEmpty;

type CheckerboardType = 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz' | 'xyz';

Expand Down Expand Up @@ -83,7 +88,7 @@ abstract class VoxelsRenderableFactoryBase {
this.uniformsTemplate.uTexture.value = this.texture;
}

public async buildVoxelsRenderable(voxelsChunkData: VoxelsChunkData): Promise<VoxelsRenderable | null> {
public buildVoxelsRenderable(voxelsChunkData: VoxelsChunkData): null | Promise<VoxelsRenderable | null> {
const innerChunkSize = voxelsChunkData.size.clone().subScalar(2);
if (
innerChunkSize.x > this.maxVoxelsChunkSize.x ||
Expand All @@ -97,8 +102,9 @@ abstract class VoxelsRenderableFactoryBase {
return null;
}

const geometryAndMaterialsList = await this.buildGeometryAndMaterials(voxelsChunkData);
return this.assembleVoxelsRenderable(innerChunkSize, geometryAndMaterialsList);
return this.buildGeometryAndMaterials(voxelsChunkData).then(geometryAndMaterialsList => {
return this.assembleVoxelsRenderable(innerChunkSize, geometryAndMaterialsList);
});
}

public dispose(): void {
Expand Down Expand Up @@ -142,7 +148,7 @@ abstract class VoxelsRenderableFactoryBase {
return voxelsRenderable;
}

public abstract buildGeometryAndMaterials(voxelsChunkData: VoxelsChunkData): Promise<GeometryAndMaterial[]>;
public abstract buildGeometryAndMaterials(voxelsChunkData: VoxelsChunkDataNotEmpty): Promise<GeometryAndMaterial[]>;

private static buildMaterialsTexture(
voxelMaterials: ReadonlyArray<IVoxelMaterial>,
Expand Down Expand Up @@ -191,4 +197,6 @@ export {
type Parameters,
type VertexData,
type VoxelsChunkData,
type VoxelsChunkDataEmpty,
type VoxelsChunkDataNotEmpty,
};
3 changes: 3 additions & 0 deletions src/test/map/trees/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class Tree {

public getVoxel(position: THREE.Vector3Like): number | null {
const index = this.buildIndex(position);
if (this.voxels.isEmpty) {
return null;
}
const voxel = this.voxels.data[index];
if (typeof voxel === 'undefined') {
throw new Error();
Expand Down

0 comments on commit 0a8f719

Please sign in to comment.