96 lines
2.9 KiB
TypeScript
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);
|
|
});
|
|
}
|
|
}
|