Add elevation snippets to weld bound vertices

develop
kaetemi 4 years ago
parent 30ece314c5
commit 87b5a77d4f

@ -186,6 +186,111 @@ NLMISC::CVector getHeightNormal(float x, float y)
// compute the heightmap normal with the tangents
return (ds ^ dt).normed();
}
// ***************************************************************************
// void CExport::computeSubdividedTangents(uint numBinds, const NL3D::CBezierPatch &patch, uint edge, NLMISC::CVector subTangents[8])
void computeSubdividedTangents(uint numBinds, const NL3D::CBezierPatch &patch, uint edge, NLMISC::CVector subTangents[8])
{
// Subdivide the Bezier patch to get the correct tangents to apply to neighbors
CBezierPatch subPatchs1_2[2];
CBezierPatch subPatchs1_4[4];
// subdivide on s if edge is horizontal
bool subDivideOnS= (edge&1)==1;
// Subdivide one time.
if(subDivideOnS) patch.subdivideS(subPatchs1_2[0], subPatchs1_2[1]);
else patch.subdivideT(subPatchs1_2[0], subPatchs1_2[1]);
// Subdivide again for bind 1/4.
if(numBinds==4)
{
if(subDivideOnS)
{
subPatchs1_2[0].subdivideS(subPatchs1_4[0], subPatchs1_4[1]);
subPatchs1_2[1].subdivideS(subPatchs1_4[2], subPatchs1_4[3]);
}
else
{
subPatchs1_2[0].subdivideT(subPatchs1_4[0], subPatchs1_4[1]);
subPatchs1_2[1].subdivideT(subPatchs1_4[2], subPatchs1_4[3]);
}
}
// Now, fill the tangents according to edge.
bool invertPaSrc= edge>=2;
// Bind 1/2 case.
if(numBinds==2)
{
// 4 tangents to fill.
for(uint i=0;i<4;i++)
{
// get patch id from 0 to 1.
uint paSrcId= i/2;
// invert if edge is 2 or 3
if(invertPaSrc) paSrcId= 1-paSrcId;
// get tg id in this patch.
uint tgSrcId= (i&1) + edge*2;
// fill result.
subTangents[i]= subPatchs1_2[paSrcId].Tangents[tgSrcId];
}
}
// Bind 1/4 case.
else
{
// 8 tangents to fill.
for(uint i=0;i<8;i++)
{
// get patch id from 0 to 3.
uint paSrcId= i/2;
// invert if edge is 2 or 3
if(invertPaSrc) paSrcId= 3-paSrcId;
// get tg id in this patch.
uint tgSrcId= (i&1) + edge*2;
// fill result.
subTangents[i]= subPatchs1_4[paSrcId].Tangents[tgSrcId];
}
}
}
// ***************************************************************************
// bool CExport::applyVertexBind(NL3D::CPatchInfo &pa, NL3D::CPatchInfo &oldPa, uint edgeToModify, bool startEdge, ...
bool applyVertexBind(NL3D::CPatchInfo &pa, NL3D::CPatchInfo &oldPa, uint edgeToModify, bool startEdge,
const NLMISC::CMatrix &oldTgSpace, const NLMISC::CMatrix &newTgSpace,
const NLMISC::CVector &bindedPos, const NLMISC::CVector &bindedTangent )
{
// Get the vertex to modify according to edge/startEdge
uint vertexToModify= edgeToModify + (startEdge?0:1);
vertexToModify&=3;
// If already moved, no-op
if(pa.Patch.Vertices[vertexToModify]==bindedPos)
return false;
else
{
// Change the vertex
pa.Patch.Vertices[vertexToModify]= bindedPos;
// change the tangent, according to startEdge
pa.Patch.Tangents[edgeToModify*2 + (startEdge?0:1) ]= bindedTangent;
// Must change the tangent which is on the other side of the vertex:
uint tgToModify= 8 + edgeToModify*2 + (startEdge?-1:+2);
tgToModify&=7;
/* To keep the same continuity aspect around the vertex, we compute the original tangent in a
special space: the Binded Patch Tangent Space. Once we have the original tangent in the original patch TgSpace,
we reapply it in the transformed patch TgSpace, to get the transformed tangent
*/
pa.Patch.Tangents[tgToModify]= newTgSpace * ( oldTgSpace.inverted() * oldPa.Patch.Tangents[tgToModify] );
// Do the same to the associated interior.
pa.Patch.Interiors[vertexToModify]= newTgSpace * ( oldTgSpace.inverted() * oldPa.Patch.Interiors[vertexToModify] );
// modified
return true;
}
}
void applyZoneHeightmap()
{
@ -201,6 +306,9 @@ void applyZoneHeightmap()
std::vector<CBorderVertex> zoneBorderVertices;
zone.retrieve(zonePatches, zoneBorderVertices);
// Bkup the original patchs.
vector<CPatchInfo> oldPatchInfos = zonePatches;
// Apply the Heighmap to all vertices/tangents/interiors (see Land Export tool.)
for (size_t i = 0; i < zonePatches.size(); ++i)
{
@ -254,6 +362,94 @@ void applyZoneHeightmap()
}
}
// See `void CExport::transformZone (CZone &zeZone, sint32 nPosX, sint32 nPosY, uint8 nRot, uint8 nFlip, bool computeHeightmap)`
// 3. For all binds, reset the position of near vertices/tangents/interiors. Must do it at last
// --------
bool bindVertexModified = true;
// Since this is a recursive problem (binded patchs may bind other patchs), do it unitl all vertices no more move :)
while (bindVertexModified)
{
bindVertexModified = false;
for (size_t i = 0; i < zonePatches.size(); ++i)
{
CPatchInfo &rPI = zonePatches[i];
// For all edges
for (size_t j = 0; j < 4; ++j)
{
uint numBinds = rPI.BindEdges[j].NPatchs;
// If this edge is binded on 2 or 4 patches.
if (numBinds == 2 || numBinds == 4)
{
// compute the 4 or 8 tangents along the edge (in CCW)
CVector subTangents[8];
computeSubdividedTangents(numBinds, rPI.Patch, j, subTangents);
// For all vertex to bind: 1 or 3.
for (uint vb = 0; vb < numBinds - 1; vb++)
{
// compute the s/t coordinate
float bindS, bindT;
// 0.5, or 0.25, 0.5, 0.75
float ec = (float)(vb + 1) / (float)numBinds;
switch (j)
{
case 0: bindS= 0; bindT= ec; break;
case 1: bindS= ec; bindT= 1; break;
case 2: bindS= 1; bindT= 1-ec; break;
case 3: bindS= 1-ec; bindT= 0; break;
}
// compute the vertex position from big patch.
CVector bindedPos;
bindedPos = rPI.Patch.eval(bindS, bindT);
// Compute a TgSpace matrix around this position.
CMatrix oldTgSpace;
CMatrix newTgSpace;
// Build the original tgtSpace (patch before deformation)
oldTgSpace.setRot(oldPatchInfos[i].Patch.evalTangentS(bindS, bindT),
oldPatchInfos[i].Patch.evalTangentT(bindS, bindT),
oldPatchInfos[i].Patch.evalNormal(bindS, bindT));
oldTgSpace.normalize(CMatrix::ZYX);
oldTgSpace.setPos(oldPatchInfos[i].Patch.eval(bindS, bindT));
// Build the new tgtSpace
newTgSpace.setRot(rPI.Patch.evalTangentS(bindS, bindT),
rPI.Patch.evalTangentT(bindS, bindT),
rPI.Patch.evalNormal(bindS, bindT));
newTgSpace.normalize(CMatrix::ZYX);
newTgSpace.setPos(bindedPos);
// apply to the 2 smaller binded patchs which share this vertex.
uint edgeToModify;
sint ngbId;
CVector bindedTangent;
// The first patch (CCW) must change the vertex which starts on the edge (CCW)
edgeToModify = rPI.BindEdges[j].Edge[vb];
// get the tangent to set
bindedTangent = subTangents[vb * 2 + 1];
// get the patch id.
ngbId = rPI.BindEdges[j].Next[vb];
bindVertexModified |= applyVertexBind(zonePatches[ngbId], oldPatchInfos[ngbId], edgeToModify,
true, oldTgSpace, newTgSpace, bindedPos, bindedTangent);
// The second patch (CCW) must change the vertex which ends on the edge (CCW)
edgeToModify = rPI.BindEdges[j].Edge[vb + 1];
// get the tangent to set
bindedTangent = subTangents[vb * 2 + 2];
// get the patch id.
ngbId = rPI.BindEdges[j].Next[vb + 1];
bindVertexModified |= applyVertexBind(zonePatches[ngbId], oldPatchInfos[ngbId], edgeToModify,
false, oldTgSpace, newTgSpace, bindedPos, bindedTangent);
}
}
}
}
}
// Save zone
zone.build(zoneId, zonePatches, zoneBorderVertices);
COFile centerSave(s_OutputZone);

Loading…
Cancel
Save