Skip to content

Commit

Permalink
Merge pull request #3 from mstop4/bounds-calc
Browse files Browse the repository at this point in the history
Add bounds calculation, centering of camera to map
  • Loading branch information
mstop4 authored Oct 3, 2023
2 parents 32330de + 48f1a8a commit 94340f9
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 68 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<script type="module" src="src/main.ts"></script>
<div id="legendContainer"></div>
<div id="scaleContainer">
<span id="scaleNumber">100 blocks</span>
<span id="scaleNumber">? blocks</span>
<div class="scaleLineContainer">
<div class="scaleEnd"></div>
<div class="scaleLine"></div>
Expand Down
28 changes: 17 additions & 11 deletions src/components/objects/mapObjects.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import * as THREE from 'three';
import {
Mesh,
type MeshStandardMaterial,
BoxGeometry,
CylinderGeometry,
SphereGeometry,
} from 'three';
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
import { Line2 } from 'three/addons/lines/Line2.js';
Expand Down Expand Up @@ -65,8 +71,8 @@ export function createPath(pathData: PathData, id: number) {
}

export function createRoom(roomData: RoomData, id: number) {
let roomMesh: THREE.Mesh | null = null;
const material = getMaterial('room') as THREE.MeshStandardMaterial;
let roomMesh: Mesh | null = null;
const material = getMaterial('room') as MeshStandardMaterial;

if (isCuboidRoomData(roomData)) {
const { corners } = roomData;
Expand All @@ -75,22 +81,22 @@ export function createRoom(roomData: RoomData, id: number) {
const height = Math.abs(corners[1][1] - corners[0][1]) + 1;
const length = Math.abs(corners[1][2] - corners[0][2]) + 1;

const roomGeom = new THREE.BoxGeometry(width, height, length);
roomMesh = new THREE.Mesh(roomGeom, material);
const roomGeom = new BoxGeometry(width, height, length);
roomMesh = new Mesh(roomGeom, material);
roomMesh.position.x = (corners[0][0] + corners[1][0]) / 2;
roomMesh.position.y = (corners[0][1] + corners[1][1]) / 2;
roomMesh.position.z = (corners[0][2] + corners[1][2]) / 2;
} else if (isCylindricalRoomData(roomData)) {
const { height, radius, bottomCenter } = roomData;

const roomGeom = new THREE.CylinderGeometry(
const roomGeom = new CylinderGeometry(
radius + 1,
radius + 1,
height + 1,
8,
3,
);
roomMesh = new THREE.Mesh(roomGeom, material);
roomMesh = new Mesh(roomGeom, material);
roomMesh.position.x = bottomCenter[0];
roomMesh.position.y = bottomCenter[1] + height / 2;
roomMesh.position.z = bottomCenter[2];
Expand Down Expand Up @@ -138,8 +144,8 @@ export function createDoor(doorData: DoorData, id: number) {
height = doorHeight;
}

const doorGeom = new THREE.BoxGeometry(width, height, length);
const doorMesh = new THREE.Mesh(doorGeom, material);
const doorGeom = new BoxGeometry(width, height, length);
const doorMesh = new Mesh(doorGeom, material);
doorMesh.position.x = location[0];
doorMesh.position.y = location[1] + height / 2;
doorMesh.position.z = location[2];
Expand All @@ -156,12 +162,12 @@ export function createPortal(portalData: PortalData, id: number) {
const material = getMaterial('portal');

// Create portal marker
const portalGeom = new THREE.SphereGeometry(
const portalGeom = new SphereGeometry(
portalSize,
portalWidthSegments,
portalHeightSegments,
);
const portalMesh = new THREE.Mesh(portalGeom, material);
const portalMesh = new Mesh(portalGeom, material);
portalMesh.position.x = location[0];
portalMesh.position.y = location[1] + portalSize / 2;
portalMesh.position.z = location[2];
Expand Down
58 changes: 35 additions & 23 deletions src/components/setup/camera.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import * as THREE from 'three';
import { OrthographicCamera, type WebGLRenderer, Vector3 } from 'three';
import { MapControls } from 'three/addons/controls/MapControls.js';
import { getMapBounds } from './mapScene';
import { CameraState } from '../../types';

export let camera: THREE.OrthographicCamera;
export let camera: OrthographicCamera;
export let cameraControls: MapControls;
let lastZoom: number;

const camX = -1;
const camY = 1;
const camZ = 1;
let initialCameraPosition: Vector3;
export const viewScale = 4;
const zoomConst = 0.5133420832795057; // used to calculate the relationship between camera zoom and the scale on the gui
const guiScaleSize = 100;
Expand All @@ -17,7 +16,7 @@ const cameraStates: CameraState[] = [];
let scaleNumberElem: HTMLElement | null;

export function setupCamera() {
camera = new THREE.OrthographicCamera(
camera = new OrthographicCamera(
-window.innerWidth / viewScale,
window.innerWidth / viewScale,
window.innerHeight / viewScale,
Expand All @@ -27,30 +26,43 @@ export function setupCamera() {
);
}

export function setupCameraControls(renderer: THREE.WebGLRenderer) {
export function setupCameraControls(renderer: WebGLRenderer) {
cameraControls = new MapControls(camera, renderer.domElement);
cameraControls.enableDamping = false;
camera.position.set(camX, camY, camZ);
camera.lookAt(0, 0, 0);
cameraControls.update();

const { center } = getMapBounds();
initialCameraPosition = new Vector3(
center[0] - 1,
center[1] + 1,
center[2] + 1,
);
lastZoom = 0;

saveCameraState(new Vector3(...center), initialCameraPosition, 1); // Isometric Camera
saveCameraState(
new Vector3(...center),
new Vector3(center[0], 127, center[2]),
1,
); // Overhead Camera
saveCameraState(
new Vector3(center[0], 64, center[2]),
new Vector3(center[0] - 1, 64, center[2]),
1,
); // Side Camera (East)
saveCameraState(
new Vector3(center[0], 64, center[2]),
new Vector3(center[0], 64, center[2] + 1),
1,
); // Side Camera (North)

scaleNumberElem = document.getElementById('scaleNumber');

if (scaleNumberElem !== null) {
onZoomChanged();
cameraControls.addEventListener('change', onZoomChanged);
}

const initCameraPos = getInitialCameraPosition();

saveCameraState(new THREE.Vector3(0, 0, 0), initCameraPos, 1); // Isometric Camera
saveCameraState(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, initCameraPos.y, 0),
1,
); // Overhead Camera
saveCameraState(new THREE.Vector3(0, 64, 0), new THREE.Vector3(-1, 64, 0), 1); // Side Camera (East)
saveCameraState(new THREE.Vector3(0, 64, 0), new THREE.Vector3(0, 64, 1), 1); // Side Camera (North)
loadCameraState(0);
}

function onZoomChanged() {
Expand All @@ -74,8 +86,8 @@ function onZoomChanged() {
}

export function saveCameraState(
target: THREE.Vector3,
position: THREE.Vector3,
target: Vector3,
position: Vector3,
zoom: number,
) {
cameraStates.push({
Expand All @@ -99,5 +111,5 @@ export function loadCameraState(index: number) {
}

export function getInitialCameraPosition() {
return new THREE.Vector3(camX, camY, camZ);
return initialCameraPosition;
}
98 changes: 86 additions & 12 deletions src/components/setup/mapScene.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import * as THREE from 'three';
import {
Scene,
Mesh,
AmbientLight,
DirectionalLight,
PlaneGeometry,
} from 'three';
import {
createDoor,
createPath,
Expand All @@ -8,37 +14,52 @@ import {
import { getMaterial } from './materials';

import { type CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
import { DoorData, PathData, PortalData, RoomData } from '../../types';
import {
DoorData,
MapBounds,
PathData,
PortalData,
RoomData,
} from '../../types';

import featureConfig from '../../config/features.json';
import pathsData from '../../data/paths';
import roomsData from '../../data/rooms';
import doorsData from '../../data/doors';
import portalsData from '../../data/portals';

export let mapScene: THREE.Scene;
const roomObjects: THREE.Mesh[] = [];
const doorObjects: THREE.Mesh[] = [];
const portalObjects: THREE.Mesh[] = [];
const pathObjects: THREE.Mesh[] = [];
export let mapScene: Scene;
const roomObjects: Mesh[] = [];
const doorObjects: Mesh[] = [];
const portalObjects: Mesh[] = [];
const pathObjects: Mesh[] = [];
const labelObjects: CSS2DObject[] = [];
const mapBounds: MapBounds = {
center: [0, 64, 0],
xMin: 0,
xMax: 0,
yMin: 64,
yMax: 64,
zMin: 0,
zMax: 0,
};

export function setupMapScene() {
mapScene = new THREE.Scene();
mapScene = new Scene();

// Set up lights
const light = new THREE.AmbientLight(0xffffff); // soft white light
const light = new AmbientLight(0xffffff); // soft white light
mapScene.add(light);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
const directionalLight = new DirectionalLight(0xffffff, 1);
directionalLight.position.x = 1;
directionalLight.position.y = 1;
directionalLight.position.z = 1;
mapScene.add(directionalLight);

// Lava
if (featureConfig.lavaGeometry) {
const lavaGeom = new THREE.PlaneGeometry(1500, 1500);
const lavaMesh = new THREE.Mesh(lavaGeom, getMaterial('lava'));
const lavaGeom = new PlaneGeometry(1500, 1500);
const lavaMesh = new Mesh(lavaGeom, getMaterial('lava'));
lavaMesh.rotation.x = Math.PI / 2;
lavaMesh.position.y = 32;
mapScene.add(lavaMesh);
Expand All @@ -59,6 +80,24 @@ export function setupMapScene() {
labelObjects.push(roomLabel);
}

if (object.shape === 'cuboid') {
const { corners } = object;
checkMapBounds(corners[0][0], corners[1][1], corners[0][2]);
checkMapBounds(corners[1][0], corners[0][1], corners[1][2]);
} else if (object.shape === 'cylinder') {
const { radius, height, bottomCenter } = object;
checkMapBounds(
bottomCenter[0] - radius,
bottomCenter[1],
bottomCenter[2] - radius,
);
checkMapBounds(
bottomCenter[0] + radius,
bottomCenter[1] + height,
bottomCenter[2] + radius,
);
}

return incrementId;
});

Expand All @@ -67,6 +106,12 @@ export function setupMapScene() {
if (pathMesh !== null) {
pathObjects.push(pathMesh);
mapScene.add(pathMesh);

const { points } = object;
for (const point of points) {
checkMapBounds(...point);
}

return true;
}
return false;
Expand All @@ -76,6 +121,10 @@ export function setupMapScene() {
const doorMesh = createDoor(object, id);
doorObjects.push(doorMesh);
mapScene.add(doorMesh);

const { location } = object;
checkMapBounds(...location);

return true;
});

Expand All @@ -84,12 +133,17 @@ export function setupMapScene() {
portalObjects.push(portalMesh);
mapScene.add(portalMesh);

const { location } = object;
checkMapBounds(...location);

if (portalLabel !== null) {
labelObjects.push(portalLabel);
}

return true;
});

calculateMapCenter();
}

function initMapObjects<T>(
Expand All @@ -104,6 +158,22 @@ function initMapObjects<T>(
}
}

export function checkMapBounds(x: number, y: number, z: number) {
if (x < mapBounds.xMin) mapBounds.xMin = x;
if (x > mapBounds.xMax) mapBounds.xMax = x;
if (y < mapBounds.yMin) mapBounds.yMin = y;
if (y > mapBounds.yMax) mapBounds.yMax = y;
if (z < mapBounds.zMin) mapBounds.zMin = z;
if (z > mapBounds.zMax) mapBounds.zMax = z;
}

function calculateMapCenter() {
const { xMin, yMin, xMax, yMax, zMin, zMax } = mapBounds;
mapBounds.center[0] = (xMin + xMax) / 2;
mapBounds.center[1] = (yMin + yMax) / 2;
mapBounds.center[2] = (zMin + zMax) / 2;
}

export function getMapObjects() {
return {
roomObjects,
Expand All @@ -113,3 +183,7 @@ export function getMapObjects() {
labelObjects,
};
}

export function getMapBounds() {
return mapBounds;
}
8 changes: 4 additions & 4 deletions src/components/setup/materials.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import * as THREE from 'three';
import { type Material, MeshStandardMaterial } from 'three';
import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
import materialDefs from '../../config/materials';

const materials: Record<string, THREE.Material | LineMaterial> = {};
const materials: Record<string, Material | LineMaterial> = {};

export function initMaterials() {
const { mesh, line } = materialDefs;

// Mesh Materials
for (const materialName in mesh) {
const materialDef = mesh[materialName];
materials[materialName] = new THREE.MeshStandardMaterial(materialDef);
materials[materialName] = new MeshStandardMaterial(materialDef);
}

// Line Materials
Expand All @@ -30,6 +30,6 @@ export function initMaterials() {
}
}

export function getMaterial(name: string): THREE.Material {
export function getMaterial(name: string): Material {
return materials[name] ?? null;
}
Loading

0 comments on commit 94340f9

Please sign in to comment.