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 { BufferGeometry, Float32BufferAttribute } from "three";
|
||||||
|
|
||||||
import type { Vec3 } from "../core/vector";
|
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 type { SplineCorridorJunction } from "../document/spline-corridor-junctions";
|
||||||
import {
|
import {
|
||||||
sampleTerrainHeightAtWorldPosition,
|
sampleTerrainHeightAtWorldPosition,
|
||||||
type Terrain
|
type Terrain
|
||||||
} from "../document/terrains";
|
} from "../document/terrains";
|
||||||
|
import {
|
||||||
|
buildSplineCorridorJunctionFootprint,
|
||||||
|
type SplineCorridorJunctionFootprintPathLike
|
||||||
|
} from "./spline-corridor-junction-footprint";
|
||||||
|
|
||||||
export interface SplineCorridorJunctionMeshPathLike {
|
export type SplineCorridorJunctionMeshPathLike =
|
||||||
id: string;
|
SplineCorridorJunctionFootprintPathLike;
|
||||||
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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function sampleHighestTerrainWorldY(
|
function sampleHighestTerrainWorldY(
|
||||||
terrains: readonly Terrain[],
|
terrains: readonly Terrain[],
|
||||||
@@ -73,53 +42,6 @@ function sampleHighestTerrainWorldY(
|
|||||||
return highestWorldY;
|
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: {
|
function shouldConformToTerrain(options: {
|
||||||
junction: SplineCorridorJunction;
|
junction: SplineCorridorJunction;
|
||||||
paths: readonly SplineCorridorJunctionMeshPathLike[];
|
paths: readonly SplineCorridorJunctionMeshPathLike[];
|
||||||
@@ -140,43 +62,73 @@ export function buildSplineCorridorJunctionMeshGeometry(options: {
|
|||||||
}): BufferGeometry | null {
|
}): BufferGeometry | null {
|
||||||
const { junction, paths } = options;
|
const { junction, paths } = options;
|
||||||
const terrains = options.terrains ?? [];
|
const terrains = options.terrains ?? [];
|
||||||
|
const footprint = buildSplineCorridorJunctionFootprint({
|
||||||
|
junction,
|
||||||
|
paths,
|
||||||
|
terrains
|
||||||
|
});
|
||||||
|
|
||||||
if (!junction.enabled || !junction.visible || junction.radius <= 0) {
|
if (footprint === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const conformToTerrain = shouldConformToTerrain({ junction, paths });
|
const conformToTerrain = shouldConformToTerrain({ junction, paths });
|
||||||
const fallbackY = resolveFallbackY({ junction, paths, terrains });
|
|
||||||
const positions: number[] = [];
|
const positions: number[] = [];
|
||||||
const uvs: number[] = [];
|
const uvs: number[] = [];
|
||||||
const indices: number[] = [];
|
const indices: number[] = [];
|
||||||
|
|
||||||
function resolveY(position: Vec3): number {
|
function resolveY(position: Vec3, fallbackY: number, heightOffset: number): number {
|
||||||
const terrainWorldY = conformToTerrain
|
const terrainWorldY = conformToTerrain
|
||||||
? sampleHighestTerrainWorldY(terrains, position)
|
? sampleHighestTerrainWorldY(terrains, position)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return terrainWorldY ?? fallbackY;
|
return terrainWorldY === null ? fallbackY : terrainWorldY + heightOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
positions.push(junction.center.x, resolveY(junction.center), junction.center.z);
|
function pushUv(x: number, z: number) {
|
||||||
uvs.push(0.5, 0.5);
|
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(
|
||||||
const angle = (index / JUNCTION_SEGMENTS) * Math.PI * 2;
|
footprint.center.x,
|
||||||
const position = {
|
resolveY(
|
||||||
x: junction.center.x + Math.cos(angle) * junction.radius,
|
{
|
||||||
|
x: footprint.center.x,
|
||||||
y: junction.center.y,
|
y: junction.center.y,
|
||||||
z: junction.center.z + Math.sin(angle) * junction.radius
|
z: footprint.center.z
|
||||||
};
|
},
|
||||||
|
footprint.center.fallbackY,
|
||||||
|
footprint.center.heightOffset
|
||||||
|
),
|
||||||
|
footprint.center.z
|
||||||
|
);
|
||||||
|
pushUv(footprint.center.x, footprint.center.z);
|
||||||
|
|
||||||
positions.push(position.x, resolveY(position), position.z);
|
for (const point of footprint.points) {
|
||||||
uvs.push(0.5 + Math.cos(angle) * 0.5, 0.5 + Math.sin(angle) * 0.5);
|
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 < JUNCTION_SEGMENTS; index += 1) {
|
for (let index = 0; index < footprint.points.length; index += 1) {
|
||||||
const current = 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);
|
indices.push(0, current, next);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user