auto-git:
[change] src/geometry/spline-corridor-junction-mesh.ts
This commit is contained in:
@@ -1,49 +1,18 @@
|
||||
import { BufferGeometry, Float32BufferAttribute } from "three";
|
||||
|
||||
import type { Vec3 } from "../core/vector";
|
||||
import {
|
||||
resolveScenePath,
|
||||
sampleResolvedScenePathPosition,
|
||||
type ScenePathCurveMode,
|
||||
type ScenePathPoint,
|
||||
type ScenePathRoadSettings
|
||||
} from "../document/paths";
|
||||
import type { SplineCorridorJunction } from "../document/spline-corridor-junctions";
|
||||
import {
|
||||
sampleTerrainHeightAtWorldPosition,
|
||||
type Terrain
|
||||
} from "../document/terrains";
|
||||
import {
|
||||
buildSplineCorridorJunctionFootprint,
|
||||
type SplineCorridorJunctionFootprintPathLike
|
||||
} from "./spline-corridor-junction-footprint";
|
||||
|
||||
export interface SplineCorridorJunctionMeshPathLike {
|
||||
id: string;
|
||||
loop: boolean;
|
||||
curveMode?: ScenePathCurveMode;
|
||||
sampledResolution?: number;
|
||||
glueToTerrain?: boolean;
|
||||
terrainOffset?: number;
|
||||
road: ScenePathRoadSettings;
|
||||
points: ReadonlyArray<{
|
||||
id?: string;
|
||||
pointId?: string;
|
||||
position: Vec3;
|
||||
}>;
|
||||
}
|
||||
|
||||
const JUNCTION_SEGMENTS = 32;
|
||||
|
||||
function normalizePathPoint(
|
||||
point: SplineCorridorJunctionMeshPathLike["points"][number],
|
||||
index: number
|
||||
): ScenePathPoint {
|
||||
return {
|
||||
id: point.id ?? point.pointId ?? `junction-path-point-${index}`,
|
||||
position: {
|
||||
x: point.position.x,
|
||||
y: point.position.y,
|
||||
z: point.position.z
|
||||
}
|
||||
};
|
||||
}
|
||||
export type SplineCorridorJunctionMeshPathLike =
|
||||
SplineCorridorJunctionFootprintPathLike;
|
||||
|
||||
function sampleHighestTerrainWorldY(
|
||||
terrains: readonly Terrain[],
|
||||
@@ -73,53 +42,6 @@ function sampleHighestTerrainWorldY(
|
||||
return highestWorldY;
|
||||
}
|
||||
|
||||
function resolveJunctionPath(
|
||||
path: SplineCorridorJunctionMeshPathLike,
|
||||
terrains: readonly Terrain[]
|
||||
) {
|
||||
return resolveScenePath(
|
||||
{
|
||||
loop: path.loop,
|
||||
curveMode: path.curveMode,
|
||||
sampledResolution: path.sampledResolution,
|
||||
glueToTerrain: path.glueToTerrain,
|
||||
terrainOffset: path.terrainOffset,
|
||||
points: path.points.map(normalizePathPoint)
|
||||
},
|
||||
{ terrains }
|
||||
);
|
||||
}
|
||||
|
||||
function resolveFallbackY(options: {
|
||||
junction: SplineCorridorJunction;
|
||||
paths: readonly SplineCorridorJunctionMeshPathLike[];
|
||||
terrains: readonly Terrain[];
|
||||
}): number {
|
||||
const sampledPositions = options.junction.connections
|
||||
.map((connection) => {
|
||||
const path =
|
||||
options.paths.find((candidate) => candidate.id === connection.pathId) ??
|
||||
null;
|
||||
|
||||
if (path === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const resolvedPath = resolveJunctionPath(path, options.terrains);
|
||||
return sampleResolvedScenePathPosition(resolvedPath, connection.progress);
|
||||
})
|
||||
.filter((position): position is Vec3 => position !== null);
|
||||
|
||||
if (sampledPositions.length === 0) {
|
||||
return options.junction.center.y;
|
||||
}
|
||||
|
||||
return (
|
||||
sampledPositions.reduce((sum, position) => sum + position.y, 0) /
|
||||
sampledPositions.length
|
||||
);
|
||||
}
|
||||
|
||||
function shouldConformToTerrain(options: {
|
||||
junction: SplineCorridorJunction;
|
||||
paths: readonly SplineCorridorJunctionMeshPathLike[];
|
||||
@@ -140,43 +62,73 @@ export function buildSplineCorridorJunctionMeshGeometry(options: {
|
||||
}): BufferGeometry | null {
|
||||
const { junction, paths } = options;
|
||||
const terrains = options.terrains ?? [];
|
||||
const footprint = buildSplineCorridorJunctionFootprint({
|
||||
junction,
|
||||
paths,
|
||||
terrains
|
||||
});
|
||||
|
||||
if (!junction.enabled || !junction.visible || junction.radius <= 0) {
|
||||
if (footprint === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const conformToTerrain = shouldConformToTerrain({ junction, paths });
|
||||
const fallbackY = resolveFallbackY({ junction, paths, terrains });
|
||||
const positions: number[] = [];
|
||||
const uvs: number[] = [];
|
||||
const indices: number[] = [];
|
||||
|
||||
function resolveY(position: Vec3): number {
|
||||
function resolveY(position: Vec3, fallbackY: number, heightOffset: number): number {
|
||||
const terrainWorldY = conformToTerrain
|
||||
? sampleHighestTerrainWorldY(terrains, position)
|
||||
: null;
|
||||
|
||||
return terrainWorldY ?? fallbackY;
|
||||
return terrainWorldY === null ? fallbackY : terrainWorldY + heightOffset;
|
||||
}
|
||||
|
||||
positions.push(junction.center.x, resolveY(junction.center), junction.center.z);
|
||||
uvs.push(0.5, 0.5);
|
||||
|
||||
for (let index = 0; index < JUNCTION_SEGMENTS; index += 1) {
|
||||
const angle = (index / JUNCTION_SEGMENTS) * Math.PI * 2;
|
||||
const position = {
|
||||
x: junction.center.x + Math.cos(angle) * junction.radius,
|
||||
y: junction.center.y,
|
||||
z: junction.center.z + Math.sin(angle) * junction.radius
|
||||
};
|
||||
|
||||
positions.push(position.x, resolveY(position), position.z);
|
||||
uvs.push(0.5 + Math.cos(angle) * 0.5, 0.5 + Math.sin(angle) * 0.5);
|
||||
function pushUv(x: number, z: number) {
|
||||
const deltaX = x - footprint.center.x;
|
||||
const deltaZ = z - footprint.center.z;
|
||||
uvs.push(
|
||||
deltaX * footprint.rightAxis.x + deltaZ * footprint.rightAxis.z,
|
||||
deltaX * footprint.forwardAxis.x + deltaZ * footprint.forwardAxis.z
|
||||
);
|
||||
}
|
||||
|
||||
for (let index = 0; index < JUNCTION_SEGMENTS; index += 1) {
|
||||
positions.push(
|
||||
footprint.center.x,
|
||||
resolveY(
|
||||
{
|
||||
x: footprint.center.x,
|
||||
y: junction.center.y,
|
||||
z: footprint.center.z
|
||||
},
|
||||
footprint.center.fallbackY,
|
||||
footprint.center.heightOffset
|
||||
),
|
||||
footprint.center.z
|
||||
);
|
||||
pushUv(footprint.center.x, footprint.center.z);
|
||||
|
||||
for (const point of footprint.points) {
|
||||
positions.push(
|
||||
point.x,
|
||||
resolveY(
|
||||
{
|
||||
x: point.x,
|
||||
y: point.fallbackY,
|
||||
z: point.z
|
||||
},
|
||||
point.fallbackY,
|
||||
point.heightOffset
|
||||
),
|
||||
point.z
|
||||
);
|
||||
pushUv(point.x, point.z);
|
||||
}
|
||||
|
||||
for (let index = 0; index < footprint.points.length; index += 1) {
|
||||
const current = index + 1;
|
||||
const next = index === JUNCTION_SEGMENTS - 1 ? 1 : current + 1;
|
||||
const next = index === footprint.points.length - 1 ? 1 : current + 1;
|
||||
|
||||
indices.push(0, current, next);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user