in UVAtlas/isochart/meshpartitionchart.cpp [1295:1557]
HRESULT CIsochartMesh::ProcessPlaneLikeShape(
size_t dwCalculatedDimension,
size_t dwPrimaryEigenDimension,
bool& bPlaneLikeShape)
{
HRESULT hr = S_OK;
bPlaneLikeShape = false;
#if USING_COMBINED_DISTANCE_TO_PARAMETERIZE
if (IsIMTSpecified())
{
return hr;
}
#endif
// When processing sub-chart, only process the chart which is exactly isomorphic
// to a plane. Otherwise, self overlapping can be easily generated.
if (m_bIsSubChart && dwCalculatedDimension > 2)
{
return hr;
}
// Only used to expand charts whose energy centralizes into one plane.
if (dwPrimaryEigenDimension > 2)
{
return hr;
}
// Find one face as the standard face to expand all other faces
uint32_t dwStandardFaceID = INVALID_FACE_ID;
for (uint32_t i = 0; i < m_dwFaceNumber; i++)
{
if (m_baseInfo.pfFaceAreaArray[m_pFaces[i].dwIDInRootMesh]
> ISOCHART_ZERO_EPS
&& INVALID_FACE_ID == dwStandardFaceID)
{
dwStandardFaceID = i;
break;
}
}
if (INVALID_FACE_ID == dwStandardFaceID)
{
return hr;
}
XMVECTOR axisX, axisY, axisZ;
XMVECTOR normalDelta;
XMFLOAT3 v1, v2;
XMVECTOR temp[3];
std::queue<uint32_t> faceQueue;
std::unique_ptr<bool[]> rgbVertProcessed(new (std::nothrow) bool[m_dwVertNumber]);
std::unique_ptr<bool[]> rgbFaceAdded(new (std::nothrow) bool[m_dwFaceNumber]);
if (!rgbVertProcessed || !rgbFaceAdded)
{
return E_OUTOFMEMORY;
}
memset(rgbFaceAdded.get(), 0, sizeof(bool) * m_dwFaceNumber);
memset(rgbVertProcessed.get(), 0, sizeof(bool) * m_dwVertNumber);
// Parameterize the standard face to UV plane
XMVECTOR vV[3];
ISOCHARTFACE& face = m_pFaces[dwStandardFaceID];
for (size_t i = 0; i < 3; i++)
{
ISOCHARTVERTEX& v = m_pVerts[face.dwVertexID[i]];
vV[i] = XMLoadFloat3(m_baseInfo.pVertPosition + v.dwIDInRootMesh);
}
float fMinDot = FLT_MAX;
uint32_t dwOrgIndex = INVALID_INDEX;
// Find a vertex whose adjacent 2 edges has angle closest to PI/4
for (uint32_t i = 0; i < 3; i++)
{
axisX = XMVectorSubtract(vV[(i + 1) % 3], vV[i]);
axisY = XMVectorSubtract(vV[(i + 2) % 3], vV[i]);
axisX = XMVector3Normalize(axisX);
axisY = XMVector3Normalize(axisY);
float fDot = fabsf(XMVectorGetX(XMVector3Dot(axisX, axisY)));
if (fMinDot > fDot)
{
fMinDot = fDot;
dwOrgIndex = i;
}
}
_Analysis_assume_(dwOrgIndex < 3);
axisX = XMVectorSubtract(vV[(dwOrgIndex + 1) % 3], vV[dwOrgIndex]);
axisY = XMVectorSubtract(vV[(dwOrgIndex + 2) % 3], vV[dwOrgIndex]);
axisZ = XMVector3Cross(axisX, axisY);
axisY = XMVector3Cross(axisZ, axisX);
axisX = XMVector3Normalize(axisX);
axisY = XMVector3Normalize(axisY);
axisZ = XMVector3Normalize(axisZ);
for (size_t i = 0; i < 3; i++)
{
normalDelta = XMVectorSubtract(vV[(dwOrgIndex + i) % 3], vV[dwOrgIndex]);
m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.x =
XMVectorGetX(XMVector3Dot(normalDelta, axisX));
m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.y =
XMVectorGetX(XMVector3Dot(normalDelta, axisY));
temp[(dwOrgIndex + i) % 3] = XMVectorSet(
m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.x,
m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.y,
0, 0);
rgbVertProcessed[face.dwVertexID[(dwOrgIndex + i) % 3]] = true;
}
XMStoreFloat3(&v1, XMVectorSubtract(temp[1], temp[0]));
XMStoreFloat3(&v2, XMVectorSubtract(temp[2], temp[0]));
bool bPositive = (CalculateZOfVec3Cross(&v1, &v2) >= 0);
// From iteratively lay faces adjacent to the parameterized faces onto UV plane.
try
{
faceQueue.push(dwStandardFaceID);
rgbFaceAdded[dwStandardFaceID] = true;
while (!faceQueue.empty())
{
uint32_t dwFaceID = faceQueue.front();
faceQueue.pop();
ISOCHARTFACE& curFace = m_pFaces[dwFaceID];
for (size_t i = 0; i < 3; i++)
{
if (!rgbVertProcessed[curFace.dwVertexID[i]])
{
uint32_t vId0 = curFace.dwVertexID[(i + 1) % 3];
uint32_t vId1 = curFace.dwVertexID[(i + 2) % 3];
assert(rgbVertProcessed[vId0]);
assert(rgbVertProcessed[vId1]);
uint32_t vId2 = curFace.dwVertexID[i];
vV[0] = XMLoadFloat3(m_baseInfo.pVertPosition + m_pVerts[vId0].dwIDInRootMesh);
vV[1] = XMLoadFloat3(m_baseInfo.pVertPosition + m_pVerts[vId1].dwIDInRootMesh);
vV[2] = XMLoadFloat3(m_baseInfo.pVertPosition + m_pVerts[vId2].dwIDInRootMesh);
XMVECTOR vv1 = XMVectorSubtract(vV[1], vV[0]);
XMVECTOR vv2 = XMVectorSubtract(vV[2], vV[0]);
float fLen1 = XMVectorGetX(XMVector3Length(vv1));
float fLen2 = XMVectorGetX(XMVector3Length(vv2));
if (IsInZeroRange(fLen1))
{
return S_OK;
}
if (IsInZeroRange(fLen2))
{
m_pVerts[vId2].uv = m_pVerts[vId0].uv;
rgbVertProcessed[vId2] = true;
break;
}
float cosB = XMVectorGetX(XMVector3Dot(vv1, vv2)) / (fLen1 * fLen2);
if (cosB < -1.0f)
{
cosB = -1.0f;
}
if (cosB > 1.0f)
{
cosB = 1.0f;
}
float sinB = IsochartSqrtf(1.0f - cosB * cosB);
XMFLOAT2 v2D;
XMStoreFloat2(&v2D, XMVector2Normalize(
XMVectorSubtract(XMLoadFloat2(&m_pVerts[vId1].uv), XMLoadFloat2(&m_pVerts[vId0].uv))));
float x = v2D.x * cosB - v2D.y * sinB;
float y = v2D.y * cosB + v2D.x * sinB;
temp[i] = XMVectorSet(x, y, 0, 0);
temp[(i + 1) % 3] = XMVectorSet(0, 0, 0, 0);
temp[(i + 2) % 3] = XMVectorSet(v2D.x, v2D.y, 0, 0);
XMStoreFloat3(&v1, XMVectorSubtract(temp[1], temp[0]));
XMStoreFloat3(&v2, XMVectorSubtract(temp[2], temp[0]));
bool bPositive1 = (CalculateZOfVec3Cross(&v1, &v2) >= 0);
if ((bPositive && !bPositive1)
|| (!bPositive && bPositive1))
{
sinB = -sinB;
x = v2D.x * cosB - v2D.y * sinB;
y = v2D.y * cosB + v2D.x * sinB;
}
m_pVerts[vId2].uv.x = fLen2 * x + m_pVerts[vId0].uv.x;
m_pVerts[vId2].uv.y = fLen2 * y + m_pVerts[vId0].uv.y;
assert(std::isfinite(double(m_pVerts[vId2].uv.x)) &&
std::isfinite(double(m_pVerts[vId2].uv.y)));
if (!std::isfinite(double(m_pVerts[vId2].uv.x)) ||
!std::isfinite(double(m_pVerts[vId2].uv.y)))
{
DPF(0, "ProcessPlaneLikeShape failed due to INFs");
return E_FAIL;
}
rgbVertProcessed[vId2] = true;
break;
}
}
for (size_t i = 0; i < 3; i++)
{
ISOCHARTEDGE& edge = m_edges[curFace.dwEdgeID[i]];
uint32_t dwAdjacent = edge.dwFaceID[0];
if (dwAdjacent == curFace.dwID)
{
dwAdjacent = edge.dwFaceID[1];
}
if (dwAdjacent != INVALID_FACE_ID &&
!rgbFaceAdded[dwAdjacent])
{
faceQueue.push(dwAdjacent);
rgbFaceAdded[dwAdjacent] = true;
}
}
}
}
catch (std::bad_alloc&)
{
return E_OUTOFMEMORY;
}
#if CHECK_OVER_LAPPING_BEFORE_OPT_INFINIT
bool bIsOverlapping = false;
bIsOverlapping = IsSelfOverlapping(this);
if (bIsOverlapping)
{
DPF(1, "Generate self overlapping chart when processing plane-like chart");
return S_OK;
}
#endif
hr = OptimizeGeoLnInfiniteStretch(bPlaneLikeShape);
m_bIsParameterized = bPlaneLikeShape;
m_fParamStretchL2 = m_fBaseL2Stretch;
return hr;
}