Refactor road mesh generation to integrate junction edge seams
This commit is contained in:
@@ -13,7 +13,10 @@ import {
|
|||||||
sampleTerrainHeightAtWorldPosition,
|
sampleTerrainHeightAtWorldPosition,
|
||||||
type Terrain
|
type Terrain
|
||||||
} from "../document/terrains";
|
} from "../document/terrains";
|
||||||
import type { SplineCorridorPathClipInterval } from "../spline-corridor/spline-corridor-clips";
|
import type {
|
||||||
|
SplineCorridorPathClipInterval,
|
||||||
|
SplineCorridorRoadEdgeSeam
|
||||||
|
} from "../spline-corridor/spline-corridor-clips";
|
||||||
|
|
||||||
export interface SplineRoadPathPointLike {
|
export interface SplineRoadPathPointLike {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -431,22 +434,18 @@ function isClipBoundaryDistance(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandClipIntervalsForRoadEdge(options: {
|
function findRoadEdgeSeam(options: {
|
||||||
clipIntervals: readonly SplineCorridorPathClipInterval[];
|
distance: number;
|
||||||
edgeWidth: number;
|
side: ScenePathRoadEdgeSide;
|
||||||
totalLength: number;
|
seams: readonly SplineCorridorRoadEdgeSeam[];
|
||||||
}): SplineCorridorPathClipInterval[] {
|
}): SplineCorridorRoadEdgeSeam | null {
|
||||||
if (options.clipIntervals.length === 0 || options.edgeWidth <= 0) {
|
return (
|
||||||
return [...options.clipIntervals];
|
options.seams.find(
|
||||||
}
|
(seam) =>
|
||||||
|
seam.side === options.side &&
|
||||||
const insetDistance = options.edgeWidth * 0.45;
|
Math.abs(seam.distance - options.distance) <= 1e-6
|
||||||
|
) ?? null
|
||||||
return options.clipIntervals.map((clipInterval) => ({
|
);
|
||||||
junctionId: clipInterval.junctionId,
|
|
||||||
startDistance: Math.max(0, clipInterval.startDistance - insetDistance),
|
|
||||||
endDistance: Math.min(options.totalLength, clipInterval.endDistance + insetDistance)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildSplineRoadMeshData(options: {
|
export function buildSplineRoadMeshData(options: {
|
||||||
@@ -550,6 +549,7 @@ export function buildSplineRoadEdgeMeshData(options: {
|
|||||||
side: ScenePathRoadEdgeSide;
|
side: ScenePathRoadEdgeSide;
|
||||||
terrains?: readonly Terrain[];
|
terrains?: readonly Terrain[];
|
||||||
clipIntervals?: readonly SplineCorridorPathClipInterval[];
|
clipIntervals?: readonly SplineCorridorPathClipInterval[];
|
||||||
|
junctionEdgeSeams?: readonly SplineCorridorRoadEdgeSeam[];
|
||||||
}): SplineRoadEdgeMeshData | null {
|
}): SplineRoadEdgeMeshData | null {
|
||||||
const { path, side } = options;
|
const { path, side } = options;
|
||||||
const edge = path.road.edges[side];
|
const edge = path.road.edges[side];
|
||||||
@@ -580,11 +580,7 @@ export function buildSplineRoadEdgeMeshData(options: {
|
|||||||
const uvs: number[] = [];
|
const uvs: number[] = [];
|
||||||
const indices: number[] = [];
|
const indices: number[] = [];
|
||||||
const profileLastIndex = Math.max(1, profile.length - 1);
|
const profileLastIndex = Math.max(1, profile.length - 1);
|
||||||
const edgeClipIntervals = expandClipIntervalsForRoadEdge({
|
const edgeClipIntervals = options.clipIntervals ?? [];
|
||||||
clipIntervals: options.clipIntervals ?? [],
|
|
||||||
edgeWidth: edge.width,
|
|
||||||
totalLength: stations[stations.length - 1]?.distance ?? 0
|
|
||||||
});
|
|
||||||
const stationRuns = buildVisibleRoadStationRuns(stations, edgeClipIntervals);
|
const stationRuns = buildVisibleRoadStationRuns(stations, edgeClipIntervals);
|
||||||
let stationCount = 0;
|
let stationCount = 0;
|
||||||
|
|
||||||
@@ -604,14 +600,40 @@ export function buildSplineRoadEdgeMeshData(options: {
|
|||||||
y: 0,
|
y: 0,
|
||||||
z: tangent.x
|
z: tangent.x
|
||||||
};
|
};
|
||||||
|
const sideSign = side === "left" ? 1 : -1;
|
||||||
|
const innerOffset = sideSign * path.road.width * 0.5;
|
||||||
|
const seam = findRoadEdgeSeam({
|
||||||
|
distance: station.distance,
|
||||||
|
side,
|
||||||
|
seams: options.junctionEdgeSeams ?? []
|
||||||
|
});
|
||||||
|
const seamInnerPoint =
|
||||||
|
seam === null
|
||||||
|
? null
|
||||||
|
: addVec3(station.center, {
|
||||||
|
x: leftDirection.x * innerOffset,
|
||||||
|
y: 0,
|
||||||
|
z: leftDirection.z * innerOffset
|
||||||
|
});
|
||||||
|
|
||||||
for (let profileIndex = 0; profileIndex < profile.length; profileIndex += 1) {
|
for (let profileIndex = 0; profileIndex < profile.length; profileIndex += 1) {
|
||||||
const profilePoint = profile[profileIndex]!;
|
const profilePoint = profile[profileIndex]!;
|
||||||
const edgePoint = addVec3(station.center, {
|
const profileOffsetRatio =
|
||||||
x: leftDirection.x * profilePoint.offset,
|
edge.width <= 1e-8
|
||||||
y: 0,
|
? 0
|
||||||
z: leftDirection.z * profilePoint.offset
|
: (profilePoint.offset - innerOffset) / (sideSign * edge.width);
|
||||||
});
|
const edgePoint =
|
||||||
|
seam === null || seamInnerPoint === null
|
||||||
|
? addVec3(station.center, {
|
||||||
|
x: leftDirection.x * profilePoint.offset,
|
||||||
|
y: 0,
|
||||||
|
z: leftDirection.z * profilePoint.offset
|
||||||
|
})
|
||||||
|
: {
|
||||||
|
x: seamInnerPoint.x + seam.outerOffset.x * profileOffsetRatio,
|
||||||
|
y: seamInnerPoint.y,
|
||||||
|
z: seamInnerPoint.z + seam.outerOffset.z * profileOffsetRatio
|
||||||
|
};
|
||||||
const vertex = resolveRoadVertexPosition({
|
const vertex = resolveRoadVertexPosition({
|
||||||
path,
|
path,
|
||||||
terrains,
|
terrains,
|
||||||
|
|||||||
Reference in New Issue
Block a user