wip(standalone): owner LOD0 defects -- skirt curtains clipped, exact edge roots; interrupted (OpenAI capacity)
Not verified as a whole. In the tree when Luna's session ended ("model at capacity"):
- fins: LOD seam skirts could hang into tunnel air; skirt triangles are now clipped against the solid
half-space and carry a per-face mask so a host can hide skirts between same-LOD neighbours.
- choppy LOD0 stairs: marching cubes' linear edge interpolation misplaced vertices where the relief
bends within one cell; edge crossings corrected with the exact field (82 patches, midpoint-edge
errors 18,818 -> 3,288); normal halo now ignores the +-4.125 fallback samples.
- an explicit unclamped Core distance query for audits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
08ceed200d
commit
b3af0e589e
7 files changed
+1304
-62
No files matched your search
@@ -56,6 +56,9 @@ namespace VoxelForgeCore
|
||||
TileKey key;
|
||||
std::vector<MeshVertex> vertices;
|
||||
std::vector<std::uint32_t> indices;
|
||||
// One entry per triangle. Zero is a surface triangle; skirt entries contain the
|
||||
// boundary-face bit mask (bit order: -X,+X,-Y,+Y,-Z,+Z).
|
||||
std::vector<std::uint8_t> skirtFaceMasks;
|
||||
std::vector<float> debugDensitySamples;
|
||||
MeshGroups groups;
|
||||
std::uint64_t densitySampleCount = 0;
|
||||
@@ -148,6 +151,13 @@ namespace VoxelForgeCore
|
||||
std::uint64_t walkFailures = 0;
|
||||
};
|
||||
|
||||
struct DetailFieldSample
|
||||
{
|
||||
float displacement = 0.0f;
|
||||
float caveInfluence = 0.0f;
|
||||
float floorInfluence = 0.0f;
|
||||
};
|
||||
|
||||
struct TileRegionCompileStats
|
||||
{
|
||||
std::size_t regionsBuilt = 0;
|
||||
@@ -229,6 +239,9 @@ namespace VoxelForgeCore
|
||||
ShapeBuildStats buildStats() const;
|
||||
|
||||
float densityAt(Vec3d voxelPosition) const;
|
||||
// Analytic source distance without the occupancy-preserving near-zero clamp or packed proxy.
|
||||
float unclampedDensityAt(Vec3d voxelPosition) const;
|
||||
DetailFieldSample detailSampleAt(Vec3d voxelPosition) const;
|
||||
float densityAtLattice(Vec3i voxelPosition) const;
|
||||
bool isSolidAt(Vec3d voxelPosition) const;
|
||||
bool isSolidAlongSegment(Vec3d start, Vec3d end, double sampleSpacingVoxels = 0.5) const;
|
||||
|
||||
@@ -313,7 +313,7 @@ public:
|
||||
const size_t NZ=static_cast<size_t>(Size[2]);
|
||||
WordsPerZ=(NZ+63u)/64u;
|
||||
RockWords.assign(static_cast<size_t>(Size[0])*Size[1]*WordsPerZ,0);
|
||||
SurfaceDistanceQ=std::make_unique_for_overwrite<int8[]>(static_cast<size_t>(NodeCount));
|
||||
SurfaceDistanceQ=std::make_unique_for_overwrite<int16[]>(static_cast<size_t>(NodeCount));
|
||||
BuildPackedRockIntervals(Stats.RockIntervalLines);
|
||||
BuildCandidateBands(Stats.CandidateAxisLines,Stats.CandidateMergeLines,
|
||||
Stats.CandidateMergeSeconds);
|
||||
@@ -348,7 +348,7 @@ public:
|
||||
Stats.DetailBandLines.WorkerSeconds*1000.0);
|
||||
std::printf("[ShapeAllocation] words=%.2fMiB candidate_axis_words=%.2fMiB proxy=%.2fMiB primitives=%.2fMiB spatial_bins=%llu spatial_bin_refs=%llu spatial_bin_capacity=%llu inline_bins=%llu overflow_bins=%llu far_primitive_build=%.3fms far_bin_rebuild=%.3fms\n",
|
||||
static_cast<double>(WordBytes)/1048576.0,static_cast<double>(CandidateAxisBytes)/1048576.0,
|
||||
static_cast<double>(Stats.SignNodes*sizeof(int8))/1048576.0,
|
||||
static_cast<double>(Stats.SignNodes*sizeof(int16))/1048576.0,
|
||||
static_cast<double>(Primitives.capacity()*sizeof(FPrimitive))/1048576.0,
|
||||
static_cast<unsigned long long>(SpatialBins.size()),
|
||||
static_cast<unsigned long long>(BinReferences),
|
||||
@@ -364,7 +364,7 @@ public:
|
||||
static_cast<unsigned long long>(Stats.SignNodes),
|
||||
static_cast<double>(WordBytes)/1048576.0,
|
||||
static_cast<unsigned long long>(Stats.SurfaceProxyNodes),
|
||||
static_cast<double>(Stats.SignNodes*sizeof(int8))/1048576.0,WorkerCount);
|
||||
static_cast<double>(Stats.SignNodes*sizeof(int16))/1048576.0,WorkerCount);
|
||||
std::printf("[ShapeStage] local-shapes=%.3f ms intervals+signs=%.3f ms surface-band=%.3f ms far-parents=%.3f ms total=%.3f ms candidates=%llu flips=%llu walk=%llu/%llu\n",
|
||||
Stats.ShapeSeconds*1000.0,Stats.IntervalSeconds*1000.0,Stats.SurfaceSeconds*1000.0,Stats.FarShapeSeconds*1000.0,
|
||||
std::chrono::duration<double>(Clock::now()-TotalStart).count()*1000.0,
|
||||
@@ -539,6 +539,24 @@ public:
|
||||
static_cast<float>(Z));
|
||||
}
|
||||
|
||||
float DensityAtUnclamped(float X,float Y,float Z) const
|
||||
{
|
||||
return AnalyticDensityAt(X,Y,Z,false);
|
||||
}
|
||||
|
||||
VoxelForgeCore::DetailFieldSample DetailSampleAt(float X,float Y,float Z) const
|
||||
{
|
||||
VoxelForgeCore::DetailFieldSample Sample;
|
||||
AnalyticDensityAt(X,Y,Z,false,&Sample.displacement,
|
||||
&Sample.caveInfluence,&Sample.floorInfluence);
|
||||
return Sample;
|
||||
}
|
||||
|
||||
bool IsProxyBandFallback(float Density) const
|
||||
{
|
||||
return std::abs(std::abs(Density)-(DetailSupremum+0.125f))<1.0e-4f;
|
||||
}
|
||||
|
||||
bool IsAnalyticOnly() const { return bAnalyticOnly; }
|
||||
|
||||
void DensityAtLatticeX8(int32 XStart,int32 XStep,int32 Y,int32 Z,
|
||||
@@ -578,11 +596,11 @@ public:
|
||||
float Density;
|
||||
if(CandidateWords[Word]&Mask)
|
||||
{
|
||||
const int8 Proxy=SurfaceDistanceQ[NodeBase
|
||||
const int16 Proxy=SurfaceDistanceQ[NodeBase
|
||||
+static_cast<size_t>(Lane*XStep)];
|
||||
Density=static_cast<float>(Proxy)*(1.0f/16.0f);
|
||||
Density=static_cast<float>(Proxy)*(1.0f/256.0f);
|
||||
if((Density<0.0f)!=bRock)
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/16.0f);
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/256.0f);
|
||||
}
|
||||
else
|
||||
Density=bRock?-ProxyBandEdge:ProxyBandEdge;
|
||||
@@ -607,10 +625,10 @@ private:
|
||||
if(CandidateWords[Word]&Mask)
|
||||
{
|
||||
const size_t Node=Zi*static_cast<size_t>(Size[1])*Size[0]+Column;
|
||||
const int8 Proxy=SurfaceDistanceQ[Node];
|
||||
float Density=static_cast<float>(Proxy)*(1.0f/16.0f);
|
||||
const int16 Proxy=SurfaceDistanceQ[Node];
|
||||
float Density=static_cast<float>(Proxy)*(1.0f/256.0f);
|
||||
if((Density<0.0f)!=bRock)
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/16.0f);
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/256.0f);
|
||||
return ApplyEditBrushes(Density,FX,FY,FZ);
|
||||
}
|
||||
// Match the fixed fallback to the edge of the stored proxy band. The
|
||||
@@ -620,8 +638,14 @@ private:
|
||||
return ApplyEditBrushes(bRock?-ProxyBandEdge:ProxyBandEdge,FX,FY,FZ);
|
||||
}
|
||||
|
||||
float AnalyticDensityAt(float X,float Y,float Z) const
|
||||
float AnalyticDensityAt(float X,float Y,float Z,bool bClampNearZero=true,
|
||||
float* OutDetailDisplacement=nullptr,
|
||||
float* OutCaveInfluence=nullptr,
|
||||
float* OutFloorInfluence=nullptr) const
|
||||
{
|
||||
if(OutDetailDisplacement)*OutDetailDisplacement=0.0f;
|
||||
if(OutCaveInfluence)*OutCaveInfluence=0.0f;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
|
||||
const bool bInsideFine=X>=Min[0]&&X<=Max[0]&&Y>=Min[1]&&Y<=Max[1]
|
||||
&&Z>=Min[2]&&Z<=Max[2];
|
||||
if(!bInsideFine)
|
||||
@@ -631,8 +655,9 @@ private:
|
||||
if(bCriticalAir)RockDistance=std::min(RockDistance,-1.0f/16.0f);
|
||||
const bool bRock=RockDistance>=0.0f;
|
||||
float Density=-RockDistance;
|
||||
if((Density<0.0f)!=bRock||std::abs(Density)<0.05f)
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),0.05f);
|
||||
if((Density<0.0f)!=bRock||(bClampNearZero&&std::abs(Density)<0.05f))
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),
|
||||
bClampNearZero?0.05f:1.0e-7f);
|
||||
return ApplyEditBrushes(Density,X,Y,Z);
|
||||
}
|
||||
ESurfaceFamily SurfaceFamily=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
@@ -641,19 +666,27 @@ private:
|
||||
float RockDistance=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,
|
||||
&bFloorSurface,&CaveInfluence,&FloorInfluence,&bCriticalAir,nullptr,false,
|
||||
&PassageInfluence);
|
||||
if(OutCaveInfluence)*OutCaveInfluence=CaveInfluence;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=FloorInfluence;
|
||||
if(bInsideFine&&DetailVariant!=EDetailVariant::Smooth
|
||||
&&std::abs(RockDistance)<=DetailSupremum+0.125f)
|
||||
{
|
||||
const float Fade=DetailBandFadeAt(X,Y,Z,RockDistance,SurfaceSDF,
|
||||
CaveInfluence,FloorInfluence);
|
||||
if(Fade>0.0f)RockDistance+=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,
|
||||
FloorInfluence,PassageInfluence)*Fade;
|
||||
if(Fade>0.0f)
|
||||
{
|
||||
const float Detail=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,
|
||||
FloorInfluence,PassageInfluence)*Fade;
|
||||
RockDistance+=Detail;
|
||||
if(OutDetailDisplacement)*OutDetailDisplacement=Detail;
|
||||
}
|
||||
}
|
||||
if(bCriticalAir)RockDistance=std::min(RockDistance,-1.0f/16.0f);
|
||||
const bool bRock=RockDistance>=0.0f;
|
||||
float Density=-RockDistance;
|
||||
if((Density<0.0f)!=bRock||std::abs(Density)<0.05f)
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),0.05f);
|
||||
if((Density<0.0f)!=bRock||(bClampNearZero&&std::abs(Density)<0.05f))
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),
|
||||
bClampNearZero?0.05f:1.0e-7f);
|
||||
return ApplyEditBrushes(Density,X,Y,Z);
|
||||
}
|
||||
|
||||
@@ -923,7 +956,9 @@ public:
|
||||
const double OX=CameraX*4.0,OY=CameraY*4.0,OZ=CameraZ*4.0;
|
||||
auto Distance=[&](double X,double Y,double Z,ESurfaceFamily* OutFamily=nullptr,
|
||||
float* OutRaw=nullptr,float* OutDetail=nullptr,
|
||||
bool* OutFloorSurface=nullptr,float* OutPassageInfluence=nullptr)
|
||||
bool* OutFloorSurface=nullptr,float* OutPassageInfluence=nullptr,
|
||||
float* OutCaveInfluence=nullptr,float* OutFloorInfluence=nullptr,
|
||||
float* OutSurfaceSDF=nullptr)
|
||||
{
|
||||
ESurfaceFamily Family=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
|
||||
@@ -948,6 +983,9 @@ public:
|
||||
if(OutDetail)*OutDetail=Detail;
|
||||
if(OutFloorSurface)*OutFloorSurface=bFloorSurface;
|
||||
if(OutPassageInfluence)*OutPassageInfluence=PassageInfluence;
|
||||
if(OutCaveInfluence)*OutCaveInfluence=CaveInfluence;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=FloorInfluence;
|
||||
if(OutSurfaceSDF)*OutSurfaceSDF=SurfaceSDF;
|
||||
return D;
|
||||
};
|
||||
uint64 TotalHits=0,TotalAxisLocked=0,TotalNearZero=0,FloorTaggedHits=0,FloorAxisLocked=0;
|
||||
@@ -982,7 +1020,9 @@ public:
|
||||
const double XH=OX+DX*HitT,YH=OY+DY*HitT,ZH=OZ+DZ*HitT;
|
||||
ESurfaceFamily Family=ESurfaceFamily::Strata;float Raw=0.0f,Detail=0.0f;
|
||||
bool bFloorSurface=false;float PassageInfluence=0.0f;
|
||||
Distance(XH,YH,ZH,&Family,&Raw,&Detail,&bFloorSurface,&PassageInfluence);
|
||||
float CaveInfluence=0.0f,FloorInfluence=0.0f,SurfaceSDF=100000.0f;
|
||||
Distance(XH,YH,ZH,&Family,&Raw,&Detail,&bFloorSurface,&PassageInfluence,
|
||||
&CaveInfluence,&FloorInfluence,&SurfaceSDF);
|
||||
const double GX=Distance(XH+0.5,YH,ZH)-Distance(XH-0.5,YH,ZH);
|
||||
const double GY=Distance(XH,YH+0.5,ZH)-Distance(XH,YH-0.5,ZH);
|
||||
const double GZ=Distance(XH,YH,ZH+0.5)-Distance(XH,YH,ZH-0.5);
|
||||
@@ -1036,8 +1076,19 @@ public:
|
||||
{
|
||||
const char* Name=Family==ESurfaceFamily::Strata?"strata":
|
||||
Family==ESurfaceFamily::Cave?"cave":"solid_overlay";
|
||||
std::printf("[SurfaceRay] t=%.2f vox hit=(%.2f,%.2f,%.2f) family=%s floor_surface=%s passage_influence=%.3f raw_sdf=%.4f detail=%.4f axis_dot=%.4f\n",
|
||||
HitT,XH,YH,ZH,Name,bFloorSurface?"yes":"no",PassageInfluence,Raw,Detail,AxisDot);
|
||||
const FLayerField* Field=FindLayerField(ZH);
|
||||
FOwnerNoiseLineContext OwnerNoise8,OwnerNoise2;
|
||||
const float Owner8=Field?OwnerCaveRoughness(XH,YH,ZH,SurfaceSDF,
|
||||
*Field,CaveInfluence,OwnerNoise8,nullptr,8):0.0f;
|
||||
const float Owner2=Field?OwnerCaveRoughness(XH,YH,ZH,SurfaceSDF,
|
||||
*Field,CaveInfluence,OwnerNoise2,nullptr,2):0.0f;
|
||||
const float Relief=SurfaceRelief(static_cast<float>(XH),
|
||||
static_cast<float>(YH),static_cast<float>(ZH),
|
||||
static_cast<uint32>(Owner->Seed));
|
||||
std::printf("[SurfaceRay] t=%.2f vox hit=(%.2f,%.2f,%.2f) family=%s floor_surface=%s cave_influence=%.3f floor_influence=%.3f passage_influence=%.3f surface_sdf=%.4f raw_sdf=%.4f detail=%.4f relief=%.4f owner8=%.4f owner2=%.4f axis_dot=%.4f\n",
|
||||
HitT,XH,YH,ZH,Name,bFloorSurface?"yes":"no",CaveInfluence,
|
||||
FloorInfluence,PassageInfluence,SurfaceSDF,Raw,Detail,Relief,
|
||||
Owner8,Owner2,AxisDot);
|
||||
}
|
||||
bFound=true;break;
|
||||
}
|
||||
@@ -1245,6 +1296,12 @@ private:
|
||||
constexpr float Width=1.5f;
|
||||
return SmoothUnit((Edge-std::abs(SignedDistance))/Width);
|
||||
}
|
||||
static float DetailContrast(float CaveInfluence,float FloorInfluence)
|
||||
{
|
||||
const float Cave=std::clamp(CaveInfluence,0.0f,1.0f);
|
||||
const float Floor=std::clamp(FloorInfluence,0.0f,1.0f);
|
||||
return 1.35f-0.80f*Cave+1.85f*Floor;
|
||||
}
|
||||
static constexpr float DetailBandInnerRadius=1.5f;
|
||||
static float DetailBandFade(float SignedDistance,float Edge)
|
||||
{
|
||||
@@ -1271,8 +1328,7 @@ private:
|
||||
}
|
||||
const float ReliefBound=std::abs(MacroValue)
|
||||
+(0.80f+0.25f*MacroValue)*(0.85f+0.18f);
|
||||
const float Contrast=1.35f-0.80f*std::clamp(CaveInfluence,0.0f,1.0f)
|
||||
+1.85f*std::clamp(FloorInfluence,0.0f,1.0f);
|
||||
const float Contrast=DetailContrast(CaveInfluence,FloorInfluence);
|
||||
const float LocalSupremum=std::min(3.9f,(ReliefBound+0.5f*OwnerBound)*Contrast);
|
||||
return std::clamp(LocalSupremum+0.125f,DetailBandInnerRadius,DetailSupremum+0.125f);
|
||||
}
|
||||
@@ -3040,10 +3096,10 @@ private:
|
||||
|
||||
void StoreSurfaceDistance(size_t Node,float Density)
|
||||
{
|
||||
int32 Q=static_cast<int32>(std::lround(Density*16.0f));
|
||||
Q=std::clamp(Q,-127,127);
|
||||
int32 Q=static_cast<int32>(std::lround(Density*256.0f));
|
||||
Q=std::clamp(Q,-32767,32767);
|
||||
if(Q==0)Q=Density<0.0f?-1:1;
|
||||
SurfaceDistanceQ[Node]=static_cast<int8>(Q);
|
||||
SurfaceDistanceQ[Node]=static_cast<int16>(Q);
|
||||
}
|
||||
|
||||
bool IsInsideSolidOverlay(int32 X,int32 Y,int32 Z) const
|
||||
@@ -3727,8 +3783,8 @@ private:
|
||||
static float SurfaceRelief(float X,float Y,float Z,uint32 Seed)
|
||||
{
|
||||
// The low band carries the broad rock shapes and also gently varies mid-band
|
||||
// amplitude. The quieter 6-voxel octave keeps fine relief without restoring
|
||||
// the same tight bubble pattern on every exposed surface.
|
||||
// amplitude. Keep the finest octave wider than a few marching-cubes cells so
|
||||
// it does not alias into voxel-sized ledges on the full-detail surface.
|
||||
const float Macro=FStandaloneResearchTunnels::ValueNoise(X,Y,Z,32,Seed^0xB5297A4Du);
|
||||
const float Mid=FStandaloneResearchTunnels::ValueNoise(X,Y,Z,16,Seed^0x63D83595u);
|
||||
const float Fine=FStandaloneResearchTunnels::ValueNoise(X,Y,Z,6,Seed^0xA511E9B3u);
|
||||
@@ -3794,7 +3850,7 @@ private:
|
||||
FOwnerNoiseLineContext OwnerNoise;
|
||||
FDetailNoiseLineContext(float X,float Y,uint32 Seed)
|
||||
:Macro(X,Y,32,Seed^0xB5297A4Du),Mid(X,Y,16,Seed^0x63D83595u),
|
||||
Fine(X,Y,6,Seed^0xA511E9B3u)
|
||||
Fine(X,Y,6,Seed^0xA511E9B3u)
|
||||
{}
|
||||
|
||||
float SurfaceReliefAt(float Z,bool bMacroKnown=false,float KnownMacro=0.0f)
|
||||
@@ -3827,9 +3883,9 @@ private:
|
||||
if(Field)
|
||||
OwnerRelief=OwnerCaveRoughnessForDetail(X,Y,Z,SurfaceSDF,*Field,
|
||||
CaveInfluence,PassageWeight,OwnerNoise);
|
||||
const float Contrast=1.35f-0.80f*std::clamp(CaveInfluence,0.0f,1.0f)
|
||||
+1.85f*std::clamp(FloorInfluence,0.0f,1.0f);
|
||||
return std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
|
||||
const float Contrast=DetailContrast(CaveInfluence,FloorInfluence);
|
||||
const float Detail=std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
|
||||
return Detail;
|
||||
}
|
||||
|
||||
float DetailNoiseOnLine(double X,double Y,double Z,float SurfaceSDF,
|
||||
@@ -3864,9 +3920,9 @@ private:
|
||||
if(Profile)
|
||||
Profile->OwnerRoughnessSampleNanoseconds+=static_cast<uint64>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now()-OwnerStart).count());
|
||||
const float Contrast=1.35f-0.80f*std::clamp(CaveInfluence,0.0f,1.0f)
|
||||
+1.85f*std::clamp(FloorInfluence,0.0f,1.0f);
|
||||
return std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
|
||||
const float Contrast=DetailContrast(CaveInfluence,FloorInfluence);
|
||||
const float Detail=std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
|
||||
return Detail;
|
||||
}
|
||||
|
||||
bool EvaluateFast(double X,double Y,double Z) const
|
||||
@@ -4012,7 +4068,7 @@ private:
|
||||
std::unordered_map<FBinKey,FBinItems,FBinHash> SpatialBins;
|
||||
std::unordered_map<FBinKey,FBinItems,FBinHash> CriticalAirBins;
|
||||
std::vector<uint64> RockWords;
|
||||
std::unique_ptr<int8[]> SurfaceDistanceQ;
|
||||
std::unique_ptr<int16[]> SurfaceDistanceQ;
|
||||
std::array<std::vector<uint64>,3> CandidateAxisWords;
|
||||
std::vector<uint64> CandidateWords;
|
||||
FBuildStats Stats;
|
||||
|
||||
@@ -128,6 +128,8 @@ namespace VoxelForgeCore
|
||||
{ AddWord(hash,color.R,1); AddWord(hash,color.G,1); AddWord(hash,color.B,1); AddWord(hash,color.A,1); }
|
||||
AddWord(hash,static_cast<std::uint64_t>(mesh.Triangles.Num()),8);
|
||||
for(const int32 index:mesh.Triangles)AddWord(hash,static_cast<std::uint32_t>(index),4);
|
||||
AddWord(hash,static_cast<std::uint64_t>(mesh.TriangleSkirtFaceMasks.Num()),8);
|
||||
for(const uint8 faces:mesh.TriangleSkirtFaceMasks)AddWord(hash,faces,1);
|
||||
AddWord(hash,static_cast<std::uint32_t>(mesh.NumSurfaceVertices),4);
|
||||
AddWord(hash,static_cast<std::uint32_t>(mesh.NumSkirtTriangles),4);
|
||||
AddWord(hash,static_cast<std::uint32_t>(mesh.NumCeilingTriangles),4);
|
||||
@@ -502,6 +504,10 @@ namespace VoxelForgeCore
|
||||
|
||||
float World::densityAt(Vec3d position) const
|
||||
{ return impl_&&impl_->shape?impl_->shape->DensityAt(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):0.0f; }
|
||||
float World::unclampedDensityAt(Vec3d position) const
|
||||
{ return impl_&&impl_->shape?impl_->shape->DensityAtUnclamped(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):0.0f; }
|
||||
DetailFieldSample World::detailSampleAt(Vec3d position) const
|
||||
{ return impl_&&impl_->shape?impl_->shape->DetailSampleAt(static_cast<float>(position.x),static_cast<float>(position.y),static_cast<float>(position.z)):DetailFieldSample{}; }
|
||||
float World::densityAtLattice(Vec3i position) const
|
||||
{ return impl_&&impl_->shape?impl_->shape->DensityAtLattice(position.x,position.y,position.z):0.0f; }
|
||||
bool World::isSolidAt(Vec3d position) const { return densityAt(position)<0.0f; }
|
||||
@@ -614,12 +620,16 @@ namespace VoxelForgeCore
|
||||
+static_cast<std::uint64_t>(mesh.Normals.GetAllocatedSize())
|
||||
+static_cast<std::uint64_t>(mesh.UVs.GetAllocatedSize())
|
||||
+static_cast<std::uint64_t>(mesh.Colors.GetAllocatedSize())
|
||||
+static_cast<std::uint64_t>(mesh.TriangleSkirtFaceMasks.GetAllocatedSize())
|
||||
+static_cast<std::uint64_t>(mesh.Triangles.GetAllocatedSize());
|
||||
out.groups.surfaceVertexCount=static_cast<std::uint32_t>(mesh.NumSurfaceVertices);
|
||||
out.groups.ceilingTriangleCount=static_cast<std::uint32_t>(mesh.NumCeilingTriangles);
|
||||
out.groups.groundTriangleCount=static_cast<std::uint32_t>(
|
||||
std::max(0,mesh.Triangles.Num()/3-mesh.NumCeilingTriangles));
|
||||
out.groups.skirtTriangleCount=static_cast<std::uint32_t>(mesh.NumSkirtTriangles);
|
||||
out.skirtFaceMasks.assign(mesh.TriangleSkirtFaceMasks.begin(),
|
||||
mesh.TriangleSkirtFaceMasks.end());
|
||||
out.skirtFaceMasks.resize(mesh.Triangles.Num()/3,0);
|
||||
out.vertices.reserve(static_cast<std::size_t>(mesh.Vertices.Num()));
|
||||
for(int32 i=0;i<mesh.Vertices.Num();++i)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user