Add functions for creating signed distance to patch region and box patch from segment loop in water-material.js
This commit is contained in:
@@ -422,6 +422,86 @@ function createSegmentPatchFromCluster(cluster) {
|
||||
};
|
||||
}
|
||||
|
||||
function createSignedDistanceToPatchRegion(point, center, axis, halfExtents) {
|
||||
const patchPerpendicular = new Vector2(-axis.y, axis.x);
|
||||
const patchLocalUv = new Vector2(point.clone().sub(center).dot(axis), point.clone().sub(center).dot(patchPerpendicular));
|
||||
const regionDelta = new Vector2(Math.abs(patchLocalUv.x) - halfExtents.x, Math.abs(patchLocalUv.y) - halfExtents.y);
|
||||
const outsideDistance = new Vector2(Math.max(regionDelta.x, 0), Math.max(regionDelta.y, 0)).length();
|
||||
const insideDistance = Math.min(Math.max(regionDelta.x, regionDelta.y), 0);
|
||||
return outsideDistance + insideDistance;
|
||||
}
|
||||
|
||||
function createBoxPatchFromSegmentLoop(segments, minimumThickness) {
|
||||
if (segments.length < 3) {
|
||||
return null;
|
||||
}
|
||||
const canonicalAxes = [];
|
||||
for (const segment of segments) {
|
||||
if (segment.shape !== "segment") {
|
||||
return null;
|
||||
}
|
||||
const axis = new Vector2(segment.axisX, segment.axisZ);
|
||||
if (axis.lengthSq() <= WATER_CONTACT_EPSILON) {
|
||||
continue;
|
||||
}
|
||||
axis.normalize();
|
||||
if (axis.x < 0 || (Math.abs(axis.x) <= WATER_CONTACT_EPSILON && axis.y < 0)) {
|
||||
axis.multiplyScalar(-1);
|
||||
}
|
||||
const existingAxis = canonicalAxes.find((candidate) => Math.abs(candidate.dot(axis)) >= 0.94);
|
||||
if (existingAxis === undefined) {
|
||||
canonicalAxes.push(axis);
|
||||
}
|
||||
}
|
||||
if (canonicalAxes.length < 2) {
|
||||
return null;
|
||||
}
|
||||
let foundOrthogonalAxes = false;
|
||||
for (let leftIndex = 0; leftIndex < canonicalAxes.length; leftIndex += 1) {
|
||||
for (let rightIndex = leftIndex + 1; rightIndex < canonicalAxes.length; rightIndex += 1) {
|
||||
const leftAxis = canonicalAxes[leftIndex];
|
||||
const rightAxis = canonicalAxes[rightIndex];
|
||||
if (leftAxis === undefined || rightAxis === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (Math.abs(leftAxis.dot(rightAxis)) <= 0.35) {
|
||||
foundOrthogonalAxes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundOrthogonalAxes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundOrthogonalAxes) {
|
||||
return null;
|
||||
}
|
||||
const projectedPoints = [];
|
||||
for (const segment of segments) {
|
||||
const [startPoint, endPoint] = createSegmentEndpoints(segment);
|
||||
projectedPoints.push(startPoint, endPoint);
|
||||
}
|
||||
const candidatePatch = createPatchFromProjectedPoints(projectedPoints, null, minimumThickness);
|
||||
if (candidatePatch === null) {
|
||||
return null;
|
||||
}
|
||||
const candidateAxis = new Vector2(candidatePatch.axisX, candidatePatch.axisZ);
|
||||
if (candidateAxis.lengthSq() <= WATER_CONTACT_EPSILON) {
|
||||
return null;
|
||||
}
|
||||
candidateAxis.normalize();
|
||||
const candidateCenter = new Vector2(candidatePatch.x, candidatePatch.z);
|
||||
const candidateHalfExtents = new Vector2(candidatePatch.halfWidth, candidatePatch.halfDepth);
|
||||
const acceptanceDistance = Math.max(minimumThickness * 2.2, 0.14);
|
||||
for (const point of projectedPoints) {
|
||||
const signedDistance = createSignedDistanceToPatchRegion(point, candidateCenter, candidateAxis, candidateHalfExtents);
|
||||
if (Math.abs(signedDistance) > acceptanceDistance) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return candidatePatch;
|
||||
}
|
||||
|
||||
function getTriangleMeshMergeSettings(mergeProfile, minimumThickness) {
|
||||
if (mergeProfile === "aggressive") {
|
||||
return {
|
||||
@@ -541,7 +621,13 @@ function appendTriangleMeshContactPatches(patches, source, volume, inverseRotati
|
||||
});
|
||||
}
|
||||
}
|
||||
patches.push(...mergeTriangleMeshContactPatches(rawPatches, bandMinimumThickness, source.mergeProfile));
|
||||
const mergedPatches = mergeTriangleMeshContactPatches(rawPatches, bandMinimumThickness, source.mergeProfile);
|
||||
const loopPatch = createBoxPatchFromSegmentLoop(mergedPatches, bandMinimumThickness);
|
||||
if (loopPatch !== null) {
|
||||
patches.push(loopPatch);
|
||||
return;
|
||||
}
|
||||
patches.push(...mergedPatches);
|
||||
}
|
||||
|
||||
export function collectWaterContactPatches(volume, contactBounds, patchLimit = MAX_WATER_CONTACT_PATCHES) {
|
||||
|
||||
Reference in New Issue
Block a user