icy3dw/src/client/object/world/ClientWorld.ts

96 lines
2.9 KiB
TypeScript

import { Mesh, Object3D, Vector3 } from 'three';
import { WorldChunk } from '../../../common/world/WorldChunk';
import { WorldManager } from '../../../common/world/WorldManager';
import { ClientWorldChunkShader } from './ClientWorldChunkShader';
import { ClientWorldMesher } from './ClientWorldMesher';
import { ClientWorldTexture } from './ClientWorldTexture';
// TODO: distance loading
// TODO: LOD
export class ClientWorld extends WorldManager {
public world = new Object3D();
private _mesher = new ClientWorldMesher();
private _chunkMeshes: Mesh[] = [];
private _chunkMeshQueue: WorldChunk[] = [];
private _worldTextures: Map<string, ClientWorldTexture> = new Map();
private _shader = new ClientWorldChunkShader(this._worldTextures);
getNormalVector(x: number, y: number): Vector3 {
const heightL = this.getHeight(x - 1, y);
const heightR = this.getHeight(x + 1, y);
const heightD = this.getHeight(x, y - 1);
const heightU = this.getHeight(x, y + 1);
const normalized = new Vector3(heightL - heightR, 2, heightD - heightU);
normalized.normalize();
return normalized;
}
async initialize() {
await this.loadWorld();
await this.loadTextureList([
...this._chunks.map(
(chunk) => `/assets/terrain/splat-${chunk.x}-${chunk.y}.png`,
),
'/assets/terrain/texture/simplex-noise.png',
'/assets/terrain/texture/grassy.png',
'/assets/terrain/texture/mud.png',
'/assets/terrain/texture/grass-flowers.png',
'/assets/terrain/texture/path.png',
]);
this._shader.initialize(
this._worldTextures.get('/assets/terrain/texture/simplex-noise.png'),
);
this.createMeshes();
}
async loadTexture(src: string): Promise<ClientWorldTexture> {
if (this._worldTextures.has(src)) {
return this._worldTextures.get(src);
}
const tex = await ClientWorldTexture.loadTexture(src);
// tex.texture.repeat.set(this.worldChunkSize, this.worldChunkSize);
this._worldTextures.set(src, tex);
return tex;
}
async loadTextureList(srcList: string[]): Promise<void> {
for (const src of srcList) {
await this.loadTexture(src);
}
}
update(dt: number) {
if (this._chunkMeshQueue.length) {
const chunk = this._chunkMeshQueue.shift();
const material = this._shader.getShader(
chunk,
`/assets/terrain/splat-${chunk.x}-${chunk.y}.png`,
[
'/assets/terrain/texture/grassy.png',
'/assets/terrain/texture/mud.png',
'/assets/terrain/texture/grass-flowers.png',
'/assets/terrain/texture/path.png',
],
);
const mesh = this._mesher.createTerrainMesh(
chunk,
material,
this.getHeight.bind(this),
this.getNormalVector.bind(this),
);
this._chunkMeshes.push(mesh);
this.world.add(mesh);
}
}
private createMeshes() {
this._chunks.forEach((chunk) => {
this._chunkMeshQueue.push(chunk);
});
}
}