Skip to content

Commit

Permalink
Merge pull request #12 from BarthPaleologue/WIP
Browse files Browse the repository at this point in the history
Fixed ground collision issues
  • Loading branch information
BarthPaleologue authored Jan 16, 2024
2 parents c99e889 + d530de7 commit 5a0e45e
Show file tree
Hide file tree
Showing 15 changed files with 195 additions and 190 deletions.
4 changes: 4 additions & 0 deletions src/shaders/starfieldFragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ void main() {

vec2 starfieldUV = vec2(0.0);

// Here, a color test is used and not a depth test
// You may wonder why. The answer is that using a depth test wouldn't account for the 2D UI and the starfield would be drawn on top of it.
// In fact the UI has no depth information, so we need to use something else. I chose this color test as it works in practice but it could break.
// If you have a better idea, please let me know or make a pull request.
if (screenColor == vec4(0.0)) {
// get the starfield color
// get spherical coordinates uv for the starfield texture
Expand Down
2 changes: 1 addition & 1 deletion src/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { Mouse } from "./inputs/mouse";
import { Keyboard } from "./inputs/keyboard";
import { StarModel } from "./stellarObjects/star/starModel";
import { RingsUniforms } from "./postProcesses/rings/ringsUniform";
import { SpaceStation } from "./spacestation/spaceStation";
import { getMoonSeed } from "./planemos/common";

import { Gamepad } from "./inputs/gamepad";
Expand Down Expand Up @@ -132,6 +131,7 @@ const planet = StarSystemHelper.makeTelluricPlanet(starSystem, planetModel);
planet.model.ringsUniforms = new RingsUniforms(planet.model.rng);
planet.postProcesses.push(PostProcessType.RING);


//const spacestation = new SpaceStation(starSystemView.scene, planet);
//starSystemView.getStarSystem().addSpaceStation(spacestation);

Expand Down
4 changes: 2 additions & 2 deletions src/ts/physicSpaceship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { translate } from "./uberCore/transforms/basicTransform";
import { StarModel } from "./stellarObjects/star/starModel";
import { Keyboard } from "./inputs/keyboard";
import { Star } from "./stellarObjects/star/star";
import { ChunkForge } from "./planemos/telluricPlanemo/terrain/chunks/chunkForge";
import { ChunkForgeWorkers } from "./planemos/telluricPlanemo/terrain/chunks/chunkForgeWorkers";

const canvas = document.getElementById("renderer") as HTMLCanvasElement;
canvas.width = window.innerWidth;
Expand Down Expand Up @@ -63,7 +63,7 @@ hemiLight.intensity = 0.2;
const shadowGenerator = new ShadowGenerator(1024, light);
shadowGenerator.useBlurExponentialShadowMap = true;

const chunkForge = new ChunkForge(Settings.VERTEX_RESOLUTION);
const chunkForge = new ChunkForgeWorkers(Settings.VERTEX_RESOLUTION);

const keyboard = new Keyboard();

Expand Down
14 changes: 6 additions & 8 deletions src/ts/planemos/telluricPlanemo/telluricPlanemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import { TelluricPlanemoModel } from "./telluricPlanemoModel";
import { PostProcessType } from "../../postProcesses/postProcessTypes";
import { Camera } from "@babylonjs/core/Cameras/camera";
import { ChunkTree } from "./terrain/chunks/chunkTree";
import { ChunkForge } from "./terrain/chunks/chunkForge";
import { PhysicsShapeSphere } from "@babylonjs/core/Physics/v2/physicsShape";
import { Transformable } from "../../uberCore/transforms/basicTransform";
import { ChunkForge } from "./terrain/chunks/chunkForge";
import { Observable } from "@babylonjs/core/Misc/observable";
import { PlanetChunk } from "./terrain/chunks/planetChunk";

export class TelluricPlanemo extends AbstractBody implements Planemo, PlanemoMaterial {
readonly sides: ChunkTree[]; // stores the 6 sides of the sphere
Expand All @@ -23,6 +25,8 @@ export class TelluricPlanemo extends AbstractBody implements Planemo, PlanemoMat

readonly model: TelluricPlanemoModel;

readonly onChunkCreatedObservable = new Observable<PlanetChunk>();

/**
* New Telluric Planet
* @param name The name of the planet
Expand Down Expand Up @@ -70,13 +74,7 @@ export class TelluricPlanemo extends AbstractBody implements Planemo, PlanemoMat
new ChunkTree(Direction.Left, this.name, this.model, this.aggregate, this.material, scene)
];

for (const side of this.sides) {
side.onChunkPhysicsShapeDeletedObservable.add((index) => {
for (const side2 of this.sides) {
side2.registerPhysicsShapeDeletion(index);
}
});
}
this.sides.forEach((side) => side.onChunkCreatedObservable.add((chunk) => this.onChunkCreatedObservable.notifyObservers(chunk)));
}

getTypeName(): string {
Expand Down
114 changes: 4 additions & 110 deletions src/ts/planemos/telluricPlanemo/terrain/chunks/chunkForge.ts
Original file line number Diff line number Diff line change
@@ -1,112 +1,6 @@
import { TransferBuildData } from "./workerDataTypes";
import { ApplyTask, BuildTask, ReturnedChunkData, TaskType } from "./taskTypes";
import { WorkerPool } from "./workerPool";
import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData";
import { BuildTask } from "./taskTypes";

export class ChunkForge {
/**
* the number vertices per row of the chunk (total number of vertices = nbVerticesPerRow * nbVerticesPerRow)
*/
nbVerticesPerRow: number;

/**
* The worker manager
* FIXME: the workerpool does not need to be a class
*/
workerPool: WorkerPool;

/**
* The queue of tasks containing chunks ready to be enabled
*/
applyTaskQueue: ApplyTask[] = [];

constructor(nbVerticesPerRow: number) {
this.nbVerticesPerRow = nbVerticesPerRow;
const nbMaxWorkers = navigator.hardwareConcurrency - 1; // -1 because the main thread is also used
this.workerPool = new WorkerPool(nbMaxWorkers);
}

public addTask(task: BuildTask) {
this.workerPool.submitTask(task);
}

/**
* Executes the next task using an available worker
* @param worker the web worker assigned to the next task
*/
private executeNextTask(worker: Worker) {
if (this.workerPool.hasTask()) this.dispatchBuildTask(this.workerPool.nextTask(), worker);
else this.workerPool.finishedWorkers.push(worker);
}

private dispatchBuildTask(task: BuildTask, worker: Worker): void {
const buildData: TransferBuildData = {
taskType: TaskType.Build,
planetName: task.planetName,
planetDiameter: task.planetDiameter,
nbVerticesPerSide: this.nbVerticesPerRow,
depth: task.depth,
direction: task.direction,
position: [task.position.x, task.position.y, task.position.z],
terrainSettings: {
continents_frequency: task.terrainSettings.continents_frequency,
continents_fragmentation: task.terrainSettings.continents_fragmentation,
continent_base_height: task.terrainSettings.continent_base_height,
max_mountain_height: task.terrainSettings.max_mountain_height,
max_bump_height: task.terrainSettings.max_bump_height,
bumps_frequency: task.terrainSettings.bumps_frequency,
mountains_frequency: task.terrainSettings.mountains_frequency
},
seed: task.planetSeed
};

worker.postMessage(buildData);

worker.onmessage = (e) => {
const data: ReturnedChunkData = e.data;

const vertexData = new VertexData();
vertexData.positions = data.positions;
vertexData.normals = data.normals;
vertexData.indices = data.indices;

const applyTask: ApplyTask = {
type: TaskType.Apply,
vertexData: vertexData,
chunk: task.chunk,
instancesMatrixBuffer: data.instancesMatrixBuffer,
alignedInstancesMatrixBuffer: data.alignedInstancesMatrixBuffer,
averageHeight: data.averageHeight
};
this.applyTaskQueue.push(applyTask);

if (this.workerPool.hasTask()) this.dispatchBuildTask(this.workerPool.nextTask(), worker);
else this.workerPool.finishedWorkers.push(worker);
};
}

/**
* Apply generated vertexData to waiting chunks
*/
private executeNextApplyTask() {
let task = this.applyTaskQueue.shift();
while (task !== undefined && task.chunk.hasBeenDisposed()) {
// if the chunk has been disposed, we skip it
task = this.applyTaskQueue.shift();
}
if (task) task.chunk.init(task.vertexData, task.instancesMatrixBuffer, task.alignedInstancesMatrixBuffer, task.averageHeight);
}

/**
* Updates the state of the forge : dispatch tasks to workers, remove useless chunks, apply vertexData to new chunks
*/
public update() {
for (let i = 0; i < this.workerPool.availableWorkers.length; i++) {
this.executeNextTask(this.workerPool.availableWorkers.shift() as Worker);
}
this.workerPool.availableWorkers = this.workerPool.availableWorkers.concat(this.workerPool.finishedWorkers);
this.workerPool.finishedWorkers = [];

this.executeNextApplyTask();
}
export interface ChunkForge {
addTask(task: BuildTask): void;
update(): void;
}
113 changes: 113 additions & 0 deletions src/ts/planemos/telluricPlanemo/terrain/chunks/chunkForgeWorkers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { TransferBuildData } from "./workerDataTypes";
import { ApplyTask, BuildTask, ReturnedChunkData, TaskType } from "./taskTypes";
import { WorkerPool } from "./workerPool";
import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData";
import { ChunkForge } from "./chunkForge";

export class ChunkForgeWorkers implements ChunkForge {
/**
* the number vertices per row of the chunk (total number of vertices = nbVerticesPerRow * nbVerticesPerRow)
*/
nbVerticesPerRow: number;

/**
* The worker manager
* FIXME: the workerpool does not need to be a class
*/
workerPool: WorkerPool;

/**
* The queue of tasks containing chunks ready to be enabled
*/
applyTaskQueue: ApplyTask[] = [];

constructor(nbVerticesPerRow: number) {
this.nbVerticesPerRow = nbVerticesPerRow;
const nbMaxWorkers = navigator.hardwareConcurrency - 1; // -1 because the main thread is also used
this.workerPool = new WorkerPool(nbMaxWorkers);
}

public addTask(task: BuildTask) {
this.workerPool.submitTask(task);
}

/**
* Executes the next task using an available worker
* @param worker the web worker assigned to the next task
*/
private executeNextTask(worker: Worker) {
if (this.workerPool.hasTask()) this.dispatchBuildTask(this.workerPool.nextTask(), worker);
else this.workerPool.finishedWorkers.push(worker);
}

private dispatchBuildTask(task: BuildTask, worker: Worker): void {
const buildData: TransferBuildData = {
taskType: TaskType.Build,
planetName: task.planetName,
planetDiameter: task.planetDiameter,
nbVerticesPerSide: this.nbVerticesPerRow,
depth: task.depth,
direction: task.direction,
position: [task.position.x, task.position.y, task.position.z],
terrainSettings: {
continents_frequency: task.terrainSettings.continents_frequency,
continents_fragmentation: task.terrainSettings.continents_fragmentation,
continent_base_height: task.terrainSettings.continent_base_height,
max_mountain_height: task.terrainSettings.max_mountain_height,
max_bump_height: task.terrainSettings.max_bump_height,
bumps_frequency: task.terrainSettings.bumps_frequency,
mountains_frequency: task.terrainSettings.mountains_frequency
},
seed: task.planetSeed
};

worker.postMessage(buildData);

worker.onmessage = (e) => {
const data: ReturnedChunkData = e.data;

const vertexData = new VertexData();
vertexData.positions = data.positions;
vertexData.normals = data.normals;
vertexData.indices = data.indices;

const applyTask: ApplyTask = {
type: TaskType.Apply,
vertexData: vertexData,
chunk: task.chunk,
instancesMatrixBuffer: data.instancesMatrixBuffer,
alignedInstancesMatrixBuffer: data.alignedInstancesMatrixBuffer,
averageHeight: data.averageHeight
};
this.applyTaskQueue.push(applyTask);

if (this.workerPool.hasTask()) this.dispatchBuildTask(this.workerPool.nextTask(), worker);
else this.workerPool.finishedWorkers.push(worker);
};
}

/**
* Apply generated vertexData to waiting chunks
*/
private executeNextApplyTask() {
let task = this.applyTaskQueue.shift();
while (task !== undefined && task.chunk.hasBeenDisposed()) {
// if the chunk has been disposed, we skip it
task = this.applyTaskQueue.shift();
}
if (task) task.chunk.init(task.vertexData, task.instancesMatrixBuffer, task.alignedInstancesMatrixBuffer, task.averageHeight);
}

/**
* Updates the state of the forge : dispatch tasks to workers, remove useless chunks, apply vertexData to new chunks
*/
public update() {
for (let i = 0; i < this.workerPool.availableWorkers.length; i++) {
this.executeNextTask(this.workerPool.availableWorkers.shift() as Worker);
}
this.workerPool.availableWorkers = this.workerPool.availableWorkers.concat(this.workerPool.finishedWorkers);
this.workerPool.finishedWorkers = [];

this.executeNextApplyTask();
}
}
23 changes: 6 additions & 17 deletions src/ts/planemos/telluricPlanemo/terrain/chunks/chunkTree.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { PlanetChunk } from "./planetChunk";
import { Direction } from "../../../../utils/direction";
import { ChunkForge } from "./chunkForge";
import { BuildTask, TaskType } from "./taskTypes";
import { Settings } from "../../../../settings";
import { getChunkSphereSpacePositionFromPath } from "../../../../utils/chunkUtils";
Expand All @@ -11,11 +10,11 @@ import { Vector3 } from "@babylonjs/core/Maths/math.vector";
import { PhysicsAggregate } from "@babylonjs/core/Physics/v2/physicsAggregate";
import { TransformNode } from "@babylonjs/core/Meshes";
import { Camera } from "@babylonjs/core/Cameras/camera";
import { isSizeOnScreenEnough } from "../../../../utils/isObjectVisibleOnScreen";
import { Observable } from "@babylonjs/core/Misc/observable";
import { DeleteSemaphore } from "./deleteSemaphore";
import { UberScene } from "../../../../uberCore/uberScene";
import { getRotationQuaternion } from "../../../../uberCore/transforms/basicTransform";
import { ChunkForge } from "./chunkForge";

/**
* A quadTree is defined recursively
Expand Down Expand Up @@ -48,7 +47,7 @@ export class ChunkTree {
readonly parent: TransformNode;
readonly parentAggregate: PhysicsAggregate;

readonly onChunkPhysicsShapeDeletedObservable = new Observable<number>();
readonly onChunkCreatedObservable = new Observable<PlanetChunk>();

readonly material: Material;

Expand All @@ -61,7 +60,7 @@ export class ChunkTree {
* @param material
* @param scene
*/
constructor(direction: Direction, planetName: string, planetModel: TelluricPlanemoModel, parentAggregate: PhysicsAggregate, material: Material, scene: UberScene) {
constructor(direction: Direction, planetName: string, planetModel: TelluricPlanemoModel, parentAggregate: PhysicsAggregate, material: Material, scene: UberScene) {
this.rootChunkLength = planetModel.radius * 2;
this.planetName = planetName;
this.planetSeed = planetModel.seed;
Expand Down Expand Up @@ -189,6 +188,7 @@ export class ChunkTree {
if (tree instanceof PlanetChunk) {
if (!tree.isReady()) return tree;
if (!tree.mesh.isVisible) return tree;
if (!tree.mesh.isEnabled()) return tree;
}

const newTree = [
Expand All @@ -215,8 +215,8 @@ export class ChunkTree {
private createChunk(path: number[], chunkForge: ChunkForge): PlanetChunk {
const chunk = new PlanetChunk(path, this.direction, this.parentAggregate, this.material, this.planetModel, this.rootChunkLength, this.scene);

chunk.onDestroyPhysicsShapeObservable.add((index) => {
this.onChunkPhysicsShapeDeletedObservable.notifyObservers(index);
chunk.onRecieveVertexDataObservable.add(() => {
this.onChunkCreatedObservable.notifyObservers(chunk);
});

const buildTask: BuildTask = {
Expand All @@ -236,17 +236,6 @@ export class ChunkTree {
return chunk;
}

public registerPhysicsShapeDeletion(index: number): void {
this.executeOnEveryChunk((chunk) => {
chunk.registerPhysicsShapeDeletion(index);
});
for (const deleteSemaphore of this.deleteSemaphores) {
for (const chunk of deleteSemaphore.chunksToDelete) {
chunk.registerPhysicsShapeDeletion(index);
}
}
}

public computeCulling(camera: Camera): void {
this.executeOnEveryChunk((chunk: PlanetChunk) => {
chunk.computeCulling(camera);
Expand Down
Loading

0 comments on commit 5a0e45e

Please sign in to comment.