Merge branch 'feat/hud-scene' into feat/hud-neighbours
# Conflicts: # src/app/features/galaxy-system/galaxy-system-scene.component.ts
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* How a size in pixels becomes a size the scene can draw.
|
||||||
|
*
|
||||||
|
* Sprites in this view are sized angularly rather than in world units, so a star holds the same
|
||||||
|
* share of the screen however far away it is and whatever the window is doing. Pixels are what
|
||||||
|
* the figures are chosen in, though — "a star is between one and a half and six pixels across"
|
||||||
|
* is a statement someone can check by looking — so the two are related through a reference
|
||||||
|
* viewport and field of view, and the pixel figures are exact only at that height.
|
||||||
|
*
|
||||||
|
* Shared rather than restated per renderer: the star field and the rings drawn over it have to
|
||||||
|
* agree, or a ring sits a little wide of the star it belongs to at some window sizes and not at
|
||||||
|
* others.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const REFERENCE_VIEWPORT_HEIGHT_PX = 900;
|
||||||
|
export const REFERENCE_FOV_DEGREES = 55;
|
||||||
|
|
||||||
|
/** Multiply a size in reference pixels by this to get the angular size the material wants. */
|
||||||
|
export const PIXELS_TO_ANGULAR_SIZE = (2 * Math.tan((REFERENCE_FOV_DEGREES * Math.PI) / 180 / 2)) / REFERENCE_VIEWPORT_HEIGHT_PX;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AfterViewInit, Component, effect, ElementRef, OnDestroy, signal, viewChild } from '@angular/core';
|
import { AfterViewInit, Component, computed, effect, ElementRef, OnDestroy, signal, viewChild } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import * as THREE from 'three/webgpu';
|
import * as THREE from 'three/webgpu';
|
||||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||||
@@ -217,6 +217,12 @@ export class GalaxySystemSceneComponent implements AfterViewInit, OnDestroy {
|
|||||||
private readonly leaderRef = viewChild.required<ElementRef<SVGLineElement>>('leader');
|
private readonly leaderRef = viewChild.required<ElementRef<SVGLineElement>>('leader');
|
||||||
private readonly objectCardRef = viewChild<SystemObjectCardComponent, ElementRef<HTMLElement>>(SystemObjectCardComponent, { read: ElementRef });
|
private readonly objectCardRef = viewChild<SystemObjectCardComponent, ElementRef<HTMLElement>>(SystemObjectCardComponent, { read: ElementRef });
|
||||||
private readonly dockRef = viewChild<HudDockComponent, ElementRef<HTMLElement>>(HudDockComponent, { read: ElementRef });
|
private readonly dockRef = viewChild<HudDockComponent, ElementRef<HTMLElement>>(HudDockComponent, { read: ElementRef });
|
||||||
|
/**
|
||||||
|
* The card's own box, looked up when the card changes rather than in the render loop that
|
||||||
|
* draws the leader to it. The host element is a stable wrapper; the panel inside it is what
|
||||||
|
* moves, and it is only replaced when a different body is selected.
|
||||||
|
*/
|
||||||
|
private readonly objectCardElement = computed(() => this.objectCardRef()?.nativeElement.querySelector('[data-testid="object-card"]') ?? null);
|
||||||
|
|
||||||
private readonly raycaster = new THREE.Raycaster();
|
private readonly raycaster = new THREE.Raycaster();
|
||||||
private readonly galaxyGroup = new THREE.Group();
|
private readonly galaxyGroup = new THREE.Group();
|
||||||
@@ -684,7 +690,7 @@ export class GalaxySystemSceneComponent implements AfterViewInit, OnDestroy {
|
|||||||
const world = member.marker.getWorldPosition(new THREE.Vector3());
|
const world = member.marker.getWorldPosition(new THREE.Vector3());
|
||||||
this.labelOverlay?.setSelection(world);
|
this.labelOverlay?.setSelection(world);
|
||||||
|
|
||||||
const card = this.objectCardRef()?.nativeElement.querySelector('[data-testid="object-card"]');
|
const card = this.objectCardElement();
|
||||||
const canvas = this.canvasRef().nativeElement;
|
const canvas = this.canvasRef().nativeElement;
|
||||||
const projected = world.clone().project(camera);
|
const projected = world.clone().project(camera);
|
||||||
if (!card || projected.z > 1) {
|
if (!card || projected.z > 1) {
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ import * as THREE from 'three/webgpu';
|
|||||||
import { color, float, instancedBufferAttribute, smoothstep, uniform, uv, vec2 } from 'three/tsl';
|
import { color, float, instancedBufferAttribute, smoothstep, uniform, uv, vec2 } from 'three/tsl';
|
||||||
|
|
||||||
import { StarRecord } from '../../shared/models/star.model';
|
import { StarRecord } from '../../shared/models/star.model';
|
||||||
|
import { PIXELS_TO_ANGULAR_SIZE } from './angular-size';
|
||||||
|
|
||||||
/** Ring diameter in screen pixels at the reference viewport — angular, like the star points. */
|
/** Ring diameter in screen pixels at the reference viewport — angular, like the star points. */
|
||||||
const RING_SIZE_PX = 12;
|
const RING_SIZE_PX = 12;
|
||||||
const RING_PEAK_OPACITY = 0.35;
|
const RING_PEAK_OPACITY = 0.35;
|
||||||
/** Same reference as `StarFieldRenderer`, so a ring and its star agree on what a pixel is. */
|
|
||||||
const REFERENCE_VIEWPORT_HEIGHT_PX = 900;
|
|
||||||
const REFERENCE_FOV_DEGREES = 55;
|
|
||||||
const PIXELS_TO_ANGULAR_SIZE = (2 * Math.tan((REFERENCE_FOV_DEGREES * Math.PI) / 180 / 2)) / REFERENCE_VIEWPORT_HEIGHT_PX;
|
|
||||||
/** Ring radius and stroke half-width in quad-uv units (the quad runs 0..1, centre 0.5). */
|
/** Ring radius and stroke half-width in quad-uv units (the quad runs 0..1, centre 0.5). */
|
||||||
const RING_RADIUS_UV = 0.42;
|
const RING_RADIUS_UV = 0.42;
|
||||||
const RING_STROKE_UV = 0.06;
|
const RING_STROKE_UV = 0.06;
|
||||||
|
|||||||
@@ -2,22 +2,13 @@ import * as THREE from 'three/webgpu';
|
|||||||
import { instancedBufferAttribute, smoothstep, uv, vec2 } from 'three/tsl';
|
import { instancedBufferAttribute, smoothstep, uv, vec2 } from 'three/tsl';
|
||||||
|
|
||||||
import { spectralTypeToColorIndex } from '../../shared/astro/spectral';
|
import { spectralTypeToColorIndex } from '../../shared/astro/spectral';
|
||||||
|
import { PIXELS_TO_ANGULAR_SIZE, REFERENCE_VIEWPORT_HEIGHT_PX } from './angular-size';
|
||||||
import { StarRecord } from '../../shared/models/star.model';
|
import { StarRecord } from '../../shared/models/star.model';
|
||||||
|
|
||||||
/** Apparent star diameters, in pixels at {@link REFERENCE_VIEWPORT_HEIGHT_PX}. */
|
/** Apparent star diameters, in pixels at {@link REFERENCE_VIEWPORT_HEIGHT_PX}. */
|
||||||
const MIN_POINT_SIZE = 1.5;
|
const MIN_POINT_SIZE = 1.5;
|
||||||
const MAX_POINT_SIZE = 6;
|
const MAX_POINT_SIZE = 6;
|
||||||
|
|
||||||
/**
|
|
||||||
* Star size is expressed in pixels for readability, but the material works in angular size, so
|
|
||||||
* the two are related through the scene's vertical field of view and a reference viewport.
|
|
||||||
* Because the size is angular, a star keeps the same share of the screen at any window size —
|
|
||||||
* these pixel figures are exact only at this reference height.
|
|
||||||
*/
|
|
||||||
const REFERENCE_VIEWPORT_HEIGHT_PX = 900;
|
|
||||||
const REFERENCE_FOV_DEGREES = 55;
|
|
||||||
const PIXELS_TO_ANGULAR_SIZE =
|
|
||||||
(2 * Math.tan((REFERENCE_FOV_DEGREES * Math.PI) / 180 / 2)) / REFERENCE_VIEWPORT_HEIGHT_PX;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra click forgiveness added to a star's drawn radius, in NDC — roughly 4 px on the
|
* Extra click forgiveness added to a star's drawn radius, in NDC — roughly 4 px on the
|
||||||
|
|||||||
Reference in New Issue
Block a user