Skip to content

Commit 56030d7

Browse files
committed
release: v0.1.14
1 parent ed584b5 commit 56030d7

File tree

3 files changed

+62
-17
lines changed

3 files changed

+62
-17
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "airshipone",
3-
"version": "0.1.13",
3+
"version": "0.1.14",
44
"author": "Timeless Prototype",
55
"license": "MIT",
66
"homepage": "https://timelessp.github.io/airshipone/",

public/version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
// Generated from package.json by scripts/write-version.mjs.
2-
export const APP_VERSION = '0.1.13';
2+
export const APP_VERSION = '0.1.14';

src/main.ts

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ const renderer = new THREE.WebGLRenderer({ antialias: false });
686686
renderer.setSize(320, 320, false);
687687
renderer.setPixelRatio(1);
688688
renderer.shadowMap.enabled = true;
689+
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
689690
canvasWrap.appendChild(renderer.domElement);
690691

691692
const scene = new THREE.Scene();
@@ -697,6 +698,17 @@ camera.lookAt(0, 1.2, 0);
697698

698699
const sunLight = new THREE.DirectionalLight(0xffffff, 1);
699700
sunLight.position.set(3, 2, 4);
701+
sunLight.castShadow = true;
702+
sunLight.shadow.mapSize.set(1536, 1536);
703+
sunLight.shadow.radius = 1.6;
704+
sunLight.shadow.bias = -0.0002;
705+
sunLight.shadow.normalBias = 0.02;
706+
sunLight.shadow.camera.near = 0.5;
707+
sunLight.shadow.camera.far = 120;
708+
sunLight.shadow.camera.left = -10;
709+
sunLight.shadow.camera.right = 10;
710+
sunLight.shadow.camera.top = 8;
711+
sunLight.shadow.camera.bottom = -8;
700712
const sunTarget = new THREE.Object3D();
701713
sunTarget.position.set(0, 0, 0);
702714
sunLight.target = sunTarget;
@@ -796,21 +808,46 @@ const updateGlobalLightingFromUtc = (utcMs: number) => {
796808
-Math.cos(azimuthRad) * Math.cos(elevationRad)
797809
).normalize();
798810

799-
const distanceScale = 12;
800-
sunLight.position.copy(sunDirection).multiplyScalar(distanceScale);
801-
sunTarget.position.set(0, 0, 0);
811+
const interiorCenterX = (interiorMinX + interiorMaxX) * 0.5;
812+
const interiorCenterZ = (interiorMinZ + interiorMaxZ) * 0.5;
813+
const shadowTarget = new THREE.Vector3(interiorCenterX, playerPosition.y - playerEyeHeightM + 1.15, interiorCenterZ);
814+
const distanceScale = 40;
815+
sunTarget.position.copy(shadowTarget);
816+
sunLight.position.copy(shadowTarget).addScaledVector(sunDirection, distanceScale);
817+
818+
const cameraToFloorDistance = Math.max(1, Math.abs(camera.position.y - shadowTarget.y));
819+
const viewHalfHeightAtFloor = Math.tan((camera.fov * DEG_TO_RAD) / 2) * cameraToFloorDistance;
820+
const viewHalfWidthAtFloor = viewHalfHeightAtFloor * Math.max(1, camera.aspect);
821+
const interiorHalfWidth = Math.max(2.5, (interiorMaxX - interiorMinX) * 0.5 + 1.8);
822+
const interiorHalfDepth = Math.max(4.5, (interiorMaxZ - interiorMinZ) * 0.5 + 2.4);
823+
const interiorRadius = Math.hypot(interiorHalfWidth, interiorHalfDepth);
824+
const visibleRadius = Math.hypot(viewHalfWidthAtFloor + 6.0, viewHalfHeightAtFloor + 14.0);
825+
const shadowRadius = Math.max(interiorRadius, visibleRadius);
826+
sunLight.shadow.camera.left = -shadowRadius;
827+
sunLight.shadow.camera.right = shadowRadius;
828+
sunLight.shadow.camera.top = shadowRadius;
829+
sunLight.shadow.camera.bottom = -shadowRadius;
830+
sunLight.shadow.camera.near = 0.5;
831+
sunLight.shadow.camera.far = Math.max(180, distanceScale + (shadowRadius * 2.4));
832+
sunLight.shadow.camera.updateProjectionMatrix();
802833

803834
const distanceFactor = 1 / Math.max(0.25, simulation.planetDistanceAu) ** 2;
804-
const dayFactor = clampNumber((elevationDeg + 8) / 68, 0, 1);
805-
sunLight.intensity = distanceFactor * (0.02 + dayFactor * 1.15);
806-
ambientLight.intensity = distanceFactor * (0.06 + dayFactor * 0.32);
807-
808-
const warmFactor = clampNumber((18 - elevationDeg) / 30, 0, 1);
809-
sunLight.color.setRGB(1, 1 - warmFactor * 0.18, 1 - warmFactor * 0.38);
835+
const sunAboveFactor = clampNumber(Math.sin(Math.max(0, elevationRad)), 0, 1);
836+
const belowHorizonTaper = elevationDeg >= 0
837+
? 1
838+
: clampNumber(1 - ((-elevationDeg) / 4.5), 0, 1);
839+
const twilightTail = elevationDeg < 0 ? 0.06 * belowHorizonTaper : 0;
840+
const directSunFactor = (sunAboveFactor * belowHorizonTaper) + twilightTail;
841+
sunLight.intensity = distanceFactor * directSunFactor * 2.45;
842+
ambientLight.intensity = distanceFactor * (0.03 + directSunFactor * 0.31);
843+
sunLight.castShadow = directSunFactor > 0.015;
844+
845+
const warmFactor = clampNumber((9 - elevationDeg) / 14, 0, 1);
846+
sunLight.color.setRGB(1, 1 - warmFactor * 0.28, 1 - warmFactor * 0.58);
810847
ambientLight.color.setRGB(
811-
0.72 + dayFactor * 0.28,
812-
0.75 + dayFactor * 0.25,
813-
0.84 + dayFactor * 0.16
848+
0.60 + directSunFactor * 0.36,
849+
0.63 + directSunFactor * 0.34,
850+
0.72 + directSunFactor * 0.24
814851
);
815852
};
816853

@@ -979,6 +1016,9 @@ const createModuleMesh = (moduleDoc: GeneratedModule): THREE.Group => {
9791016
: new THREE.CylinderGeometry(block.radiusTop, block.radiusBottom, block.height, block.radialSegments);
9801017
const material = getMaterial(block);
9811018
const mesh = new THREE.Mesh(geometry, material);
1019+
const isWindow = block.role.includes('window');
1020+
mesh.receiveShadow = !isWindow;
1021+
mesh.castShadow = !isWindow;
9821022
mesh.name = `${moduleDoc.id}:${block.id}`;
9831023
if (block.role === 'furniture-paper-a4') {
9841024
mesh.userData.interactionKind = 'captains-letter-paper';
@@ -1178,8 +1218,8 @@ const getActiveLevelOffset = (): number => {
11781218
let best = levels[0] ?? 0;
11791219
let bestDistance = Number.POSITIVE_INFINITY;
11801220
for (const level of levels) {
1181-
const levelY = level * ladderDeckLevelHeightM;
1182-
const distance = Math.abs(playerPosition.y - levelY);
1221+
const standingEyeY = (level * ladderDeckLevelHeightM) + playerEyeHeightM;
1222+
const distance = Math.abs(playerPosition.y - standingEyeY);
11831223
if (distance < bestDistance) {
11841224
bestDistance = distance;
11851225
best = level;
@@ -1672,7 +1712,8 @@ const alignPlayerToClimbVolume = (volume: ModuleVolume, deltaSeconds: number) =>
16721712
const halfY = sy / 2;
16731713
const levelOffset = getClimbVolumeLevelOffset(volume);
16741714
const hasBelow = levelOffset !== null ? ladderLevelOffsets.includes(levelOffset - 1) : false;
1675-
const minY = Math.max(cy - halfY + 0.05, hasBelow ? -Infinity : playerEyeHeightM);
1715+
const levelStandingEyeY = ((levelOffset ?? 0) * ladderDeckLevelHeightM) + playerEyeHeightM;
1716+
const minY = Math.max(cy - halfY + 0.05, hasBelow ? -Infinity : levelStandingEyeY);
16761717
const maxY = cy + halfY - 0.05;
16771718

16781719
const targetX = cx + clamp(activeClimbOffsetX, -((sx / 2) - 0.03), (sx / 2) - 0.03);
@@ -2647,6 +2688,10 @@ const mapModuleIndexAfterTopologyMutation = (oldIndex: number, mutation: Topolog
26472688
return oldIndex > mutation.index ? oldIndex - 1 : oldIndex;
26482689
}
26492690

2691+
if (mutation.kind === 'ladder-level') {
2692+
return null;
2693+
}
2694+
26502695
return oldIndex;
26512696
};
26522697

0 commit comments

Comments
 (0)