2023-03-14 08:02:43 +03:00
|
|
|
/*
|
|
|
|
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
2023-03-15 17:00:29 +03:00
|
|
|
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
|
|
|
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
2023-03-14 08:02:43 +03:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
using System;
|
2023-03-28 18:03:33 +03:00
|
|
|
using DotRecast.Core;
|
2023-05-10 16:44:51 +03:00
|
|
|
using static DotRecast.Core.RcMath;
|
2023-06-08 14:53:03 +03:00
|
|
|
using static DotRecast.Recast.RcConstants;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:09:10 +03:00
|
|
|
namespace DotRecast.Recast
|
|
|
|
{
|
2023-06-08 14:53:03 +03:00
|
|
|
public static class RecastRasterization
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
|
|
|
/**
|
2023-03-14 08:02:43 +03:00
|
|
|
* Check whether two bounding boxes overlap
|
|
|
|
*
|
|
|
|
* @param amin
|
|
|
|
* Min axis extents of bounding box A
|
|
|
|
* @param amax
|
|
|
|
* Max axis extents of bounding box A
|
|
|
|
* @param bmin
|
|
|
|
* Min axis extents of bounding box B
|
|
|
|
* @param bmax
|
|
|
|
* Max axis extents of bounding box B
|
|
|
|
* @returns true if the two bounding boxes overlap. False otherwise
|
|
|
|
*/
|
2023-05-05 02:44:48 +03:00
|
|
|
private static bool OverlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
|
|
|
bool overlap = true;
|
|
|
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
|
|
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
|
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
|
|
return overlap;
|
|
|
|
}
|
2023-06-03 16:13:27 +03:00
|
|
|
|
2023-06-03 15:47:26 +03:00
|
|
|
private static bool OverlapBounds(RcVec3f amin, RcVec3f amax, RcVec3f bmin, RcVec3f bmax)
|
2023-03-28 18:03:33 +03:00
|
|
|
{
|
|
|
|
bool overlap = true;
|
2023-04-29 07:00:19 +03:00
|
|
|
overlap = (amin.x > bmax.x || amax.x < bmin.x) ? false : overlap;
|
|
|
|
overlap = (amin.y > bmax.y || amax.y < bmin.y) ? false : overlap;
|
|
|
|
overlap = (amin.z > bmax.z || amax.z < bmin.z) ? false : overlap;
|
2023-03-28 18:03:33 +03:00
|
|
|
return overlap;
|
|
|
|
}
|
|
|
|
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/**
|
2023-03-14 08:02:43 +03:00
|
|
|
* Adds a span to the heightfield. If the new span overlaps existing spans, it will merge the new span with the
|
|
|
|
* existing ones. The span addition can be set to favor flags. If the span is merged to another span and the new
|
|
|
|
* spanMax is within flagMergeThreshold units from the existing span, the span flags are merged.
|
|
|
|
*
|
|
|
|
* @param heightfield
|
|
|
|
* An initialized heightfield.
|
|
|
|
* @param x
|
|
|
|
* The width index where the span is to be added. [Limits: 0 <= value < Heightfield::width]
|
|
|
|
* @param y
|
|
|
|
* The height index where the span is to be added. [Limits: 0 <= value < Heightfield::height]
|
|
|
|
* @param spanMin
|
|
|
|
* The minimum height of the span. [Limit: < spanMax] [Units: vx]
|
|
|
|
* @param spanMax
|
|
|
|
* The minimum height of the span. [Limit: <= RecastConstants.SPAN_MAX_HEIGHT] [Units: vx]
|
|
|
|
* @param areaId
|
|
|
|
* The area id of the span. [Limit: <= WALKABLE_AREA)
|
|
|
|
* @param flagMergeThreshold
|
|
|
|
* The merge theshold. [Limit: >= 0] [Units: vx]
|
|
|
|
* @see Heightfield, Span.
|
|
|
|
*/
|
2023-06-08 14:53:03 +03:00
|
|
|
public static void AddSpan(RcHeightfield heightfield, int x, int y, int spanMin, int spanMax, int areaId,
|
2023-03-16 19:48:49 +03:00
|
|
|
int flagMergeThreshold)
|
|
|
|
{
|
|
|
|
int idx = x + y * heightfield.width;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-06-08 14:53:03 +03:00
|
|
|
RcSpan s = new RcSpan();
|
2023-03-16 19:48:49 +03:00
|
|
|
s.smin = spanMin;
|
|
|
|
s.smax = spanMax;
|
|
|
|
s.area = areaId;
|
|
|
|
s.next = null;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
// Empty cell, add the first span.
|
|
|
|
if (heightfield.spans[idx] == null)
|
|
|
|
{
|
|
|
|
heightfield.spans[idx] = s;
|
|
|
|
return;
|
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-06-08 14:53:03 +03:00
|
|
|
RcSpan prev = null;
|
|
|
|
RcSpan cur = heightfield.spans[idx];
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
// Insert and merge spans.
|
|
|
|
while (cur != null)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
if (cur.smin > s.smax)
|
|
|
|
{
|
|
|
|
// Current span is further than the new span, break.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (cur.smax < s.smin)
|
|
|
|
{
|
|
|
|
// Current span is before the new span advance.
|
|
|
|
prev = cur;
|
|
|
|
cur = cur.next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Merge spans.
|
|
|
|
if (cur.smin < s.smin)
|
|
|
|
s.smin = cur.smin;
|
|
|
|
if (cur.smax > s.smax)
|
|
|
|
s.smax = cur.smax;
|
|
|
|
|
|
|
|
// Merge flags.
|
|
|
|
if (Math.Abs(s.smax - cur.smax) <= flagMergeThreshold)
|
|
|
|
s.area = Math.Max(s.area, cur.area);
|
|
|
|
|
|
|
|
// Remove current span.
|
2023-06-08 14:53:03 +03:00
|
|
|
RcSpan next = cur.next;
|
2023-03-16 19:48:49 +03:00
|
|
|
if (prev != null)
|
|
|
|
prev.next = next;
|
|
|
|
else
|
|
|
|
heightfield.spans[idx] = next;
|
|
|
|
cur = next;
|
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
// Insert new span.
|
|
|
|
if (prev != null)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
s.next = prev.next;
|
|
|
|
prev.next = s;
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
s.next = heightfield.spans[idx];
|
|
|
|
heightfield.spans[idx] = s;
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-03 16:13:27 +03:00
|
|
|
/// Divides a convex polygon of max 12 vertices into two convex polygons
|
|
|
|
/// across a separating axis.
|
|
|
|
///
|
|
|
|
/// @param[in] inVerts The input polygon vertices
|
|
|
|
/// @param[in] inVertsCount The number of input polygon vertices
|
|
|
|
/// @param[out] outVerts1 Resulting polygon 1's vertices
|
|
|
|
/// @param[out] outVerts1Count The number of resulting polygon 1 vertices
|
|
|
|
/// @param[out] outVerts2 Resulting polygon 2's vertices
|
|
|
|
/// @param[out] outVerts2Count The number of resulting polygon 2 vertices
|
|
|
|
/// @param[in] axisOffset THe offset along the specified axis
|
|
|
|
/// @param[in] axis The separating axis
|
|
|
|
private static void DividePoly(float[] inVerts, int inVertsOffset, int inVertsCount,
|
|
|
|
int outVerts1, out int outVerts1Count,
|
|
|
|
int outVerts2, out int outVerts2Count,
|
|
|
|
float axisOffset, int axis)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
float[] d = new float[12];
|
|
|
|
|
2023-06-03 16:13:27 +03:00
|
|
|
// How far positive or negative away from the separating axis is each vertex.
|
|
|
|
for (int inVert = 0; inVert < inVertsCount; ++inVert)
|
|
|
|
{
|
|
|
|
d[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis];
|
|
|
|
}
|
|
|
|
|
|
|
|
int poly1Vert = 0;
|
|
|
|
int poly2Vert = 0;
|
|
|
|
for (int inVertA = 0, inVertB = inVertsCount - 1; inVertA < inVertsCount; inVertB = inVertA, ++inVertA)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-06-03 16:13:27 +03:00
|
|
|
bool ina = d[inVertB] >= 0;
|
|
|
|
bool inb = d[inVertA] >= 0;
|
2023-03-16 19:48:49 +03:00
|
|
|
if (ina != inb)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-06-03 16:13:27 +03:00
|
|
|
float s = d[inVertB] / (d[inVertB] - d[inVertA]);
|
|
|
|
inVerts[outVerts1 + poly1Vert * 3 + 0] = inVerts[inVertsOffset + inVertB * 3 + 0] +
|
|
|
|
(inVerts[inVertsOffset + inVertA * 3 + 0] - inVerts[inVertsOffset + inVertB * 3 + 0]) * s;
|
|
|
|
inVerts[outVerts1 + poly1Vert * 3 + 1] = inVerts[inVertsOffset + inVertB * 3 + 1] +
|
|
|
|
(inVerts[inVertsOffset + inVertA * 3 + 1] - inVerts[inVertsOffset + inVertB * 3 + 1]) * s;
|
|
|
|
inVerts[outVerts1 + poly1Vert * 3 + 2] = inVerts[inVertsOffset + inVertB * 3 + 2] +
|
|
|
|
(inVerts[inVertsOffset + inVertA * 3 + 2] - inVerts[inVertsOffset + inVertB * 3 + 2]) * s;
|
|
|
|
RcVec3f.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, outVerts1 + poly1Vert * 3);
|
|
|
|
poly1Vert++;
|
|
|
|
poly2Vert++;
|
2023-03-16 19:48:49 +03:00
|
|
|
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
|
|
|
|
// since these were already added above
|
2023-06-03 16:13:27 +03:00
|
|
|
if (d[inVertA] > 0)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-03 16:13:27 +03:00
|
|
|
RcVec3f.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
|
|
|
poly1Vert++;
|
2023-03-16 19:48:49 +03:00
|
|
|
}
|
2023-06-03 16:13:27 +03:00
|
|
|
else if (d[inVertA] < 0)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-03 16:13:27 +03:00
|
|
|
RcVec3f.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
|
|
|
poly2Vert++;
|
2023-03-16 19:48:49 +03:00
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
2023-03-16 19:48:49 +03:00
|
|
|
else // same side
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
|
2023-06-03 16:13:27 +03:00
|
|
|
if (d[inVertA] >= 0)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-03 16:13:27 +03:00
|
|
|
RcVec3f.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
|
|
|
poly1Vert++;
|
|
|
|
if (d[inVertA] != 0)
|
2023-03-16 19:48:49 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-06-03 16:13:27 +03:00
|
|
|
RcVec3f.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
|
|
|
poly2Vert++;
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-03 16:13:27 +03:00
|
|
|
outVerts1Count = poly1Vert;
|
|
|
|
outVerts2Count = poly2Vert;
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/**
|
2023-03-14 08:02:43 +03:00
|
|
|
* Rasterize a single triangle to the heightfield. This code is extremely hot, so much care should be given to
|
|
|
|
* maintaining maximum perf here.
|
|
|
|
*
|
|
|
|
* @param verts
|
|
|
|
* An array with vertex coordinates [(x, y, z) * N]
|
|
|
|
* @param v0
|
|
|
|
* Index of triangle vertex 0, will be multiplied by 3 to get vertex coordinates
|
|
|
|
* @param v1
|
|
|
|
* Triangle vertex 1 index
|
|
|
|
* @param v2
|
|
|
|
* Triangle vertex 2 index
|
|
|
|
* @param area
|
|
|
|
* The area ID to assign to the rasterized spans
|
|
|
|
* @param hf
|
|
|
|
* Heightfield to rasterize into
|
|
|
|
* @param hfBBMin
|
|
|
|
* The min extents of the heightfield bounding box
|
|
|
|
* @param hfBBMax
|
|
|
|
* The max extents of the heightfield bounding box
|
|
|
|
* @param cellSize
|
|
|
|
* The x and z axis size of a voxel in the heightfield
|
|
|
|
* @param inverseCellSize
|
|
|
|
* 1 / cellSize
|
|
|
|
* @param inverseCellHeight
|
|
|
|
* 1 / cellHeight
|
|
|
|
* @param flagMergeThreshold
|
|
|
|
* The threshold in which area flags will be merged
|
|
|
|
*/
|
2023-06-08 14:53:03 +03:00
|
|
|
private static void RasterizeTri(float[] verts, int v0, int v1, int v2, int area, RcHeightfield hf, RcVec3f hfBBMin,
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f hfBBMax, float cellSize, float inverseCellSize, float inverseCellHeight, int flagMergeThreshold)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f tmin = new RcVec3f();
|
|
|
|
RcVec3f tmax = new RcVec3f();
|
2023-04-29 07:00:19 +03:00
|
|
|
float by = hfBBMax.y - hfBBMin.y;
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
// Calculate the bounding box of the triangle.
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f.Copy(ref tmin, verts, v0 * 3);
|
|
|
|
RcVec3f.Copy(ref tmax, verts, v0 * 3);
|
2023-05-27 05:37:32 +03:00
|
|
|
tmin.Min(verts, v1 * 3);
|
|
|
|
tmin.Min(verts, v2 * 3);
|
|
|
|
tmax.Max(verts, v1 * 3);
|
|
|
|
tmax.Max(verts, v2 * 3);
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
|
2023-05-05 02:44:48 +03:00
|
|
|
if (!OverlapBounds(hfBBMin, hfBBMax, tmin, tmax))
|
2023-03-16 19:48:49 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Calculate the footprint of the triangle on the grid's y-axis
|
2023-04-29 07:00:19 +03:00
|
|
|
int z0 = (int)((tmin.z - hfBBMin.z) * inverseCellSize);
|
|
|
|
int z1 = (int)((tmax.z - hfBBMin.z) * inverseCellSize);
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
int w = hf.width;
|
|
|
|
int h = hf.height;
|
|
|
|
// use -1 rather than 0 to cut the polygon properly at the start of the tile
|
2023-05-05 02:44:48 +03:00
|
|
|
z0 = Clamp(z0, -1, h - 1);
|
|
|
|
z1 = Clamp(z1, 0, h - 1);
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
// Clip the triangle into all grid cells it touches.
|
|
|
|
float[] buf = new float[7 * 3 * 4];
|
|
|
|
int @in = 0;
|
|
|
|
int inRow = 7 * 3;
|
|
|
|
int p1 = inRow + 7 * 3;
|
|
|
|
int p2 = p1 + 7 * 3;
|
|
|
|
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f.Copy(buf, 0, verts, v0 * 3);
|
|
|
|
RcVec3f.Copy(buf, 3, verts, v1 * 3);
|
|
|
|
RcVec3f.Copy(buf, 6, verts, v2 * 3);
|
2023-03-16 19:48:49 +03:00
|
|
|
int nvRow, nvIn = 3;
|
|
|
|
|
|
|
|
for (int z = z0; z <= z1; ++z)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
// Clip polygon to row. Store the remaining polygon as well
|
2023-04-29 07:00:19 +03:00
|
|
|
float cellZ = hfBBMin.z + z * cellSize;
|
2023-06-03 16:13:27 +03:00
|
|
|
DividePoly(buf, @in, nvIn, inRow, out nvRow, p1, out nvIn, cellZ + cellSize, 2);
|
|
|
|
(@in, p1) = (p1, @in);
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
if (nvRow < 3)
|
2023-03-14 08:02:43 +03:00
|
|
|
continue;
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
if (z < 0)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
// find the horizontal bounds in the row
|
|
|
|
float minX = buf[inRow], maxX = buf[inRow];
|
|
|
|
for (int i = 1; i < nvRow; ++i)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-03-16 19:48:49 +03:00
|
|
|
float v = buf[inRow + i * 3];
|
|
|
|
minX = Math.Min(minX, v);
|
|
|
|
maxX = Math.Max(maxX, v);
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-04-29 07:00:19 +03:00
|
|
|
int x0 = (int)((minX - hfBBMin.x) * inverseCellSize);
|
|
|
|
int x1 = (int)((maxX - hfBBMin.x) * inverseCellSize);
|
2023-03-16 19:48:49 +03:00
|
|
|
if (x1 < 0 || x0 >= w)
|
|
|
|
{
|
2023-03-14 08:02:43 +03:00
|
|
|
continue;
|
2023-03-16 19:48:49 +03:00
|
|
|
}
|
|
|
|
|
2023-05-05 02:44:48 +03:00
|
|
|
x0 = Clamp(x0, -1, w - 1);
|
|
|
|
x1 = Clamp(x1, 0, w - 1);
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
int nv, nv2 = nvRow;
|
|
|
|
for (int x = x0; x <= x1; ++x)
|
|
|
|
{
|
|
|
|
// Clip polygon to column. store the remaining polygon as well
|
2023-04-29 07:00:19 +03:00
|
|
|
float cx = hfBBMin.x + x * cellSize;
|
2023-06-03 16:13:27 +03:00
|
|
|
DividePoly(buf, inRow, nv2, p1, out nv, p2, out nv2, cx + cellSize, 0);
|
|
|
|
(inRow, p2) = (p2, inRow);
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
if (nv < 3)
|
|
|
|
continue;
|
2023-06-03 16:13:27 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
if (x < 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate min and max of the span.
|
|
|
|
float spanMin = buf[p1 + 1];
|
|
|
|
float spanMax = buf[p1 + 1];
|
|
|
|
for (int i = 1; i < nv; ++i)
|
|
|
|
{
|
|
|
|
spanMin = Math.Min(spanMin, buf[p1 + i * 3 + 1]);
|
|
|
|
spanMax = Math.Max(spanMax, buf[p1 + i * 3 + 1]);
|
|
|
|
}
|
|
|
|
|
2023-04-29 07:00:19 +03:00
|
|
|
spanMin -= hfBBMin.y;
|
|
|
|
spanMax -= hfBBMin.y;
|
2023-03-16 19:48:49 +03:00
|
|
|
// Skip the span if it is outside the heightfield bbox
|
|
|
|
if (spanMax < 0.0f)
|
|
|
|
continue;
|
|
|
|
if (spanMin > by)
|
|
|
|
continue;
|
|
|
|
// Clamp the span to the heightfield bbox.
|
|
|
|
if (spanMin < 0.0f)
|
|
|
|
spanMin = 0;
|
|
|
|
if (spanMax > by)
|
|
|
|
spanMax = by;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
// Snap the span to the heightfield height grid.
|
2023-05-05 02:44:48 +03:00
|
|
|
int spanMinCellIndex = Clamp((int)Math.Floor(spanMin * inverseCellHeight), 0, SPAN_MAX_HEIGHT);
|
|
|
|
int spanMaxCellIndex = Clamp((int)Math.Ceiling(spanMax * inverseCellHeight), spanMinCellIndex + 1, SPAN_MAX_HEIGHT);
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-05-05 02:44:48 +03:00
|
|
|
AddSpan(hf, x, z, spanMinCellIndex, spanMaxCellIndex, area, flagMergeThreshold);
|
2023-03-16 19:48:49 +03:00
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/**
|
2023-03-14 08:02:43 +03:00
|
|
|
* Rasterizes a single triangle into the specified heightfield. Calling this for each triangle in a mesh is less
|
|
|
|
* efficient than calling rasterizeTriangles. No spans will be added if the triangle does not overlap the
|
|
|
|
* heightfield grid.
|
|
|
|
*
|
|
|
|
* @param heightfield
|
|
|
|
* An initialized heightfield.
|
|
|
|
* @param verts
|
|
|
|
* An array with vertex coordinates [(x, y, z) * N]
|
|
|
|
* @param v0
|
|
|
|
* Index of triangle vertex 0, will be multiplied by 3 to get vertex coordinates
|
|
|
|
* @param v1
|
|
|
|
* Triangle vertex 1 index
|
|
|
|
* @param v2
|
|
|
|
* Triangle vertex 2 index
|
|
|
|
* @param areaId
|
|
|
|
* The area id of the triangle. [Limit: <= WALKABLE_AREA)
|
|
|
|
* @param flagMergeThreshold
|
|
|
|
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
|
|
|
|
* @see Heightfield
|
|
|
|
*/
|
2023-06-08 14:53:03 +03:00
|
|
|
public static void RasterizeTriangle(RcHeightfield heightfield, float[] verts, int v0, int v1, int v2, int area,
|
2023-07-01 06:50:25 +03:00
|
|
|
int flagMergeThreshold, RcTelemetry ctx)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-07-08 06:20:20 +03:00
|
|
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
float inverseCellSize = 1.0f / heightfield.cs;
|
|
|
|
float inverseCellHeight = 1.0f / heightfield.ch;
|
2023-05-05 02:44:48 +03:00
|
|
|
RasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize,
|
2023-03-16 19:48:49 +03:00
|
|
|
inverseCellHeight, flagMergeThreshold);
|
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/**
|
2023-03-14 08:02:43 +03:00
|
|
|
* Rasterizes an indexed triangle mesh into the specified heightfield. Spans will only be added for triangles that
|
|
|
|
* overlap the heightfield grid.
|
|
|
|
*
|
|
|
|
* @param heightfield
|
|
|
|
* An initialized heightfield.
|
|
|
|
* @param verts
|
|
|
|
* The vertices. [(x, y, z) * N]
|
|
|
|
* @param tris
|
|
|
|
* The triangle indices. [(vertA, vertB, vertC) * nt]
|
|
|
|
* @param areaIds
|
|
|
|
* The area id's of the triangles. [Limit: <= WALKABLE_AREA] [Size: numTris]
|
|
|
|
* @param numTris
|
|
|
|
* The number of triangles.
|
|
|
|
* @param flagMergeThreshold
|
|
|
|
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
|
|
|
|
* @see Heightfield
|
|
|
|
*/
|
2023-06-08 14:53:03 +03:00
|
|
|
public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] tris, int[] areaIds, int numTris,
|
2023-07-01 06:50:25 +03:00
|
|
|
int flagMergeThreshold, RcTelemetry ctx)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-07-08 06:20:20 +03:00
|
|
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
float inverseCellSize = 1.0f / heightfield.cs;
|
|
|
|
float inverseCellHeight = 1.0f / heightfield.ch;
|
|
|
|
for (int triIndex = 0; triIndex < numTris; ++triIndex)
|
|
|
|
{
|
|
|
|
int v0 = tris[triIndex * 3 + 0];
|
|
|
|
int v1 = tris[triIndex * 3 + 1];
|
|
|
|
int v2 = tris[triIndex * 3 + 2];
|
2023-05-05 02:44:48 +03:00
|
|
|
RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
|
2023-03-16 19:48:49 +03:00
|
|
|
inverseCellSize, inverseCellHeight, flagMergeThreshold);
|
|
|
|
}
|
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/**
|
2023-03-14 08:02:43 +03:00
|
|
|
* Rasterizes a triangle list into the specified heightfield. Expects each triangle to be specified as three
|
|
|
|
* sequential vertices of 3 floats. Spans will only be added for triangles that overlap the heightfield grid.
|
|
|
|
*
|
|
|
|
* @param heightfield
|
|
|
|
* An initialized heightfield.
|
|
|
|
* @param verts
|
|
|
|
* The vertices. [(x, y, z) * numVerts]
|
|
|
|
* @param areaIds
|
|
|
|
* The area id's of the triangles. [Limit: <= WALKABLE_AREA] [Size: numTris]
|
|
|
|
* @param tris
|
|
|
|
* The triangle indices. [(vertA, vertB, vertC) * nt]
|
|
|
|
* @param numTris
|
|
|
|
* The number of triangles.
|
|
|
|
* @param flagMergeThreshold
|
|
|
|
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
|
|
|
|
* @see Heightfield
|
|
|
|
*/
|
2023-06-08 14:53:03 +03:00
|
|
|
public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] areaIds, int numTris,
|
2023-07-01 06:50:25 +03:00
|
|
|
int flagMergeThreshold, RcTelemetry ctx)
|
2023-03-14 08:02:43 +03:00
|
|
|
{
|
2023-07-08 06:20:20 +03:00
|
|
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
float inverseCellSize = 1.0f / heightfield.cs;
|
|
|
|
float inverseCellHeight = 1.0f / heightfield.ch;
|
|
|
|
for (int triIndex = 0; triIndex < numTris; ++triIndex)
|
|
|
|
{
|
|
|
|
int v0 = (triIndex * 3 + 0);
|
|
|
|
int v1 = (triIndex * 3 + 1);
|
|
|
|
int v2 = (triIndex * 3 + 2);
|
2023-05-05 02:44:48 +03:00
|
|
|
RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
|
2023-03-16 19:48:49 +03:00
|
|
|
inverseCellSize, inverseCellHeight, flagMergeThreshold);
|
|
|
|
}
|
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
2023-06-03 16:13:27 +03:00
|
|
|
}
|