Refine Gwanaksan summit marker proportions and inscription

This commit is contained in:
2026-10-31 09:49:29 +09:00
parent 28a45ff8e3
commit 1b8698565a
20 changed files with 543 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
export const SUMMIT_MARKER = {
assetRevision: '8de117c42335',
buriedDepth: 0.12,
footHeight: 0.18,
} as const;
File diff suppressed because one or more lines are too long
+3 -1
View File
@@ -4,6 +4,7 @@ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { STRUCTURES, STRUCTURE_ASSETS } from '../constants/structures.ts';
import { SUMMIT_RELIEF } from '../constants/summitRelief.ts';
import { SUMMIT_PLATEAU } from '../constants/summitPlateau.ts';
import { SUMMIT_MARKER } from '../constants/summitMarker.ts';
import { summitPosition } from '../controls/summitCoordinates.ts';
export type StructureAssets = Map<string, Group>;
@@ -14,7 +15,8 @@ export async function loadStructures(includeRelief = false): Promise<StructureAs
const ids = [...STRUCTURES.towers.map(s => s.id), 'weather-radar', ...STRUCTURES.decks.map(s => s.id),
...(includeRelief ? [SUMMIT_RELIEF.assetId, SUMMIT_PLATEAU.marker.assetId] : [])];
return new Map(await Promise.all(ids.map(async id => {
const model = await loader.loadAsync(STRUCTURE_ASSETS.baseUrl + '/' + id + '.glb');
const revision = id === SUMMIT_PLATEAU.marker.assetId ? `?v=${SUMMIT_MARKER.assetRevision}` : '';
const model = await loader.loadAsync(STRUCTURE_ASSETS.baseUrl + '/' + id + '.glb' + revision);
return [id, model.scene] as const;
})));
}
+19 -2
View File
@@ -1,5 +1,6 @@
import { Group, Mesh, type Material, type BufferGeometry, type MeshStandardMaterial } from 'three';
import { Box3, Group, Mesh, Vector3, type Material, type BufferGeometry, type MeshStandardMaterial } from 'three';
import { SUMMIT_PLATEAU } from '../constants/summitPlateau.ts';
import { SUMMIT_MARKER } from '../constants/summitMarker.ts';
export function createSummitMarker(asset: Group, start: {x: number; z: number},
groundAt: (x: number, z: number) => number, rockMaterial: MeshStandardMaterial) {
@@ -7,6 +8,23 @@ export function createSummitMarker(asset: Group, start: {x: number; z: number},
group.name = SUMMIT_PLATEAU.marker.assetId;
const [x,z] = SUMMIT_PLATEAU.marker.offset;
group.position.set(start.x+x, groundAt(start.x+x,start.z+z), start.z+z);
group.add(asset);
group.updateMatrixWorld(true);
const base = new Box3().setFromObject(asset).min.y;
const point = new Vector3();
let seatingOffset = Infinity;
asset.traverse(object => {
if (!(object instanceof Mesh)) return;
const positions = object.geometry.getAttribute('position');
for (let i=0; i<positions.count; i++) {
point.fromBufferAttribute(positions,i).applyMatrix4(object.matrixWorld);
if (point.y-base > SUMMIT_MARKER.footHeight) continue;
seatingOffset = Math.min(seatingOffset,
groundAt(point.x,point.z)-SUMMIT_MARKER.buriedDepth-point.y);
}
});
if (Number.isFinite(seatingOffset)) group.position.y += seatingOffset;
group.updateMatrixWorld(true);
const granite = rockMaterial.clone();
granite.vertexColors = false;
const materials = new Set<Material>([granite]);
@@ -17,7 +35,6 @@ export function createSummitMarker(asset: Group, start: {x: number; z: number},
(Array.isArray(object.material) ? object.material : [object.material]).forEach(m => materials.add(m));
if (object.name.replaceAll('_',' ') === 'Marker granite body') object.material = granite;
});
group.add(asset);
return { group, dispose() {
geometries.forEach(g => g.dispose());
materials.forEach(m => m.dispose());