Skip to content

Commit

Permalink
Merge pull request #218 from vircadia/feature/light-handling
Browse files Browse the repository at this point in the history
Upgrade lightmap / light handling.
  • Loading branch information
digisomni committed May 2, 2024
2 parents 2ae2e36 + 0a052f5 commit 53710db
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 37 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ module.exports = {
"@typescript-eslint/no-use-before-define": ["error"],
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": ["error"],
"@typescript-eslint/no-misused-promises": ["off"],
"object-curly-spacing": "off",
"@typescript-eslint/object-curly-spacing": ["error", "always"],
quotes: "off",
Expand Down Expand Up @@ -327,7 +328,7 @@ module.exports = {
"jsx-quotes": ["error", "prefer-double"],
"key-spacing": "error",
// "keyword-spacing": "error", // TypeScript extension overrides.
"max-len": ["error", { code: 160, tabWidth: 4 }],
"max-len": ["error", { code: 270, tabWidth: 4 }],
"multiline-ternary": ["error", "always-multiline"],
"new-cap": "off",
"new-parens": "error",
Expand Down
5 changes: 5 additions & 0 deletions src/modules/entity/components/components/ModelComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { applicationStore } from "@Stores/index";
import Log from "@Modules/debugging/log";
import { LODManager } from "@Modules/scene/LODManager";
import { LightmapManager } from "@Modules/scene/LightmapManager";
import { LightManager } from "@Modules/scene/LightManager";

const InteractiveModelTypes = [
{ name: "chair", condition: /^(?:animate_sitting|animate_seat)/iu },
Expand Down Expand Up @@ -75,6 +76,10 @@ export class ModelComponent extends MeshComponent {
if (this._gameObject?.getScene()) {
meshes = LightmapManager.applySceneLightmapsToMeshes(meshes, this._gameObject.getScene());
}
// Light Handling
if (this._gameObject?.getScene()) {
LightManager.applyLightProperties(meshes, this._gameObject.getScene());
}

this.mesh = meshes[0];
this.renderGroupId = DEFAULT_MESH_RENDER_GROUP_ID;
Expand Down
34 changes: 17 additions & 17 deletions src/modules/scene/LODManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ import {
// import Log from "../debugging/log";
import { glTF as MeshTypes } from "../../../types/vircadia_gameUse";

export const StringsAsBillboardModes: { [key: string]: MeshTypes.BillboardModes } = {
none: MeshTypes.BillboardModes.BILLBOARDMODE_NONE,
x: MeshTypes.BillboardModes.BILLBOARDMODE_X,
y: MeshTypes.BillboardModes.BILLBOARDMODE_Y,
z: MeshTypes.BillboardModes.BILLBOARDMODE_Z,
all: MeshTypes.BillboardModes.BILLBOARDMODE_ALL,
export const StringsAsBillboardModes: { [key: string]: MeshTypes.BillboardMode } = {
none: MeshTypes.BillboardMode.BILLBOARDMODE_NONE,
x: MeshTypes.BillboardMode.BILLBOARDMODE_X,
y: MeshTypes.BillboardMode.BILLBOARDMODE_Y,
z: MeshTypes.BillboardMode.BILLBOARDMODE_Z,
all: MeshTypes.BillboardMode.BILLBOARDMODE_ALL,
};

export const DistanceTargets: { [key in MeshTypes.LOD.Levels]: number } = {
export const DistanceTargets: { [key in MeshTypes.LOD.Level]: number } = {
LOD0: 0,
LOD1: 15,
LOD2: 30,
LOD3: 60,
LOD4: 120,
};

export const SizeTargets: { [key in MeshTypes.LOD.Levels]: number } = {
export const SizeTargets: { [key in MeshTypes.LOD.Level]: number } = {
LOD0: 1.0,
LOD1: 0.25,
LOD2: 0.1,
Expand All @@ -47,7 +47,7 @@ export interface AutoTarget {
distance: number;
optimizeMesh: boolean;
}
export const AutoTargets: { [key in MeshTypes.LOD.Levels]?: AutoTarget } = {
export const AutoTargets: { [key in MeshTypes.LOD.Level]?: AutoTarget } = {
LOD0: {
quality: 0.9,
distance: DistanceTargets.LOD0,
Expand Down Expand Up @@ -129,8 +129,8 @@ export class LODManager {
}
}

private static setLODMode(mesh: Mesh, mode: MeshTypes.LOD.Modes): void {
if (mode === MeshTypes.LOD.Modes.SIZE) {
private static setLODMode(mesh: Mesh, mode: MeshTypes.LOD.Mode): void {
if (mode === MeshTypes.LOD.Mode.SIZE) {
mesh.useLODScreenCoverage = true;
// Log.debug(
// Log.types.ENTITIES,
Expand Down Expand Up @@ -203,7 +203,7 @@ export class LODManager {
if (
// (mesh.constructor.name === "Mesh" ||
// mesh.constructor.name === "AbstractMesh") &&
parse?.lodLevel === MeshTypes.LOD.Levels.LOD0
parse?.lodLevel === MeshTypes.LOD.Level.LOD0
) {
roots.push({
prefix: parse?.prefix,
Expand All @@ -228,7 +228,7 @@ export class LODManager {
// Process metadata for root mesh.
LODManager.setLODMode(
roots[root].mesh,
roots[root].metadata.vircadia_lod_mode ?? MeshTypes.LOD.Modes.DISTANCE
roots[root].metadata.vircadia_lod_mode ?? MeshTypes.LOD.Mode.DISTANCE
);
LODManager.setLODHide(
roots[root].mesh,
Expand Down Expand Up @@ -264,15 +264,15 @@ export class LODManager {
(!(level in DistanceTargets) &&
!(level in SizeTargets) &&
!(level in AutoTargets)) ||
level === MeshTypes.LOD.Levels.LOD0
level === MeshTypes.LOD.Level.LOD0
) {
continue;
}

const mode = metadata.vircadia_lod_mode ?? MeshTypes.LOD.Modes.DISTANCE;
const mode = metadata.vircadia_lod_mode ?? MeshTypes.LOD.Mode.DISTANCE;

switch (mode) {
case MeshTypes.LOD.Modes.DISTANCE: {
case MeshTypes.LOD.Mode.DISTANCE: {
let distanceTarget =
DistanceTargets[
level as keyof typeof DistanceTargets
Expand All @@ -290,7 +290,7 @@ export class LODManager {

break;
}
case MeshTypes.LOD.Modes.SIZE: {
case MeshTypes.LOD.Mode.SIZE: {
let sizeTarget =
SizeTargets[level as keyof typeof SizeTargets];

Expand Down
44 changes: 44 additions & 0 deletions src/modules/scene/LightManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
//
// LightManager.ts
//
// Created by Kalila on 08 Feb 2024.
// Copyright 2024 Vircadia contributors.
// Copyright 2024 DigiSomni LLC.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

import {
type AbstractMesh,
type Scene,
} from "@babylonjs/core";
import Log from "../debugging/log";

export class LightManager {
private static handleKeyPress = (event: KeyboardEvent) => {
if (event.key === "u") {
const scene = LightManager.currentScene; // Ensure you have a reference to the current scene
const lights = scene.lights;
lights.forEach((light) => {
light.lightmapMode = (light.lightmapMode + 1) % 3;
Log.debug(Log.types.ENTITIES, `Lightmap mode for ${light.name}: ${light.lightmapMode}`);
});
}
};

private static currentScene: Scene;

public static applyLightProperties(meshes: AbstractMesh[], scene: Scene): void {

Check warning on line 33 in src/modules/scene/LightManager.ts

View workflow job for this annotation

GitHub Actions / 🎉 Deploy

'meshes' is defined but never used

Check warning on line 33 in src/modules/scene/LightManager.ts

View workflow job for this annotation

GitHub Actions / 🎉 Deploy

'scene' is defined but never used
// this.currentScene = scene; // Store the current scene reference

// // Find all the lights in the meshes as they are imported.
// const lights = meshes.filter((mesh) => mesh instanceof AbstractMesh && mesh.name.startsWith("Light_"));
// console.info("##### LIGHTS", lights);

// // Ensure we don't add the same event listener more than once
// window.removeEventListener("keyup", this.handleKeyPress);
// window.addEventListener("keyup", this.handleKeyPress);
}
}
118 changes: 108 additions & 10 deletions src/modules/scene/LightmapManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import {
type AbstractMesh,
type Scene,
BaseTexture,
PBRMaterial,
Texture,
} from "@babylonjs/core";
Expand All @@ -21,6 +22,63 @@ import { glTF as MeshTypes } from "../../../types/vircadia_gameUse";

export class LightmapManager {
public static applySceneLightmapsToMeshes(meshes: AbstractMesh[], scene: Scene): AbstractMesh[] {
// ////
// //// HANDLE MASTER LIGHTMAP DATA
// ////

let lightmapColorSpace = null;
let lightmapLevel = null;
let lightmapMode = null;

const foundLightmapMesh = meshes.find((m) => m.name.startsWith(MeshTypes.Lightmap.DATA_MESH_NAME));
if (foundLightmapMesh) {
Log.debug(Log.types.ENTITIES, `Found lightmap mesh: ${foundLightmapMesh.name}`);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const metadataExtras = foundLightmapMesh?.metadata?.gltf?.extras ?? foundLightmapMesh?.parent?.metadata?.gltf?.extras;
const metadata = new MeshTypes.Metadata(metadataExtras as Partial<MeshTypes.MetadataInterface>);

if (metadata.vircadia_lightmap_mode) {
Log.debug(Log.types.ENTITIES, `Found lightmap mode for all meshes as ${metadata.vircadia_lightmap_mode}`);
lightmapMode = String(metadata.vircadia_lightmap_mode) as unknown as MeshTypes.Light.LightmapMode;
}

if (metadata.vircadia_lightmap_level) {
Log.debug(Log.types.ENTITIES, `Found lightmap level for all meshes as ${metadata.vircadia_lightmap_level}`);
lightmapLevel = 2; // Number(metadata.vircadia_lightmap_level);
}

if (metadata.vircadia_lightmap_color_space) {
Log.debug(Log.types.ENTITIES, `Found lightmap color space for all meshes as ${metadata.vircadia_lightmap_color_space}`);
lightmapColorSpace = String(metadata.vircadia_lightmap_color_space) as unknown as MeshTypes.Texture.ColorSpace;
}

foundLightmapMesh.dispose(true, false);
Log.debug(Log.types.ENTITIES, `Deleting lightmap data mesh: ${foundLightmapMesh.name}`);
}

const lights = scene.lights;
lights.forEach((light) => {
switch (lightmapMode) {
case MeshTypes.Light.LightmapMode.DEFAULT:
light.lightmapMode = 0;
break;
case MeshTypes.Light.LightmapMode.SHADOWSONLY:
light.lightmapMode = 1;
break;
case MeshTypes.Light.LightmapMode.SPECULAR:
light.lightmapMode = 2;
break;
default:
light.lightmapMode = 0;
break;
}
Log.debug(Log.types.ENTITIES, `Setting lightmap mode for ${light.name}: ${light.lightmapMode}`);
});

// ////
// //// APPLY LIGHTMAPS TO MESHES FOR EACH MESH
// ////

meshes.forEach((mesh) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const metadataExtras = mesh?.metadata?.gltf?.extras ?? mesh?.parent?.metadata?.gltf?.extras;
Expand All @@ -43,31 +101,71 @@ export class LightmapManager {
if (!(mesh.material instanceof PBRMaterial)) {
Log.error(Log.types.ENTITIES,
`Material type of ${JSON.stringify(mesh.material)}
for: ${mesh.name} is not supported for lightmap application. Need PBRMaterial. Skipping...`);
for: ${mesh.name} is not supported for lightmap application. Need PBRMaterial. Skipping...`);
}

const materialToUse = material as PBRMaterial;

if (materialToUse
&& materialToUse.albedoTexture
&& mesh.material
&& metadata.vircadia_lightmap_texcoord) {
&& Boolean(metadata.vircadia_lightmap_texcoord)) {

Texture.WhenAllReady([materialToUse.albedoTexture], () => {
(mesh.material as PBRMaterial).lightmapTexture = materialToUse.albedoTexture;
(mesh.material as PBRMaterial).useLightmapAsShadowmap = metadata.vircadia_lightmap_use_as_shadowmap ?? true;
try {
const lightmapTexture: Nullable<BaseTexture> = materialToUse.albedoTexture;

if (lightmapTexture) {
(mesh.material as PBRMaterial).lightmapTexture = lightmapTexture;
(mesh.material as PBRMaterial).useLightmapAsShadowmap = metadata.vircadia_lightmap_use_as_shadowmap ?? true;

if ((mesh.material as PBRMaterial).lightmapTexture && metadata.vircadia_lightmap_texcoord) {
(mesh.material as PBRMaterial).lightmapTexture!.coordinatesIndex = metadata.vircadia_lightmap_texcoord;
if ((mesh.material as PBRMaterial).lightmapTexture && metadata.vircadia_lightmap_texcoord) {
(mesh.material as PBRMaterial).lightmapTexture!.coordinatesIndex = metadata.vircadia_lightmap_texcoord;
}
}
} catch (e) {
Log.error(Log.types.ENTITIES, `Error setting lightmap texture for: ${mesh.name}, error: ${e}`);
}
});
} else {

Log.error(Log.types.ENTITIES, `Could not find material or albedo texture for: ${mesh.name}`);
}
}

if (mesh.name.startsWith(MeshTypes.Lightmap.DATA_MESH_NAME)) {
mesh.dispose(true, false);
Log.debug(Log.types.ENTITIES, `Deleting lightmap data mesh: ${mesh.name}`);
if (mesh.material) {
mesh.material?.getActiveTextures().forEach((texture) => {
if (texture instanceof Texture) {
if (lightmapLevel) {
texture.level = lightmapLevel;
}

if (lightmapColorSpace) {
switch (lightmapColorSpace) {
case MeshTypes.Texture.ColorSpace.LINEAR:
Log.debug(Log.types.ENTITIES, `Setting color space for ${mesh.name} to linear.`);
texture.gammaSpace = false;
break;
case MeshTypes.Texture.ColorSpace.GAMMA:
Log.debug(Log.types.ENTITIES, `Setting color space for ${mesh.name} to gamma.`);
texture.gammaSpace = true;
break;
case MeshTypes.Texture.ColorSpace.SRGB:
Log.debug(Log.types.ENTITIES, `Setting color space for ${mesh.name} to sRGB.`);
texture.gammaSpace = true;
break;
default:
Log.debug(Log.types.ENTITIES, `Setting color space for ${mesh.name} to gamma.`);
texture.gammaSpace = true;
break;
}
}

if (lightmapLevel) {
texture.level = lightmapLevel;
}
}
});
}
}
});

Expand Down
Loading

0 comments on commit 53710db

Please sign in to comment.