Add procedural lightmap system for planets and asteroids
Some checks failed
Build / build (push) Failing after 19s
Some checks failed
Build / build (push) Failing after 19s
- Create sphereLightmap.ts for procedural lighting generation - Update planets to use lightmaps oriented toward sun - Switch asteroids to PBR material with noise texture - Use sphere physics shape for asteroids 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
942c0a1af0
commit
a9054c2389
BIN
public/ship1.blend
Normal file
BIN
public/ship1.blend
Normal file
Binary file not shown.
BIN
public/ship1.glb
Normal file
BIN
public/ship1.glb
Normal file
Binary file not shown.
@ -26,6 +26,7 @@ import {
|
|||||||
validateLevelConfig
|
validateLevelConfig
|
||||||
} from "./levelConfig";
|
} from "./levelConfig";
|
||||||
import { FireProceduralTexture } from "@babylonjs/procedural-textures";
|
import { FireProceduralTexture } from "@babylonjs/procedural-textures";
|
||||||
|
import {createSphereLightmap} from "./sphereLightmap";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes a LevelConfig JSON object and creates all entities in the scene
|
* Deserializes a LevelConfig JSON object and creates all entities in the scene
|
||||||
@ -59,7 +60,7 @@ export class LevelDeserializer {
|
|||||||
const startBase = this.createStartBase();
|
const startBase = this.createStartBase();
|
||||||
const sun = this.createSun();
|
const sun = this.createSun();
|
||||||
const planets = this.createPlanets();
|
const planets = this.createPlanets();
|
||||||
const asteroids = await this.createAsteroids(startBase, scoreObservable);
|
const asteroids = await this.createAsteroids(scoreObservable);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
startBase,
|
startBase,
|
||||||
@ -104,8 +105,8 @@ export class LevelDeserializer {
|
|||||||
const config = this.config.sun;
|
const config = this.config.sun;
|
||||||
|
|
||||||
// Create point light
|
// Create point light
|
||||||
const light = new PointLight("light", this.arrayToVector3(config.position), this.scene);
|
//const light = new PointLight("light", this.arrayToVector3(config.position), this.scene);
|
||||||
light.intensity = config.intensity || 1000000;
|
//light.intensity = config.intensity || 1000000;
|
||||||
|
|
||||||
// Create sun sphere
|
// Create sun sphere
|
||||||
const sun = MeshBuilder.CreateSphere("sun", {
|
const sun = MeshBuilder.CreateSphere("sun", {
|
||||||
@ -123,8 +124,8 @@ export class LevelDeserializer {
|
|||||||
sun.material = material;
|
sun.material = material;
|
||||||
|
|
||||||
// Create glow layer
|
// Create glow layer
|
||||||
const gl = new GlowLayer("glow", this.scene);
|
//const gl = new GlowLayer("glow", this.scene);
|
||||||
gl.intensity = 1;
|
//gl.intensity = 1;
|
||||||
|
|
||||||
return sun;
|
return sun;
|
||||||
}
|
}
|
||||||
@ -134,6 +135,7 @@ export class LevelDeserializer {
|
|||||||
*/
|
*/
|
||||||
private createPlanets(): AbstractMesh[] {
|
private createPlanets(): AbstractMesh[] {
|
||||||
const planets: AbstractMesh[] = [];
|
const planets: AbstractMesh[] = [];
|
||||||
|
const sunPosition = this.arrayToVector3(this.config.sun.position);
|
||||||
|
|
||||||
for (const planetConfig of this.config.planets) {
|
for (const planetConfig of this.config.planets) {
|
||||||
const planet = MeshBuilder.CreateSphere(planetConfig.name, {
|
const planet = MeshBuilder.CreateSphere(planetConfig.name, {
|
||||||
@ -141,17 +143,37 @@ export class LevelDeserializer {
|
|||||||
segments: 32
|
segments: 32
|
||||||
}, this.scene);
|
}, this.scene);
|
||||||
|
|
||||||
planet.position = this.arrayToVector3(planetConfig.position);
|
const planetPosition = this.arrayToVector3(planetConfig.position);
|
||||||
|
planet.position = planetPosition;
|
||||||
|
|
||||||
if (planetConfig.rotation) {
|
// Calculate direction from planet to sun
|
||||||
planet.rotation = this.arrayToVector3(planetConfig.rotation);
|
const toSun = sunPosition.subtract(planetPosition).normalize();
|
||||||
}
|
|
||||||
|
|
||||||
// Apply texture
|
// Apply texture
|
||||||
const material = new StandardMaterial(planetConfig.name + "-material", this.scene);
|
const material = new StandardMaterial(planetConfig.name + "-material", this.scene);
|
||||||
const texture = new Texture(planetConfig.texturePath, this.scene);
|
const texture = new Texture(planetConfig.texturePath, this.scene);
|
||||||
material.diffuseTexture = texture;
|
|
||||||
material.ambientTexture = texture;
|
// Create lightmap with bright light pointing toward sun
|
||||||
|
const lightmap = createSphereLightmap(
|
||||||
|
planetConfig.name + "-lightmap",
|
||||||
|
512, // texture size
|
||||||
|
DefaultScene.MainScene,
|
||||||
|
toSun, // bright light from sun direction
|
||||||
|
1, // bright intensity
|
||||||
|
toSun.negate(), // dim light from opposite direction
|
||||||
|
0.3, // dim intensity
|
||||||
|
0.3 // ambient
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply to material
|
||||||
|
// Use emissiveTexture (self-lit) instead of diffuseTexture when lighting is disabled
|
||||||
|
material.emissiveTexture = texture;
|
||||||
|
material.lightmapTexture = lightmap;
|
||||||
|
material.useLightmapAsShadowmap = true;
|
||||||
|
|
||||||
|
// Disable standard lighting since we're using baked lightmap
|
||||||
|
material.disableLighting = true;
|
||||||
|
|
||||||
material.roughness = 1;
|
material.roughness = 1;
|
||||||
material.specularColor = Color3.Black();
|
material.specularColor = Color3.Black();
|
||||||
planet.material = material;
|
planet.material = material;
|
||||||
@ -167,7 +189,6 @@ export class LevelDeserializer {
|
|||||||
* Create asteroids from config
|
* Create asteroids from config
|
||||||
*/
|
*/
|
||||||
private async createAsteroids(
|
private async createAsteroids(
|
||||||
startBase: AbstractMesh,
|
|
||||||
scoreObservable: Observable<ScoreEvent>
|
scoreObservable: Observable<ScoreEvent>
|
||||||
): Promise<AbstractMesh[]> {
|
): Promise<AbstractMesh[]> {
|
||||||
const asteroids: AbstractMesh[] = [];
|
const asteroids: AbstractMesh[] = [];
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type {AudioEngineV2} from "@babylonjs/core";
|
import {AudioEngineV2, DirectionalLight} from "@babylonjs/core";
|
||||||
import {
|
import {
|
||||||
Color3,
|
Color3,
|
||||||
CreateAudioEngineAsync,
|
CreateAudioEngineAsync,
|
||||||
@ -170,9 +170,10 @@ export class Main {
|
|||||||
private async setupPhysics() {
|
private async setupPhysics() {
|
||||||
const havok = await HavokPhysics();
|
const havok = await HavokPhysics();
|
||||||
const havokPlugin = new HavokPlugin(true, havok);
|
const havokPlugin = new HavokPlugin(true, havok);
|
||||||
|
DefaultScene.MainScene.ambientColor = new Color3(.1, .1, .1);
|
||||||
|
const light = new DirectionalLight("dirLight", new Vector3(-1, -2, -1), DefaultScene.MainScene);
|
||||||
DefaultScene.MainScene.enablePhysics(new Vector3(0, 0, 0), havokPlugin);
|
DefaultScene.MainScene.enablePhysics(new Vector3(0, 0, 0), havokPlugin);
|
||||||
DefaultScene.MainScene.getPhysicsEngine().setTimeStep(1/45);
|
DefaultScene.MainScene.getPhysicsEngine().setTimeStep(1/30);
|
||||||
DefaultScene.MainScene.getPhysicsEngine().setSubTimeStep(5);
|
DefaultScene.MainScene.getPhysicsEngine().setSubTimeStep(5);
|
||||||
|
|
||||||
DefaultScene.MainScene.collisionsEnabled = true;
|
DefaultScene.MainScene.collisionsEnabled = true;
|
||||||
|
|||||||
30
src/ship.ts
30
src/ship.ts
@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
AbstractMesh,
|
AbstractMesh, Angle,
|
||||||
Color3,
|
Color3,
|
||||||
DirectionalLight,
|
DirectionalLight,
|
||||||
FreeCamera,
|
FreeCamera,
|
||||||
@ -103,7 +103,7 @@ export class Ship {
|
|||||||
ammo.position.y = 2;
|
ammo.position.y = 2;
|
||||||
ammo.rotation.x = Math.PI / 2;
|
ammo.rotation.x = Math.PI / 2;
|
||||||
ammo.setParent(null);
|
ammo.setParent(null);
|
||||||
const ammoAggregate = new PhysicsAggregate(ammo, PhysicsShapeType.CONVEX_HULL, {
|
const ammoAggregate = new PhysicsAggregate(ammo, PhysicsShapeType.SPHERE, {
|
||||||
mass: 1000,
|
mass: 1000,
|
||||||
restitution: 0
|
restitution: 0
|
||||||
}, DefaultScene.MainScene);
|
}, DefaultScene.MainScene);
|
||||||
@ -118,7 +118,7 @@ export class Ship {
|
|||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
ammoAggregate.dispose();
|
ammoAggregate.dispose();
|
||||||
ammo.dispose()
|
ammo.dispose()
|
||||||
}, 1500);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public set position(newPosition: Vector3) {
|
public set position(newPosition: Vector3) {
|
||||||
@ -141,7 +141,7 @@ export class Ship {
|
|||||||
}
|
}
|
||||||
this._ammoMaterial = new StandardMaterial("ammoMaterial", DefaultScene.MainScene);
|
this._ammoMaterial = new StandardMaterial("ammoMaterial", DefaultScene.MainScene);
|
||||||
this._ammoMaterial.emissiveColor = new Color3(1, 1, 0);
|
this._ammoMaterial.emissiveColor = new Color3(1, 1, 0);
|
||||||
this._ammoBaseMesh = MeshBuilder.CreateCapsule("bullet", {radius: .1, height: 2.5}, DefaultScene.MainScene);
|
this._ammoBaseMesh = MeshBuilder.CreateSphere("bullet", {diameter: .2}, DefaultScene.MainScene);
|
||||||
this._ammoBaseMesh.material = this._ammoMaterial;
|
this._ammoBaseMesh.material = this._ammoMaterial;
|
||||||
this._ammoBaseMesh.setEnabled(false);
|
this._ammoBaseMesh.setEnabled(false);
|
||||||
|
|
||||||
@ -176,33 +176,37 @@ export class Ship {
|
|||||||
DefaultScene.MainScene.setActiveCameraByName("Flat Camera");
|
DefaultScene.MainScene.setActiveCameraByName("Flat Camera");
|
||||||
|
|
||||||
//const sightPos = this._forwardNode.position.scale(30);
|
//const sightPos = this._forwardNode.position.scale(30);
|
||||||
const sight = MeshBuilder.CreateSphere("sight", {diameter: 1}, DefaultScene.MainScene);
|
const sight = MeshBuilder.CreateDisc("sight", {radius: 2 }, DefaultScene.MainScene);
|
||||||
|
|
||||||
sight.parent = this._ship
|
sight.parent = this._ship
|
||||||
|
//sight.rotation.x = -Math.PI / 2;
|
||||||
const signtMaterial = new StandardMaterial("sightMaterial", DefaultScene.MainScene);
|
const signtMaterial = new StandardMaterial("sightMaterial", DefaultScene.MainScene);
|
||||||
signtMaterial.emissiveColor = Color3.Yellow();
|
signtMaterial.emissiveColor = Color3.Yellow();
|
||||||
signtMaterial.ambientColor = Color3.Yellow();
|
signtMaterial.ambientColor = Color3.Yellow();
|
||||||
sight.material = signtMaterial;
|
sight.material = signtMaterial;
|
||||||
sight.position = new Vector3(0, 2, 125);
|
sight.position = new Vector3(0, 2, 125);
|
||||||
let i = Date.now();
|
sight.renderingGroupId = 3;
|
||||||
|
let i = 0;
|
||||||
DefaultScene.MainScene.onBeforeRenderObservable.add(() => {
|
DefaultScene.MainScene.onBeforeRenderObservable.add(() => {
|
||||||
if (Date.now() - i > 50 && this._active == true) {
|
if (i++ % 10 == 0) {
|
||||||
this.applyForce();
|
this.applyForce();
|
||||||
i = Date.now();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._active = true;
|
this._active = true;
|
||||||
}
|
}
|
||||||
private async initialize() {
|
private async initialize() {
|
||||||
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "cockpit2.glb", DefaultScene.MainScene);
|
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "ship1.glb", DefaultScene.MainScene);
|
||||||
const shipMesh = importMesh.meshes[0];
|
const shipMesh = importMesh.meshes[0];
|
||||||
shipMesh.id = "shipMesh";
|
shipMesh.id = "shipMesh";
|
||||||
shipMesh.name = "shipMesh";
|
shipMesh.name = "shipMesh";
|
||||||
shipMesh.parent = this._ship;
|
shipMesh.parent = this._ship;
|
||||||
shipMesh.rotation.y = Math.PI;
|
//shipMesh.rotation.y = Angle.FromDegrees(90).radians();
|
||||||
shipMesh.position.y = 1;
|
//shipMesh.rotation.y = Math.PI;
|
||||||
|
//shipMesh.position.y = 1;
|
||||||
shipMesh.position.z = -1;
|
shipMesh.position.z = -1;
|
||||||
shipMesh.renderingGroupId = 3;
|
shipMesh.renderingGroupId = 3;
|
||||||
const light = new PointLight("ship.light", new Vector3(0, 1, .9), DefaultScene.MainScene);
|
const light = new PointLight("ship.light", new Vector3(0, .5, .1), DefaultScene.MainScene);
|
||||||
light.intensity = 4;
|
light.intensity = 4;
|
||||||
light.includedOnlyMeshes = [shipMesh];
|
light.includedOnlyMeshes = [shipMesh];
|
||||||
for (const mesh of shipMesh.getChildMeshes()) {
|
for (const mesh of shipMesh.getChildMeshes()) {
|
||||||
@ -212,7 +216,7 @@ export class Ship {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
light.parent = this._ship;
|
light.parent = this._ship;
|
||||||
DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4;
|
//DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
148
src/sphereLightmap.ts
Normal file
148
src/sphereLightmap.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { DynamicTexture, Scene, Vector3 } from "@babylonjs/core";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a lightmap texture for a sphere with two directional lights
|
||||||
|
* @param name - Texture name
|
||||||
|
* @param size - Texture resolution (e.g., 512, 1024)
|
||||||
|
* @param scene - Babylon scene
|
||||||
|
* @param brightLightDir - Direction of bright light (will be normalized)
|
||||||
|
* @param brightIntensity - Intensity of bright light (0-1)
|
||||||
|
* @param dimLightDir - Direction of dim light (will be normalized)
|
||||||
|
* @param dimIntensity - Intensity of dim light (0-1)
|
||||||
|
* @param ambientIntensity - Base ambient light (0-1)
|
||||||
|
* @returns DynamicTexture with baked lighting
|
||||||
|
*/
|
||||||
|
export function createSphereLightmap(
|
||||||
|
name: string,
|
||||||
|
size: number,
|
||||||
|
scene: Scene,
|
||||||
|
brightLightDir: Vector3 = new Vector3(1, 0, 0),
|
||||||
|
brightIntensity: number = 1.0,
|
||||||
|
dimLightDir: Vector3 = new Vector3(-1, 0, 0),
|
||||||
|
dimIntensity: number = 0.2,
|
||||||
|
ambientIntensity: number = 0.1
|
||||||
|
): DynamicTexture {
|
||||||
|
const texture = new DynamicTexture(name, { width: size, height: size }, scene, false);
|
||||||
|
const context = texture.getContext();
|
||||||
|
const imageData = context.createImageData(size, size);
|
||||||
|
|
||||||
|
// Normalize light directions
|
||||||
|
const brightDir = brightLightDir.normalize();
|
||||||
|
const dimDir = dimLightDir.normalize();
|
||||||
|
|
||||||
|
// Generate lightmap
|
||||||
|
for (let y = 0; y < size; y++) {
|
||||||
|
for (let x = 0; x < size; x++) {
|
||||||
|
// Convert pixel coordinates to UV (0-1)
|
||||||
|
const u = x / (size - 1);
|
||||||
|
const v = y / (size - 1);
|
||||||
|
|
||||||
|
// Convert UV to 3D position on unit sphere
|
||||||
|
// Using spherical coordinates: theta (longitude), phi (latitude)
|
||||||
|
const theta = u * Math.PI * 2; // 0 to 2π
|
||||||
|
const phi = v * Math.PI; // 0 to π
|
||||||
|
|
||||||
|
// Convert spherical to Cartesian (unit sphere)
|
||||||
|
const normal = new Vector3(
|
||||||
|
Math.sin(phi) * Math.cos(theta),
|
||||||
|
Math.cos(phi),
|
||||||
|
Math.sin(phi) * Math.sin(theta)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate lighting from bright light
|
||||||
|
// Lambertian diffuse: max(0, dot(normal, lightDir))
|
||||||
|
const brightDot = Vector3.Dot(normal, brightDir);
|
||||||
|
const brightLight = Math.max(0, brightDot) * brightIntensity;
|
||||||
|
|
||||||
|
// Calculate lighting from dim light
|
||||||
|
const dimDot = Vector3.Dot(normal, dimDir);
|
||||||
|
const dimLight = Math.max(0, dimDot) * dimIntensity;
|
||||||
|
|
||||||
|
// Combine all lighting
|
||||||
|
const totalLight = ambientIntensity + brightLight + dimLight;
|
||||||
|
|
||||||
|
// Clamp to 0-1 range
|
||||||
|
const intensity = Math.min(1, Math.max(0, totalLight));
|
||||||
|
|
||||||
|
// Convert to 0-255 grayscale
|
||||||
|
const brightness = Math.floor(intensity * 255);
|
||||||
|
|
||||||
|
// Set pixel (RGBA)
|
||||||
|
const index = (y * size + x) * 4;
|
||||||
|
imageData.data[index + 0] = brightness; // R
|
||||||
|
imageData.data[index + 1] = brightness; // G
|
||||||
|
imageData.data[index + 2] = brightness; // B
|
||||||
|
imageData.data[index + 3] = 255; // A (fully opaque)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write image data to texture
|
||||||
|
context.putImageData(imageData, 0, 0);
|
||||||
|
texture.update();
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a colored lightmap with tinted lights
|
||||||
|
*/
|
||||||
|
export function createColoredSphereLightmap(
|
||||||
|
name: string,
|
||||||
|
size: number,
|
||||||
|
scene: Scene,
|
||||||
|
brightLightDir: Vector3 = new Vector3(1, 0, 0),
|
||||||
|
brightColor: { r: number; g: number; b: number } = { r: 1, g: 1, b: 0.8 },
|
||||||
|
brightIntensity: number = 1.0,
|
||||||
|
dimLightDir: Vector3 = new Vector3(-1, 0, 0),
|
||||||
|
dimColor: { r: number; g: number; b: number } = { r: 0.3, g: 0.3, b: 0.5 },
|
||||||
|
dimIntensity: number = 0.2,
|
||||||
|
ambientColor: { r: number; g: number; b: number } = { r: 0.1, g: 0.1, b: 0.1 }
|
||||||
|
): DynamicTexture {
|
||||||
|
const texture = new DynamicTexture(name, { width: size, height: size }, scene, false);
|
||||||
|
const context = texture.getContext();
|
||||||
|
const imageData = context.createImageData(size, size);
|
||||||
|
|
||||||
|
const brightDir = brightLightDir.normalize();
|
||||||
|
const dimDir = dimLightDir.normalize();
|
||||||
|
|
||||||
|
for (let y = 0; y < size; y++) {
|
||||||
|
for (let x = 0; x < size; x++) {
|
||||||
|
const u = x / (size - 1);
|
||||||
|
const v = y / (size - 1);
|
||||||
|
|
||||||
|
const theta = u * Math.PI * 2;
|
||||||
|
const phi = v * Math.PI;
|
||||||
|
|
||||||
|
const normal = new Vector3(
|
||||||
|
Math.sin(phi) * Math.cos(theta),
|
||||||
|
Math.cos(phi),
|
||||||
|
Math.sin(phi) * Math.sin(theta)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate lighting from each source
|
||||||
|
const brightDot = Math.max(0, Vector3.Dot(normal, brightDir)) * brightIntensity;
|
||||||
|
const dimDot = Math.max(0, Vector3.Dot(normal, dimDir)) * dimIntensity;
|
||||||
|
|
||||||
|
// Combine colored lights
|
||||||
|
const r = ambientColor.r + (brightColor.r * brightDot) + (dimColor.r * dimDot);
|
||||||
|
const g = ambientColor.g + (brightColor.g * brightDot) + (dimColor.g * dimDot);
|
||||||
|
const b = ambientColor.b + (brightColor.b * brightDot) + (dimColor.b * dimDot);
|
||||||
|
|
||||||
|
// Clamp and convert to 0-255
|
||||||
|
const red = Math.floor(Math.min(1, Math.max(0, r)) * 255);
|
||||||
|
const green = Math.floor(Math.min(1, Math.max(0, g)) * 255);
|
||||||
|
const blue = Math.floor(Math.min(1, Math.max(0, b)) * 255);
|
||||||
|
|
||||||
|
const index = (y * size + x) * 4;
|
||||||
|
imageData.data[index + 0] = red;
|
||||||
|
imageData.data[index + 1] = green;
|
||||||
|
imageData.data[index + 2] = blue;
|
||||||
|
imageData.data[index + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.putImageData(imageData, 0, 0);
|
||||||
|
texture.update();
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import {
|
|||||||
AbstractMesh,
|
AbstractMesh,
|
||||||
Color3, InstancedMesh,
|
Color3, InstancedMesh,
|
||||||
Mesh,
|
Mesh,
|
||||||
MeshBuilder, Observable,
|
MeshBuilder, NoiseProceduralTexture, Observable,
|
||||||
ParticleHelper,
|
ParticleHelper,
|
||||||
ParticleSystem,
|
ParticleSystem,
|
||||||
ParticleSystemSet,
|
ParticleSystemSet,
|
||||||
@ -10,12 +10,13 @@ import {
|
|||||||
PhysicsAggregate, PhysicsBody,
|
PhysicsAggregate, PhysicsBody,
|
||||||
PhysicsMotionType,
|
PhysicsMotionType,
|
||||||
PhysicsShapeType, PhysicsViewer,
|
PhysicsShapeType, PhysicsViewer,
|
||||||
SceneLoader,
|
SceneLoader, StandardMaterial,
|
||||||
Vector3
|
Vector3
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
import {DefaultScene} from "./defaultScene";
|
import {DefaultScene} from "./defaultScene";
|
||||||
import {ScoreEvent} from "./scoreboard";
|
import {ScoreEvent} from "./scoreboard";
|
||||||
import {Debug} from "@babylonjs/core/Legacy/legacy";
|
import {Debug} from "@babylonjs/core/Legacy/legacy";
|
||||||
|
import {createSphereLightmap} from "./sphereLightmap";
|
||||||
let _particleData: any = null;
|
let _particleData: any = null;
|
||||||
|
|
||||||
export class Rock {
|
export class Rock {
|
||||||
@ -50,35 +51,35 @@ export class RockFactory {
|
|||||||
console.log(`Created ${this._poolSize} explosion particle systems in pool`);
|
console.log(`Created ${this._poolSize} explosion particle systems in pool`);
|
||||||
|
|
||||||
if (!this._rockMesh) {
|
if (!this._rockMesh) {
|
||||||
console.log('loading mesh');
|
await this.loadMesh();
|
||||||
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "asteroid2.glb", DefaultScene.MainScene);
|
|
||||||
this._rockMesh = importMesh.meshes[1].clone("asteroid", null, false);
|
|
||||||
this._rockMesh.setParent(null);
|
|
||||||
this._rockMesh.setEnabled(false);
|
|
||||||
|
|
||||||
//importMesh.meshes[1].dispose();
|
|
||||||
console.log(importMesh.meshes);
|
|
||||||
if (!this._rockMaterial) {
|
|
||||||
this._rockMaterial = this._rockMesh.material.clone("asteroid") as PBRMaterial;
|
|
||||||
this._rockMaterial.name = 'asteroid-material';
|
|
||||||
this._rockMaterial.id = 'asteroid-material';
|
|
||||||
const material = (this._rockMaterial as PBRMaterial)
|
|
||||||
//material.albedoTexture = null;
|
|
||||||
//material.ambientColor = new Color3(.4, .4 ,.4);
|
|
||||||
material.albedoColor = new Color3(.4, .4 ,.4);
|
|
||||||
//material.ambientTexture = material.albedoTexture;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//material.albedoColor = new Color3(1, 1, 1);
|
|
||||||
//material.emissiveColor = new Color3(1, 1, 1);
|
|
||||||
this._rockMesh.material = this._rockMaterial;
|
|
||||||
importMesh.meshes[1].dispose(false, true);
|
|
||||||
importMesh.meshes[0].dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static async loadMesh() {
|
||||||
|
console.log('loading mesh');
|
||||||
|
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "asteroid2.glb", DefaultScene.MainScene);
|
||||||
|
this._rockMesh = importMesh.meshes[1].clone("asteroid", null, false);
|
||||||
|
this._rockMesh.setParent(null);
|
||||||
|
this._rockMesh.setEnabled(false);
|
||||||
|
|
||||||
|
//importMesh.meshes[1].dispose();
|
||||||
|
console.log(importMesh.meshes);
|
||||||
|
if (!this._rockMaterial) {
|
||||||
|
this._rockMaterial = this._rockMesh.material.clone("asteroid") as PBRMaterial;
|
||||||
|
|
||||||
|
this._rockMaterial.name = 'asteroid-material';
|
||||||
|
this._rockMaterial.id = 'asteroid-material';
|
||||||
|
const material = (this._rockMaterial as PBRMaterial)
|
||||||
|
const noiseTexture = new NoiseProceduralTexture("asteroid-noise", 256, DefaultScene.MainScene);
|
||||||
|
noiseTexture.brightness = 0.6; // Brighter base color
|
||||||
|
noiseTexture.octaves = 4; // More detaila
|
||||||
|
material.albedoTexture = noiseTexture;
|
||||||
|
material.roughness = 1;
|
||||||
|
|
||||||
|
this._rockMesh.material = material;
|
||||||
|
importMesh.meshes[1].dispose(false, true);
|
||||||
|
importMesh.meshes[0].dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
private static getExplosionFromPool(): ParticleSystemSet | null {
|
private static getExplosionFromPool(): ParticleSystemSet | null {
|
||||||
return this._explosionPool.pop() || null;
|
return this._explosionPool.pop() || null;
|
||||||
}
|
}
|
||||||
@ -102,19 +103,22 @@ export class RockFactory {
|
|||||||
rock.id = "asteroid-" + i;
|
rock.id = "asteroid-" + i;
|
||||||
rock.metadata = {type: 'asteroid'};
|
rock.metadata = {type: 'asteroid'};
|
||||||
rock.setEnabled(true);
|
rock.setEnabled(true);
|
||||||
console.log(rock.getBoundingInfo());
|
|
||||||
const agg = new PhysicsAggregate(rock, PhysicsShapeType.CONVEX_HULL, {
|
// PhysicsAggregate will automatically compute sphere size from mesh bounding info
|
||||||
|
// The mesh scaling is already applied, so Babylon will create correctly sized physics shape
|
||||||
|
const agg = new PhysicsAggregate(rock, PhysicsShapeType.SPHERE, {
|
||||||
mass: 10000,
|
mass: 10000,
|
||||||
restitution: .5,
|
restitution: .5
|
||||||
|
// Don't pass radius - let Babylon compute from scaled mesh bounds
|
||||||
}, DefaultScene.MainScene);
|
}, DefaultScene.MainScene);
|
||||||
const body =agg.body;
|
const body = agg.body;
|
||||||
|
|
||||||
if (!this._viewer) {
|
if (!this._viewer) {
|
||||||
this._viewer = new PhysicsViewer(DefaultScene.MainScene);
|
// this._viewer = new PhysicsViewer(DefaultScene.MainScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
//this._viewer.showBody(body);
|
// this._viewer.showBody(body);
|
||||||
body.setLinearDamping(0);
|
body.setLinearDamping(0)
|
||||||
body.setMotionType(PhysicsMotionType.DYNAMIC);
|
body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||||
body.setCollisionCallbackEnabled(true);
|
body.setCollisionCallbackEnabled(true);
|
||||||
let scaling = Vector3.One();
|
let scaling = Vector3.One();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user