wip(L5, side branch): Linux offscreen captures + sampled far-LOD gate + no-op octave cutoff

Not for assembler/world: no octave qualifies under the cutoff's supremum criterion (world
unchanged), and the build is +4.6% slower than L4 with the flag off (reviewer interleaved W12).
Keeps the working EGL/GLES capture path and a gate whose metric is vertical height error, which
overstates screen error on steep slopes; its "exact far meshes exceed 1 px / 126 px pop" claims are
unconfirmed. See Linux5/REPORT.md "Orchestrator review".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ED33VnqepD4YY6gDAAA832
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 20:39:41 +02:00
1 parent 7770074503
commit b21a19d561
33 files changed
+1977 -26

No files matched your search

+387
View File
@@ -0,0 +1,387 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <png.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <limits>
#include <string>
#include <string_view>
#include <vector>
namespace
{
struct FVertex
{
float Position[3];
float Normal[3];
float Height;
};
struct FScene
{
std::uint32_t VoxelSizeMicrons=0;
std::array<double,3> CameraMeters{};
double YawDegrees=0.0,PitchDegrees=0.0;
std::vector<FVertex> Vertices;
std::vector<std::uint32_t> Indices;
std::uint64_t Triangles=0,SkirtTriangles=0;
std::uint32_t TileCount=0;
};
template<typename T> bool Read(std::ifstream& File,T& Value)
{
File.read(reinterpret_cast<char*>(&Value),sizeof(Value));
return static_cast<bool>(File);
}
bool LoadScene(const std::filesystem::path& Path,FScene& Scene,std::string& Error)
{
std::ifstream File(Path,std::ios::binary);
if(!File){Error="cannot open mesh scene";return false;}
char Magic[8]{};
File.read(Magic,sizeof(Magic));
if(!File||std::memcmp(Magic,"VFMSH001",8)!=0)
{Error="mesh scene magic is invalid";return false;}
std::uint32_t Version=0,ExpectedTiles=0;
if(!Read(File,Version)||!Read(File,Scene.VoxelSizeMicrons)||!Read(File,ExpectedTiles)
||Version!=1||Scene.VoxelSizeMicrons==0||ExpectedTiles>1000000)
{Error="mesh scene header is malformed";return false;}
for(double& Value:Scene.CameraMeters)if(!Read(File,Value))
{Error="mesh scene camera is truncated";return false;}
if(!Read(File,Scene.YawDegrees)||!Read(File,Scene.PitchDegrees))
{Error="mesh scene camera orientation is truncated";return false;}
Scene.TileCount=ExpectedTiles;
std::uint64_t TotalVertices=0,TotalIndices=0;
for(std::uint32_t Tile=0;Tile<ExpectedTiles;++Tile)
{
std::int32_t Key[4]{};
std::uint32_t SurfaceVertices=0,SkirtCount=0,VertexCount=0,IndexCount=0,MaskCount=0;
for(auto& Value:Key)if(!Read(File,Value)){Error="tile key is truncated";return false;}
if(!Read(File,SurfaceVertices)||!Read(File,SkirtCount)||!Read(File,VertexCount)
||!Read(File,IndexCount)||!Read(File,MaskCount)
||VertexCount>10000000||IndexCount>60000000||MaskCount>20000000
||IndexCount%3!=0||(MaskCount!=0&&MaskCount!=IndexCount/3))
{Error="tile mesh header is malformed";return false;}
if(TotalVertices+VertexCount>std::numeric_limits<std::uint32_t>::max()
||TotalIndices+IndexCount>std::numeric_limits<std::size_t>::max())
{Error="mesh scene exceeds supported index space";return false;}
const std::size_t Base=Scene.Vertices.size();
Scene.Vertices.resize(Base+VertexCount);
Scene.Indices.reserve(Scene.Indices.size()+IndexCount);
for(std::size_t I=Base;I<Base+VertexCount;++I)
for(float& Value:Scene.Vertices[I].Position)if(!Read(File,Value))
{Error="tile positions are truncated";return false;}
for(std::size_t I=Base;I<Base+VertexCount;++I)
{
for(float& Value:Scene.Vertices[I].Normal)if(!Read(File,Value))
{Error="tile normals are truncated";return false;}
Scene.Vertices[I].Height=Scene.Vertices[I].Position[2];
}
const std::size_t IndexOffset=Scene.Indices.size();
Scene.Indices.resize(IndexOffset+IndexCount);
if(IndexCount)File.read(reinterpret_cast<char*>(Scene.Indices.data()+IndexOffset),
static_cast<std::streamsize>(sizeof(std::uint32_t)*IndexCount));
std::vector<std::uint8_t> Masks(MaskCount);
if(MaskCount)File.read(reinterpret_cast<char*>(Masks.data()),MaskCount);
if(!File){Error="tile index or skirt data is truncated";return false;}
for(std::size_t Index=IndexOffset;Index<Scene.Indices.size();++Index)
{
if(Scene.Indices[Index]>=VertexCount)
{Error="tile index points outside its vertex array";return false;}
Scene.Indices[Index]+=static_cast<std::uint32_t>(Base);
}
Scene.Triangles+=IndexCount/3;
Scene.SkirtTriangles+=SkirtCount;
TotalVertices+=VertexCount;TotalIndices+=IndexCount;
}
if(File.peek()!=std::char_traits<char>::eof())
{Error="mesh scene has trailing bytes";return false;}
if(Scene.Indices.empty()){Error="mesh scene contains no triangles";return false;}
return true;
}
EGLDisplay MakeDisplay()
{
using TGetPlatformDisplay=EGLDisplay(*)(EGLenum,void*,const EGLint*);
auto GetPlatformDisplay=reinterpret_cast<TGetPlatformDisplay>(
eglGetProcAddress("eglGetPlatformDisplayEXT"));
#ifdef EGL_PLATFORM_SURFACELESS_MESA
if(GetPlatformDisplay)
{
const EGLDisplay Display=GetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA,
EGL_DEFAULT_DISPLAY,nullptr);
if(Display!=EGL_NO_DISPLAY)return Display;
}
#endif
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
GLuint CompileShader(GLenum Type,const char* Source)
{
const GLuint Shader=glCreateShader(Type);
glShaderSource(Shader,1,&Source,nullptr);
glCompileShader(Shader);
GLint Success=GL_FALSE;
glGetShaderiv(Shader,GL_COMPILE_STATUS,&Success);
if(Success==GL_FALSE)
{
GLint Length=0;glGetShaderiv(Shader,GL_INFO_LOG_LENGTH,&Length);
std::string Log(static_cast<std::size_t>(std::max(Length,1)),0);
glGetShaderInfoLog(Shader,Length,nullptr,Log.data());
std::fprintf(stderr,"[OffscreenGL] shader compile failed: %s\n",Log.c_str());
glDeleteShader(Shader);return 0;
}
return Shader;
}
GLuint MakeProgram()
{
static constexpr char VertexSource[]=R"GLSL(#version 300 es
precision highp float;
layout(location=0) in vec3 inCameraPosition;
layout(location=1) in vec3 inNormal;
layout(location=2) in float inHeight;
out vec3 vNormal;
out float vHeight;
uniform float uTanHalfHorizontal;
uniform float uTanHalfVertical;
uniform float uNear;
uniform float uFar;
void main()
{
float z=max(inCameraPosition.z,0.0001);
float clipZ=((uFar+uNear)/(uFar-uNear))*z-(2.0*uFar*uNear)/(uFar-uNear);
gl_Position=vec4(inCameraPosition.x/uTanHalfHorizontal,
inCameraPosition.y/uTanHalfVertical,clipZ,z);
vNormal=normalize(inNormal);
vHeight=inHeight;
})GLSL";
static constexpr char FragmentSource[]=R"GLSL(#version 300 es
precision highp float;
in vec3 vNormal;
in float vHeight;
out vec4 outColor;
void main()
{
vec3 n=normalize(vNormal);
vec3 normalColor=abs(n)*0.78+vec3(0.12);
float band=mod(floor((vHeight+10000.0)/80.0),2.0);
vec3 bandColor=mix(vec3(0.24,0.31,0.37),vec3(0.39,0.42,0.35),band);
outColor=vec4(mix(bandColor,normalColor,0.68),1.0);
})GLSL";
const GLuint VS=CompileShader(GL_VERTEX_SHADER,VertexSource);
const GLuint FS=CompileShader(GL_FRAGMENT_SHADER,FragmentSource);
if(!VS||!FS)return 0;
const GLuint Program=glCreateProgram();
glAttachShader(Program,VS);glAttachShader(Program,FS);glLinkProgram(Program);
glDeleteShader(VS);glDeleteShader(FS);
GLint Success=GL_FALSE;glGetProgramiv(Program,GL_LINK_STATUS,&Success);
if(Success==GL_FALSE)
{
GLint Length=0;glGetProgramiv(Program,GL_INFO_LOG_LENGTH,&Length);
std::string Log(static_cast<std::size_t>(std::max(Length,1)),0);
glGetProgramInfoLog(Program,Length,nullptr,Log.data());
std::fprintf(stderr,"[OffscreenGL] program link failed: %s\n",Log.c_str());
glDeleteProgram(Program);return 0;
}
return Program;
}
bool WritePng(const std::filesystem::path& Path,int Width,int Height,
const std::vector<std::uint8_t>& Pixels)
{
std::error_code Error;
if(!Path.parent_path().empty())std::filesystem::create_directories(Path.parent_path(),Error);
if(Error)return false;
FILE* File=std::fopen(Path.c_str(),"wb");
if(!File)return false;
png_structp Png=png_create_write_struct(PNG_LIBPNG_VER_STRING,nullptr,nullptr,nullptr);
png_infop Info=Png?png_create_info_struct(Png):nullptr;
if(!Png||!Info){if(Png)png_destroy_write_struct(&Png,nullptr);std::fclose(File);return false;}
if(setjmp(png_jmpbuf(Png)))
{png_destroy_write_struct(&Png,&Info);std::fclose(File);return false;}
png_init_io(Png,File);
png_set_IHDR(Png,Info,static_cast<png_uint_32>(Width),static_cast<png_uint_32>(Height),
8,PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
png_write_info(Png,Info);
const std::size_t Stride=static_cast<std::size_t>(Width)*4;
for(int Y=Height-1;Y>=0;--Y)
png_write_row(Png,const_cast<png_bytep>(Pixels.data()+static_cast<std::size_t>(Y)*Stride));
png_write_end(Png,nullptr);
png_destroy_write_struct(&Png,&Info);
const bool Good=std::fclose(File)==0;
return Good;
}
bool Render(FScene& Scene,const std::filesystem::path& Output,int Width,int Height,
double HorizontalFovDegrees)
{
EGLDisplay Display=MakeDisplay();
EGLint Major=0,Minor=0;
if(Display==EGL_NO_DISPLAY||eglInitialize(Display,&Major,&Minor)!=EGL_TRUE)
{std::fprintf(stderr,"[OffscreenEGL] eglInitialize failed (0x%x)\n",eglGetError());return false;}
if(eglBindAPI(EGL_OPENGL_ES_API)!=EGL_TRUE)
{std::fprintf(stderr,"[OffscreenEGL] eglBindAPI failed (0x%x)\n",eglGetError());eglTerminate(Display);return false;}
const EGLint ConfigAttributes[]={EGL_SURFACE_TYPE,EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE,EGL_OPENGL_ES3_BIT,EGL_RED_SIZE,8,EGL_GREEN_SIZE,8,
EGL_BLUE_SIZE,8,EGL_ALPHA_SIZE,8,EGL_DEPTH_SIZE,24,EGL_NONE};
EGLConfig Config{};EGLint ConfigCount=0;
if(eglChooseConfig(Display,ConfigAttributes,&Config,1,&ConfigCount)!=EGL_TRUE||ConfigCount==0)
{std::fprintf(stderr,"[OffscreenEGL] no GLES3 pbuffer config (0x%x)\n",eglGetError());eglTerminate(Display);return false;}
const EGLint SurfaceAttributes[]={EGL_WIDTH,Width,EGL_HEIGHT,Height,EGL_NONE};
EGLSurface Surface=eglCreatePbufferSurface(Display,Config,SurfaceAttributes);
const EGLint ContextAttributes[]={EGL_CONTEXT_CLIENT_VERSION,3,EGL_NONE};
EGLContext Context=eglCreateContext(Display,Config,EGL_NO_CONTEXT,ContextAttributes);
if(Surface==EGL_NO_SURFACE||Context==EGL_NO_CONTEXT
||eglMakeCurrent(Display,Surface,Surface,Context)!=EGL_TRUE)
{std::fprintf(stderr,"[OffscreenEGL] context/surface creation failed (0x%x)\n",eglGetError());
if(Context!=EGL_NO_CONTEXT)eglDestroyContext(Display,Context);
if(Surface!=EGL_NO_SURFACE)eglDestroySurface(Display,Surface);
eglTerminate(Display);return false;}
const GLubyte* Renderer=glGetString(GL_RENDERER);
const GLubyte* GlVersion=glGetString(GL_VERSION);
std::printf("[OffscreenEGL] renderer=%s version=%s pbuffer=%dx%d\n",
Renderer?reinterpret_cast<const char*>(Renderer):"unknown",
GlVersion?reinterpret_cast<const char*>(GlVersion):"unknown",Width,Height);
GLuint ColorTexture=0,DepthBuffer=0,Framebuffer=0;
glGenTextures(1,&ColorTexture);glBindTexture(GL_TEXTURE_2D,ColorTexture);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,Width,Height,0,GL_RGBA,GL_UNSIGNED_BYTE,nullptr);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glGenRenderbuffers(1,&DepthBuffer);glBindRenderbuffer(GL_RENDERBUFFER,DepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,Width,Height);
glGenFramebuffers(1,&Framebuffer);glBindFramebuffer(GL_FRAMEBUFFER,Framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,ColorTexture,0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,DepthBuffer);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE)
{std::fprintf(stderr,"[OffscreenGL] framebuffer is incomplete\n");return false;}
constexpr double Pi=3.14159265358979323846;
const double Yaw=Scene.YawDegrees*Pi/180.0,Pitch=Scene.PitchDegrees*Pi/180.0;
const std::array<double,3> Forward={std::sin(Yaw)*std::cos(Pitch),
std::cos(Yaw)*std::cos(Pitch),std::sin(Pitch)};
const std::array<double,3> Right={std::cos(Yaw),-std::sin(Yaw),0.0};
const std::array<double,3> Up={Right[1]*Forward[2]-Right[2]*Forward[1],
Right[2]*Forward[0]-Right[0]*Forward[2],Right[0]*Forward[1]-Right[1]*Forward[0]};
const double TanHalfHorizontal=std::tan(HorizontalFovDegrees*Pi/360.0);
const double Aspect=static_cast<double>(Width)/Height;
const double TanHalfVertical=TanHalfHorizontal/Aspect;
const double Near=0.1,Far=20000.0;
for(FVertex& Vertex:Scene.Vertices)
{
const double DX=Vertex.Position[0]-Scene.CameraMeters[0];
const double DY=Vertex.Position[1]-Scene.CameraMeters[1];
const double DZ=Vertex.Position[2]-Scene.CameraMeters[2];
const float CameraX=static_cast<float>(DX*Right[0]+DY*Right[1]+DZ*Right[2]);
const float CameraY=static_cast<float>(DX*Up[0]+DY*Up[1]+DZ*Up[2]);
const float CameraZ=static_cast<float>(DX*Forward[0]+DY*Forward[1]+DZ*Forward[2]);
Vertex.Position[0]=CameraX;Vertex.Position[1]=CameraY;Vertex.Position[2]=CameraZ;
}
const GLuint Program=MakeProgram();
if(!Program)return false;
GLuint Vao=0,Vbo=0,Ebo=0;
glGenVertexArrays(1,&Vao);glBindVertexArray(Vao);
glGenBuffers(1,&Vbo);glBindBuffer(GL_ARRAY_BUFFER,Vbo);
glBufferData(GL_ARRAY_BUFFER,static_cast<GLsizeiptr>(Scene.Vertices.size()*sizeof(FVertex)),
Scene.Vertices.data(),GL_STATIC_DRAW);
glGenBuffers(1,&Ebo);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,Ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,static_cast<GLsizeiptr>(Scene.Indices.size()*sizeof(std::uint32_t)),
Scene.Indices.data(),GL_STATIC_DRAW);
glEnableVertexAttribArray(0);glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(FVertex),
reinterpret_cast<void*>(offsetof(FVertex,Position)));
glEnableVertexAttribArray(1);glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(FVertex),
reinterpret_cast<void*>(offsetof(FVertex,Normal)));
glEnableVertexAttribArray(2);glVertexAttribPointer(2,1,GL_FLOAT,GL_FALSE,sizeof(FVertex),
reinterpret_cast<void*>(offsetof(FVertex,Height)));
glViewport(0,0,Width,Height);glDisable(GL_CULL_FACE);glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);glClearColor(0.035f,0.055f,0.075f,1.0f);
glClearDepthf(1.0f);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(Program);
glUniform1f(glGetUniformLocation(Program,"uTanHalfHorizontal"),static_cast<float>(TanHalfHorizontal));
glUniform1f(glGetUniformLocation(Program,"uTanHalfVertical"),static_cast<float>(TanHalfVertical));
glUniform1f(glGetUniformLocation(Program,"uNear"),static_cast<float>(Near));
glUniform1f(glGetUniformLocation(Program,"uFar"),static_cast<float>(Far));
glDrawElements(GL_TRIANGLES,static_cast<GLsizei>(Scene.Indices.size()),GL_UNSIGNED_INT,nullptr);
glFinish();
std::vector<std::uint8_t> Pixels(static_cast<std::size_t>(Width)*Height*4);
glReadPixels(0,0,Width,Height,GL_RGBA,GL_UNSIGNED_BYTE,Pixels.data());
const GLenum GlError=glGetError();
const bool PngGood=GlError==GL_NO_ERROR&&WritePng(Output,Width,Height,Pixels);
if(!PngGood)std::fprintf(stderr,"[OffscreenGL] render or PNG write failed (GL=0x%x)\n",GlError);
else
{
std::error_code SizeError;
const auto Bytes=std::filesystem::file_size(Output,SizeError);
std::printf("[OffscreenCapture] triangles=%llu tiles=%u skirts=%llu png_bytes=%llu status=PASS path=%s\n",
static_cast<unsigned long long>(Scene.Triangles),Scene.TileCount,
static_cast<unsigned long long>(Scene.SkirtTriangles),
static_cast<unsigned long long>(SizeError?0:Bytes),Output.string().c_str());
}
glDeleteProgram(Program);glDeleteBuffers(1,&Ebo);glDeleteBuffers(1,&Vbo);
glDeleteVertexArrays(1,&Vao);glDeleteFramebuffers(1,&Framebuffer);
glDeleteRenderbuffers(1,&DepthBuffer);glDeleteTextures(1,&ColorTexture);
eglMakeCurrent(Display,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT);
eglDestroyContext(Display,Context);eglDestroySurface(Display,Surface);eglTerminate(Display);
return PngGood;
}
}
int main(int argc,char** argv)
{
if(argc<3)
{
std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--yaw-deg=N] [--pitch-deg=N]\n",argv[0]);
return 2;
}
int Width=2560,Height=1440;double Fov=90.0;
bool HasYaw=false,HasPitch=false;double Yaw=0.0,Pitch=0.0;
for(int I=3;I<argc;++I)
{
const std::string_view Arg(argv[I]);
if(Arg.starts_with("--size="))
{
const std::string Value(Arg.substr(7));
if(std::sscanf(Value.c_str(),"%dx%d",&Width,&Height)!=2||Width<=0||Height<=0)
{std::fprintf(stderr,"Invalid image size\n");return 2;}
}
else if(Arg.starts_with("--fov-deg="))
{
char* End=nullptr;const std::string Value(Arg.substr(10));Fov=std::strtod(Value.c_str(),&End);
if(End==Value.c_str()||*End!='\0'||Fov<=1.0||Fov>=179.0)
{std::fprintf(stderr,"Invalid horizontal FOV\n");return 2;}
}
else if(Arg.starts_with("--yaw-deg=")||Arg.starts_with("--pitch-deg="))
{
const bool IsYaw=Arg.starts_with("--yaw-deg=");
const std::size_t Prefix=IsYaw?10:12;
const std::string Value(Arg.substr(Prefix));char* End=nullptr;
const double Parsed=std::strtod(Value.c_str(),&End);
if(End==Value.c_str()||*End!='\0'||!std::isfinite(Parsed))
{std::fprintf(stderr,"Invalid camera angle\n");return 2;}
if(IsYaw){Yaw=Parsed;HasYaw=true;}else{Pitch=Parsed;HasPitch=true;}
}
else {std::fprintf(stderr,"Unknown option: %.*s\n",static_cast<int>(Arg.size()),Arg.data());return 2;}
}
FScene Scene;std::string Error;
if(!LoadScene(argv[1],Scene,Error))
{std::fprintf(stderr,"[OffscreenCapture] FAIL: %s\n",Error.c_str());return 2;}
if(HasYaw)Scene.YawDegrees=Yaw;
if(HasPitch)Scene.PitchDegrees=Pitch;
std::printf("[OffscreenScene] voxels_per_meter=%.6f camera_m=(%.3f,%.3f,%.3f) yaw=%.2f pitch=%.2f vertices=%zu triangles=%llu\n",
1000000.0/Scene.VoxelSizeMicrons,Scene.CameraMeters[0],Scene.CameraMeters[1],Scene.CameraMeters[2],
Scene.YawDegrees,Scene.PitchDegrees,Scene.Vertices.size(),
static_cast<unsigned long long>(Scene.Triangles));
return Render(Scene,argv[2],Width,Height,Fov)?0:3;
}
+512
View File
@@ -0,0 +1,512 @@
#pragma once
#include "StreamingWorld.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <optional>
#include <span>
#include <utility>
#include <vector>
namespace StandaloneScreenSpaceGate
{
inline constexpr double OnePixelRadians=1.57079632679489661923/2560.0;
struct FErrorRow
{
int Lod=0;
std::uint64_t Samples=0,Missing=0,Floating=0;
double P50=0.0,P99=0.0,Maximum=0.0;
bool Valid=false;
};
struct FPopRow
{
int CoarseLod=0;
std::uint64_t Samples=0,Cracks=0,Floating=0;
double P50=0.0,P99=0.0,Maximum=0.0;
bool Valid=false;
};
struct FHeightGrid
{
int Side=65;
double MinimumX=0.0,MaximumX=0.0,MinimumY=0.0,MaximumY=0.0;
std::vector<std::vector<double>> Hits;
FHeightGrid()=default;
FHeightGrid(int InSide,double MinX,double MaxX,double MinY,double MaxY)
:Side(InSide),MinimumX(MinX),MaximumX(MaxX),MinimumY(MinY),MaximumY(MaxY),
Hits(static_cast<std::size_t>(InSide)*InSide)
{}
double X(int Ix) const
{return MinimumX+(MaximumX-MinimumX)*Ix/(Side-1);}
double Y(int Iy) const
{return MinimumY+(MaximumY-MinimumY)*Iy/(Side-1);}
void Add(int Ix,int Iy,double Z)
{
auto& Values=Hits[static_cast<std::size_t>(Iy)*Side+Ix];
Values.push_back(Z);
}
const std::vector<double>& At(int Ix,int Iy) const
{return Hits[static_cast<std::size_t>(Iy)*Side+Ix];}
};
inline double Percentile(std::vector<double>& Values,double P)
{
if(Values.empty())return 0.0;
std::sort(Values.begin(),Values.end());
const std::size_t Index=std::min(Values.size()-1,
static_cast<std::size_t>(std::ceil(P*Values.size())-1));
return Values[Index];
}
inline double TileAabbDistanceMeters(const FVoxelTileKey& Key,
const FVector& CameraVoxels,double VoxelMeters)
{
const double Extent=static_cast<double>(Key.ExtentVoxels());
const double Min[3]={static_cast<double>(Key.OriginVoxels().X),
static_cast<double>(Key.OriginVoxels().Y),static_cast<double>(Key.OriginVoxels().Z)};
const double Cam[3]={CameraVoxels.X,CameraVoxels.Y,CameraVoxels.Z};
double Squared=0.0;
for(int Axis=0;Axis<3;++Axis)
{
const double Delta=Cam[Axis]<Min[Axis]?Min[Axis]-Cam[Axis]
:Cam[Axis]>Min[Axis]+Extent?Cam[Axis]-(Min[Axis]+Extent):0.0;
Squared+=Delta*Delta;
}
return std::sqrt(Squared)*VoxelMeters;
}
inline bool TileHasNativeSurface(const FVoxelTileKey& Key,
const VoxelForgeCore::WorldAssemblyManifest& Assembly,
double VoxelMeters)
{
const double Extent=static_cast<double>(Key.ExtentVoxels());
const double X=(static_cast<double>(Key.OriginVoxels().X)+Extent*0.5)*256.0;
const double Y=(static_cast<double>(Key.OriginVoxels().Y)+Extent*0.5)*256.0;
const double MinZ=static_cast<double>(Key.OriginVoxels().Z);
const double MaxZ=MinZ+Extent;
for(const auto& Plan:Assembly.plan.strates)
{
VoxelForgeCore::Heightfield2D Field(Assembly.recipe,Plan);
if(!Field.isValid())continue;
const auto Column=Field.point(static_cast<std::int64_t>(std::llround(X)),
static_cast<std::int64_t>(std::llround(Y)),0);
const double Ground=static_cast<double>(Column.groundHeightSubvoxels)/256.0;
const double Cap=static_cast<double>(Column.capHeightSubvoxels)/256.0;
const double Margin=std::max(2.0,0.25/VoxelMeters);
if(Ground<Cap&&((Ground>=MinZ-Margin&&Ground<=MaxZ+Margin)
||(Cap>=MinZ-Margin&&Cap<=MaxZ+Margin)))return true;
}
return false;
}
inline FHeightGrid Rasterize(std::span<const FStandaloneCpuTile* const> Tiles,
const FVoxelTileKey& Patch,double VoxelMeters,int Side=65)
{
const double Extent=static_cast<double>(Patch.ExtentVoxels())*VoxelMeters;
const double MinX=static_cast<double>(Patch.OriginVoxels().X)*VoxelMeters;
const double MinY=static_cast<double>(Patch.OriginVoxels().Y)*VoxelMeters;
FHeightGrid Grid(Side,MinX,MinX+Extent,MinY,MinY+Extent);
for(const FStandaloneCpuTile* Tile:Tiles)
{
if(!Tile||Tile->Indices.size()<3)continue;
const std::size_t TriangleCount=Tile->Indices.size()/3;
for(std::size_t Triangle=0;Triangle<TriangleCount;++Triangle)
{
if(Triangle<Tile->TriangleSkirtFaceMasks.size()
&&Tile->TriangleSkirtFaceMasks[Triangle]!=0)continue;
const std::uint32_t I0=Tile->Indices[Triangle*3];
const std::uint32_t I1=Tile->Indices[Triangle*3+1];
const std::uint32_t I2=Tile->Indices[Triangle*3+2];
if(I0>=Tile->Vertices.size()||I1>=Tile->Vertices.size()||I2>=Tile->Vertices.size())continue;
const auto& A=Tile->Vertices[I0].Position;
const auto& B=Tile->Vertices[I1].Position;
const auto& C=Tile->Vertices[I2].Position;
const double Denominator=(B[1]-C[1])*(A[0]-C[0])+(C[0]-B[0])*(A[1]-C[1]);
if(std::abs(Denominator)<1e-10)continue;
const double MinTriX=std::min({A[0],B[0],C[0]}),MaxTriX=std::max({A[0],B[0],C[0]});
const double MinTriY=std::min({A[1],B[1],C[1]}),MaxTriY=std::max({A[1],B[1],C[1]});
const double StepX=Extent/(Side-1),StepY=Extent/(Side-1);
const int Ix0=std::clamp(static_cast<int>(std::ceil((MinTriX-MinX)/StepX)),0,Side-1);
const int Ix1=std::clamp(static_cast<int>(std::floor((MaxTriX-MinX)/StepX)),0,Side-1);
const int Iy0=std::clamp(static_cast<int>(std::ceil((MinTriY-MinY)/StepY)),0,Side-1);
const int Iy1=std::clamp(static_cast<int>(std::floor((MaxTriY-MinY)/StepY)),0,Side-1);
for(int Iy=Iy0;Iy<=Iy1;++Iy)
for(int Ix=Ix0;Ix<=Ix1;++Ix)
{
const double X=Grid.X(Ix),Y=Grid.Y(Iy);
const double W0=((B[1]-C[1])*(X-C[0])+(C[0]-B[0])*(Y-C[1]))/Denominator;
const double W1=((C[1]-A[1])*(X-C[0])+(A[0]-C[0])*(Y-C[1]))/Denominator;
const double W2=1.0-W0-W1;
if(W0<-1e-6||W1<-1e-6||W2<-1e-6)continue;
Grid.Add(Ix,Iy,W0*A[2]+W1*B[2]+W2*C[2]);
}
}
}
for(auto& Values:Grid.Hits)
{
std::sort(Values.begin(),Values.end());
Values.erase(std::unique(Values.begin(),Values.end(),[](double A,double B)
{return std::abs(A-B)<0.02;}),Values.end());
}
return Grid;
}
inline std::vector<double> ExactHeightRoots(const FHeightGrid& Grid,int Ix,int Iy,
const FVoxelTileKey& Patch,double VoxelMeters,
const VoxelForgeCore::WorldAssemblyManifest& Assembly)
{
std::vector<double> Roots;
const double XSubvoxels=Grid.X(Ix)/VoxelMeters*256.0;
const double YSubvoxels=Grid.Y(Iy)/VoxelMeters*256.0;
const double MinZ=static_cast<double>(Patch.OriginVoxels().Z);
const double MaxZ=MinZ+Patch.ExtentVoxels();
for(const auto& Plan:Assembly.plan.strates)
{
VoxelForgeCore::Heightfield2D Field(Assembly.recipe,Plan);
if(!Field.isValid())continue;
const auto Column=Field.point(static_cast<std::int64_t>(std::llround(XSubvoxels)),
static_cast<std::int64_t>(std::llround(YSubvoxels)),0);
if(Column.groundHeightSubvoxels>=Column.capHeightSubvoxels)continue;
const double Ground=static_cast<double>(Column.groundHeightSubvoxels)/(256.0)*VoxelMeters;
const double Cap=static_cast<double>(Column.capHeightSubvoxels)/(256.0)*VoxelMeters;
const double PlanMinZ=static_cast<double>(Plan.bottomChunkZ)*32.0*VoxelMeters;
const double PlanMaxZ=static_cast<double>(Plan.topChunkZ+1)*32.0*VoxelMeters;
if(Ground>=MinZ*VoxelMeters-0.25*VoxelMeters
&&Ground<=MaxZ*VoxelMeters+0.25*VoxelMeters
&&Ground>=PlanMinZ-0.25*VoxelMeters&&Ground<=PlanMaxZ+0.25*VoxelMeters)
Roots.push_back(Ground);
if(Cap>=MinZ*VoxelMeters-0.25*VoxelMeters
&&Cap<=MaxZ*VoxelMeters+0.25*VoxelMeters
&&Cap>=PlanMinZ-0.25*VoxelMeters&&Cap<=PlanMaxZ+0.25*VoxelMeters)
Roots.push_back(Cap);
}
std::sort(Roots.begin(),Roots.end());
Roots.erase(std::unique(Roots.begin(),Roots.end(),[](double A,double B)
{return std::abs(A-B)<0.01;}),Roots.end());
return Roots;
}
inline bool MatchNearest(const std::vector<double>& Hits,const std::vector<bool>& Used,
double Root,std::size_t& OutIndex,double& OutError)
{
double Best=std::numeric_limits<double>::infinity();std::size_t BestIndex=Hits.size();
for(std::size_t I=0;I<Hits.size();++I)
if(I>=Used.size()||!Used[I])
{
const double Error=std::abs(Hits[I]-Root);
if(Error<Best){Best=Error;BestIndex=I;}
}
if(BestIndex==Hits.size())return false;
OutIndex=BestIndex;OutError=Best;return true;
}
inline FErrorRow CompareToExact(const FHeightGrid& MeshGrid,const FVoxelTileKey& Patch,
double VoxelMeters,double PixelBudgetMeters,
const VoxelForgeCore::WorldAssemblyManifest& Assembly)
{
FErrorRow Row;Row.Lod=Patch.Level;Row.Valid=true;
std::vector<double> Errors;
for(int Iy=0;Iy<MeshGrid.Side;++Iy)
for(int Ix=0;Ix<MeshGrid.Side;++Ix)
{
const auto Roots=ExactHeightRoots(MeshGrid,Ix,Iy,Patch,VoxelMeters,Assembly);
if(Roots.empty()&&MeshGrid.At(Ix,Iy).empty())continue;
std::vector<bool> Used(MeshGrid.At(Ix,Iy).size(),false);
for(double Root:Roots)
{
std::size_t HitIndex=0;double ErrorMeters=0.0;
if(!MatchNearest(MeshGrid.At(Ix,Iy),Used,Root,HitIndex,ErrorMeters))
{
++Row.Missing;
Errors.push_back(2.0);
continue;
}
Used[HitIndex]=true;
Errors.push_back(ErrorMeters/PixelBudgetMeters);
++Row.Samples;
}
// Heightfield2D declares ground and cap roots only. Other mesh intersections may
// be valid tunnel geometry; the exact-mesh comparison checks extra pieces.
}
Row.P50=Percentile(Errors,0.50);Row.P99=Percentile(Errors,0.99);
Row.Maximum=Errors.empty()?0.0:*std::max_element(Errors.begin(),Errors.end());
Row.Samples=Errors.size();
return Row;
}
inline FErrorRow CompareToReference(const FHeightGrid& MeshGrid,
const FHeightGrid& ReferenceGrid,int Lod,double PixelBudgetMeters)
{
FErrorRow Row;Row.Lod=Lod;Row.Valid=true;
std::vector<double> Errors;
for(int Iy=0;Iy<ReferenceGrid.Side;++Iy)
for(int Ix=0;Ix<ReferenceGrid.Side;++Ix)
{
const auto& Reference=ReferenceGrid.At(Ix,Iy);
const auto& Mesh=MeshGrid.At(Ix,Iy);
if(Reference.empty()&&Mesh.empty())continue;
std::vector<bool> Used(Mesh.size(),false);
for(double ReferenceZ:Reference)
{
std::size_t HitIndex=0;double ErrorMeters=0.0;
if(!MatchNearest(Mesh,Used,ReferenceZ,HitIndex,ErrorMeters))
{
++Row.Missing;Errors.push_back(2.0);continue;
}
Used[HitIndex]=true;
Errors.push_back(ErrorMeters/PixelBudgetMeters);
}
for(std::size_t I=0;I<Mesh.size();++I)
if(!Used[I]){++Row.Floating;Errors.push_back(2.0);}
}
Row.P50=Percentile(Errors,0.50);Row.P99=Percentile(Errors,0.99);
Row.Maximum=Errors.empty()?0.0:*std::max_element(Errors.begin(),Errors.end());
Row.Samples=Errors.size();
return Row;
}
inline FPopRow ComparePop(const FHeightGrid& Coarse,const FHeightGrid& Fine,
const FVoxelTileKey& Patch,double VoxelMeters,double PixelBudgetMeters,
const VoxelForgeCore::WorldAssemblyManifest& Assembly)
{
FPopRow Row;Row.CoarseLod=Patch.Level;Row.Valid=true;
std::vector<double> Errors;
for(int Iy=0;Iy<Coarse.Side;++Iy)
for(int Ix=0;Ix<Coarse.Side;++Ix)
{
const auto& CoarseHits=Coarse.At(Ix,Iy);
const auto& FineHits=Fine.At(Ix,Iy);
const auto Roots=ExactHeightRoots(Coarse,Ix,Iy,Patch,VoxelMeters,Assembly);
if(Roots.empty()&&CoarseHits.empty()&&FineHits.empty())continue;
std::vector<bool> CoarseUsed(CoarseHits.size(),false);
std::vector<bool> FineUsed(FineHits.size(),false);
for(double Root:Roots)
{
std::size_t CoarseIndex=0,FineIndex=0;
double CoarseError=0.0,FineError=0.0;
if(!MatchNearest(CoarseHits,CoarseUsed,Root,CoarseIndex,CoarseError)
||!MatchNearest(FineHits,FineUsed,Root,FineIndex,FineError))
{
++Row.Cracks;Errors.push_back(2.0);continue;
}
CoarseUsed[CoarseIndex]=true;
FineUsed[FineIndex]=true;
Errors.push_back(std::abs(CoarseHits[CoarseIndex]-FineHits[FineIndex])
/PixelBudgetMeters);
++Row.Samples;
}
}
Row.P50=Percentile(Errors,0.50);Row.P99=Percentile(Errors,0.99);
Row.Maximum=Errors.empty()?0.0:*std::max_element(Errors.begin(),Errors.end());
Row.Samples=Errors.size();
return Row;
}
inline std::array<double,9> ClosestDisplayedDistancesMeters(
const FStandaloneOwnerWorld& World,const FVector& CameraVoxels,
std::uint32_t VoxelSizeMicrons)
{
const double VoxelMeters=static_cast<double>(VoxelSizeMicrons)/1000000.0;
std::array<double,9> Minimums{};
Minimums.fill(std::numeric_limits<double>::infinity());
for(int Lod=0;Lod<=8;++Lod)
{
const int PhaseCount=1<<Lod;
for(int Phase=0;Phase<PhaseCount;++Phase)
{
FVector Probe=CameraVoxels;
Probe.X=static_cast<float>(Phase*32.0+32.0-1.0/256.0);
const FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,Probe);
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(Tile.Level!=Lod)continue;
Minimums[Lod]=std::min(Minimums[Lod],
TileAabbDistanceMeters(Tile,Probe,VoxelMeters));
}
}
}
for(double& Distance:Minimums)
if(!std::isfinite(Distance))Distance=0.0;
return Minimums;
}
inline std::array<double,9> ClipmapClosestDisplayedDistancesMeters(
const FStandaloneOwnerWorld& World,std::uint32_t VoxelSizeMicrons)
{
const double VoxelMeters=static_cast<double>(VoxelSizeMicrons)/1000000.0;
std::array<double,9> Distances{};
for(int Lod=1;Lod<=8;++Lod)
Distances[Lod]=static_cast<double>(World.ClipRadius)
*static_cast<double>(CHUNK_SIZE)*(1ull<<(Lod-1))*VoxelMeters;
return Distances;
}
inline bool Run(const std::array<std::optional<FStandaloneCpuTile>,9>& SampleTiles,
FStandaloneStreamingGenerator& Streamer,
const VoxelForgeCore::WorldAssemblyManifest& Assembly,
const std::array<double,9>& Distances,std::uint32_t VoxelSizeMicrons,int MaxLod,
const std::array<std::int64_t,9>& PixelBudgetsSubvoxels)
{
const double VoxelMeters=static_cast<double>(VoxelSizeMicrons)/1000000.0;
std::array<double,9> Budgets{};
std::array<FErrorRow,9> ErrorRows{};
std::array<FPopRow,9> PopRows{};
bool GatePass=true;
std::printf("[ScreenSpaceGate] angular_pixel=%.9f rad (90deg/2560) lod>=3_limit=1.0px sampling=65x65 skirts=excluded metric=vertical_height_error field_reference=direct-Heightfield2D-roots\n",
OnePixelRadians);
for(int Lod=0;Lod<=MaxLod&&Lod<9;++Lod)
{
Budgets[Lod]=Distances[Lod]*OnePixelRadians;
std::printf("[ScreenSpaceDistance] lod=%d closest_m=%.3f pixel_budget_m=%.6f pixel_budget_cm=%.3f pixel_budget_subvoxels=%lld rule=%s\n",
Lod,Distances[Lod],Budgets[Lod],Budgets[Lod]*100.0,
static_cast<long long>(PixelBudgetsSubvoxels[Lod]),Lod<3?"exact-2cm":"1px");
}
VoxelForgeCore::Heightfield2D::resetThreadColumnCacheStats(false,true,0);
for(int Lod=3;Lod<=MaxLod&&Lod<9;++Lod)
{
if(!SampleTiles[Lod]||SampleTiles[Lod]->Vertices.empty())
{
std::printf("[ScreenSpaceGateLOD] lod=%d status=NO_SURFACE_TILE\n",Lod);
GatePass=false;continue;
}
const FStandaloneCpuTile& CoarseTile=*SampleTiles[Lod];
const FStandaloneCpuTile* CoarsePtr=&CoarseTile;
const std::span<const FStandaloneCpuTile* const> CoarseSpan(&CoarsePtr,1);
const FHeightGrid CoarseGrid=Rasterize(CoarseSpan,CoarseTile.Key,VoxelMeters);
const FStandaloneCpuTile ExactTile=Streamer.GenerateDiagnostic(
CoarseTile.Key,0,1,true);
const FStandaloneCpuTile* ExactPointer=&ExactTile;
const std::span<const FStandaloneCpuTile* const> ExactSpan(&ExactPointer,1);
const FHeightGrid ExactGrid=Rasterize(ExactSpan,ExactTile.Key,VoxelMeters);
ErrorRows[Lod]=CompareToReference(CoarseGrid,ExactGrid,Lod,Budgets[Lod]);
const FErrorRow& Error=ErrorRows[Lod];
const bool LodPass=Error.Valid&&Error.Missing==0&&Error.Floating==0
&&Error.Samples>=16&&Error.Maximum<=1.0;
GatePass=GatePass&&LodPass;
std::printf("[ScreenSpaceGateLOD] lod=%d key=(%d,%d,%d) samples=%llu p50_px=%.4f p99_px=%.4f max_px=%.4f missing=%llu floating=%llu status=%s\n",
Lod,CoarseTile.Key.Coord.X,CoarseTile.Key.Coord.Y,CoarseTile.Key.Coord.Z,
static_cast<unsigned long long>(Error.Samples),Error.P50,Error.P99,Error.Maximum,
static_cast<unsigned long long>(Error.Missing),static_cast<unsigned long long>(Error.Floating),
LodPass?"PASS":"REJECT");
const FErrorRow FieldError=CompareToExact(CoarseGrid,CoarseTile.Key,VoxelMeters,
Budgets[Lod],Assembly);
const bool FieldPass=FieldError.Valid&&FieldError.Missing==0&&FieldError.Floating==0
&&FieldError.Samples>=16&&FieldError.Maximum<=1.0;
GatePass=GatePass&&FieldPass;
std::printf("[ScreenSpaceGateFieldLOD] lod=%d samples=%llu p50_px=%.4f p99_px=%.4f max_px=%.4f missing=%llu floating=%llu status=%s\n",
Lod,static_cast<unsigned long long>(FieldError.Samples),FieldError.P50,
FieldError.P99,FieldError.Maximum,static_cast<unsigned long long>(FieldError.Missing),
static_cast<unsigned long long>(FieldError.Floating),FieldPass?"PASS":"REJECT");
bool FaultControlsPass=true;
const FHeightGrid MissingGrid(ExactGrid.Side,ExactGrid.MinimumX,ExactGrid.MaximumX,
ExactGrid.MinimumY,ExactGrid.MaximumY);
const FErrorRow MissingError=CompareToReference(MissingGrid,ExactGrid,Lod,
Budgets[Lod]);
const bool MissingRejected=MissingError.Missing>0&&MissingError.Maximum>1.0;
FaultControlsPass=FaultControlsPass&&MissingRejected;
std::printf("[ScreenSpaceFaultInjection] lod=%d case=missing-displayed-surface missing=%llu status=%s\n",
Lod,static_cast<unsigned long long>(MissingError.Missing),
MissingRejected?"REJECTED_AS_REQUIRED":"GATE_FALSE_NEGATIVE");
FStandaloneCpuTile FloatingTile=CoarseTile;
const std::uint32_t FloatingVertexBase=static_cast<std::uint32_t>(FloatingTile.Vertices.size());
for(FStandaloneCpuVertex Vertex:CoarseTile.Vertices)
{
Vertex.Position[2]+=2.0f;
FloatingTile.Vertices.push_back(Vertex);
}
for(const std::uint32_t Index:CoarseTile.Indices)
FloatingTile.Indices.push_back(FloatingVertexBase+Index);
FloatingTile.TriangleSkirtFaceMasks.insert(FloatingTile.TriangleSkirtFaceMasks.end(),
CoarseTile.TriangleSkirtFaceMasks.begin(),CoarseTile.TriangleSkirtFaceMasks.end());
const FStandaloneCpuTile* FloatingPointer=&FloatingTile;
const std::span<const FStandaloneCpuTile* const> FloatingSpan(&FloatingPointer,1);
const FHeightGrid FloatingGrid=Rasterize(FloatingSpan,CoarseTile.Key,VoxelMeters);
const FErrorRow FloatingError=CompareToReference(FloatingGrid,ExactGrid,Lod,
Budgets[Lod]);
const bool FloatingRejected=FloatingError.Floating>0||FloatingError.Maximum>1.0;
FaultControlsPass=FaultControlsPass&&FloatingRejected;
std::printf("[ScreenSpaceFaultInjection] lod=%d case=2m-floating-surface floating=%llu max_px=%.4f status=%s\n",
Lod,static_cast<unsigned long long>(FloatingError.Floating),FloatingError.Maximum,
FloatingRejected?"REJECTED_AS_REQUIRED":"GATE_FALSE_NEGATIVE");
std::vector<FStandaloneCpuTile> FineTiles;
FineTiles.reserve(8);
for(int Dz=0;Dz<=1;++Dz)
for(int Dy=0;Dy<=1;++Dy)
for(int Dx=0;Dx<=1;++Dx)
{
const FVoxelTileKey FineKey(FIntVector(2*CoarseTile.Key.Coord.X+Dx,
2*CoarseTile.Key.Coord.Y+Dy,2*CoarseTile.Key.Coord.Z+Dz),Lod-1);
FStandaloneCpuTile FineTile=Streamer.GenerateDiagnostic(FineKey);
if(!FineTile.Vertices.empty())FineTiles.push_back(std::move(FineTile));
}
std::vector<const FStandaloneCpuTile*> FinePointers;
FinePointers.reserve(FineTiles.size());
for(const auto& Tile:FineTiles)FinePointers.push_back(&Tile);
const auto FineSpan=std::span<const FStandaloneCpuTile* const>(
FinePointers.data(),FinePointers.size());
const FHeightGrid FineGrid=Rasterize(FineSpan,CoarseTile.Key,VoxelMeters);
PopRows[Lod]=ComparePop(CoarseGrid,FineGrid,CoarseTile.Key,VoxelMeters,
Budgets[Lod],Assembly);
const FPopRow& Pop=PopRows[Lod];
const bool PopPass=Pop.Valid&&Pop.Cracks==0&&Pop.Floating==0&&Pop.Maximum<=1.0;
GatePass=GatePass&&PopPass;
std::printf("[ScreenSpaceSwap] lod=%d_to_%d samples=%llu p50_px=%.4f p99_px=%.4f max_px=%.4f cracks=%llu floating=%llu status=%s\n",
Lod,Lod-1,static_cast<unsigned long long>(Pop.Samples),
Pop.P50,Pop.P99,Pop.Maximum,static_cast<unsigned long long>(Pop.Cracks),
static_cast<unsigned long long>(Pop.Floating),
PopPass?"PASS":"REJECT");
const FHeightGrid MissingFineGrid(CoarseGrid.Side,CoarseGrid.MinimumX,
CoarseGrid.MaximumX,CoarseGrid.MinimumY,CoarseGrid.MaximumY);
const FPopRow MissingFineError=ComparePop(CoarseGrid,MissingFineGrid,
CoarseTile.Key,VoxelMeters,Budgets[Lod],Assembly);
const bool CrackRejected=MissingFineError.Cracks>0&&MissingFineError.Maximum>1.0;
FaultControlsPass=FaultControlsPass&&CrackRejected;
GatePass=GatePass&&FaultControlsPass;
std::printf("[ScreenSpaceFaultInjection] lod=%d case=missing-fine-ring-surface cracks=%llu max_px=%.4f status=%s\n",
Lod,static_cast<unsigned long long>(MissingFineError.Cracks),
MissingFineError.Maximum,CrackRejected?"REJECTED_AS_REQUIRED":"GATE_FALSE_NEGATIVE");
bool NegativeControlsPass=true;
const auto CheckNegative=[&](const char* Name,std::uint32_t Drop,std::uint32_t Stride)
{
FStandaloneCpuTile Bad=Streamer.GenerateDiagnostic(
CoarseTile.Key,Drop,Stride,true);
const FStandaloneCpuTile* BadPointer=&Bad;
const std::span<const FStandaloneCpuTile* const> BadSpan(&BadPointer,1);
const FHeightGrid BadGrid=Rasterize(BadSpan,Bad.Key,VoxelMeters);
const FErrorRow BadError=CompareToReference(BadGrid,ExactGrid,Lod,
Budgets[Lod]);
const bool Rejected=BadError.Missing>0||BadError.Floating>0
||BadError.Samples<16||BadError.Maximum>1.0;
NegativeControlsPass=NegativeControlsPass&&Rejected;
std::printf("[ScreenSpaceNegative] lod=%d case=%s p50_px=%.4f p99_px=%.4f max_px=%.4f missing=%llu floating=%llu status=%s\n",
Lod,Name,BadError.P50,BadError.P99,BadError.Maximum,
static_cast<unsigned long long>(BadError.Missing),
static_cast<unsigned long long>(BadError.Floating),
Rejected?"REJECTED_AS_REQUIRED":"GATE_FALSE_NEGATIVE");
};
CheckNegative("s13-global-octave-drop",1,1);
CheckNegative("stride-2-column-interpolation",0,2);
GatePass=GatePass&&NegativeControlsPass;
}
std::printf("[ScreenSpaceGateResult] status=%s\n",GatePass?"PASS":"REJECT");
return GatePass;
}
}
+23 -3
View File
@@ -37,6 +37,8 @@ namespace
bool ProfileColumnOverlap=false;
bool ForceGenerate=false;
bool MeshCoverage=false;
bool ScreenSpaceGate=false;
bool VisualDetailCutoff=false;
bool HasSeedOverride=false;
int SeedOverride=0;
bool HasRenderDistanceOverride=false;
@@ -48,6 +50,9 @@ namespace
bool HasCamera=false;
bool AutoSurfaceCamera=false;
FVector CameraMeters=FVector::ZeroVector;
float CameraYawDegrees=0.0f;
float CameraPitchDegrees=0.0f;
std::filesystem::path MeshExportPath;
};
bool ParseInteger(std::string_view text,int& output)
@@ -61,13 +66,15 @@ namespace
return true;
}
bool ParseCamera(std::string_view text,FVector& meters)
bool ParseCamera(std::string_view text,FVector& meters,float& yawDegrees,float& pitchDegrees)
{
const std::string values(text);
float x=0.0f,y=0.0f,z=0.0f,yaw=0.0f,pitch=0.0f;
if(std::sscanf(values.c_str(),"%f,%f,%f,%f,%f",&x,&y,&z,&yaw,&pitch)!=5)
return false;
meters={x,y,z};
yawDegrees=yaw;
pitchDegrees=pitch;
return true;
}
@@ -85,10 +92,13 @@ namespace
std::printf("Usage: %s [owner_world.json] --world-assembler-prototype --stream-benchmark --stream-pipeline [options]\n"
" --workers=N --clip-radius=N --max-clip-level=N --max-level=N\n"
" --camera=X,Y,Z,YAW,PITCH (position in metres) --stream-hash\n"
" --mesh-export=FILE (write the exact generated tile meshes for offline rendering)\n"
" --profile-column-overlap --far-horizon-lod8-step=N --force-generate\n"
" --seed=N --recipe=surface-world|floating-islands\n"
" --auto-surface-camera (place the 27-tile cube on this seed's surface)\n"
" --mesh-coverage (report non-empty tiles and indexed triangles)\n"
" --screen-space-gate (measure display error and historical negative controls)\n"
" --visual-detail-cutoff (enable the declared far visual octave cutoff)\n"
" --render-distance-chunks=N (0 disables the extra far ring)\n"
" --tls-probe=N (Linux worker TLS/stack measurement; N=0..12)\n"
" --tls-probe-touch=none|surface-world|floating-islands (first-use probe)\n"
@@ -103,6 +113,8 @@ namespace
else if(arg=="--profile-column-overlap")options.ProfileColumnOverlap=true;
else if(arg=="--force-generate")options.ForceGenerate=true;
else if(arg=="--mesh-coverage")options.MeshCoverage=true;
else if(arg=="--screen-space-gate")options.ScreenSpaceGate=true;
else if(arg=="--visual-detail-cutoff")options.VisualDetailCutoff=true;
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
else if(arg.starts_with("--recipe="))
{
@@ -135,10 +147,17 @@ namespace
}
else if(arg.starts_with("--camera="))
{
if(!ParseCamera(arg.substr(9),options.CameraMeters))
if(!ParseCamera(arg.substr(9),options.CameraMeters,
options.CameraYawDegrees,options.CameraPitchDegrees))
{std::fprintf(stderr,"Invalid --camera value: %.*s\n",static_cast<int>(arg.size()),arg.data());return false;}
options.HasCamera=true;
}
else if(arg.starts_with("--mesh-export="))
{
options.MeshExportPath=std::filesystem::path(arg.substr(14));
if(options.MeshExportPath.empty())
{std::fprintf(stderr,"--mesh-export needs a file path\n");return false;}
}
else if(arg.starts_with("--workers="))
{if(!readInt("--workers=",options.WorkerCount))return false;}
else if(arg.starts_with("--clip-radius="))
@@ -297,5 +316,6 @@ int main(int argc,char** argv)
cameraVoxels,options.WorkerCount,options.MaxLevel,VoxelForgeCore::DetailVariant::coherent,
scheduler,options.StreamHash,false,false,false,false,coldStart,
options.ProfileColumnOverlap,options.FarHorizonLOD8InteriorStepVoxels,
options.MeshCoverage);
options.MeshCoverage,options.MeshExportPath,options.CameraYawDegrees,
options.CameraPitchDegrees,options.ScreenSpaceGate,options.VisualDetailCutoff);
}
+296 -2
View File
@@ -2,6 +2,7 @@
#include "OwnerWorldLoader.h"
#include "StreamingWorld.h"
#include "LinuxScreenSpaceGate.h"
#include <algorithm>
#include <array>
@@ -9,6 +10,8 @@
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <limits>
#include <thread>
#include <unordered_map>
@@ -17,6 +20,76 @@
namespace StandaloneStreamBenchmark
{
struct FSceneExportWriter
{
std::ofstream File;
bool bGood=true;
std::uint32_t TileCount=0;
template<typename T> void Write(const T& Value)
{
File.write(reinterpret_cast<const char*>(&Value),sizeof(Value));
bGood=bGood&&static_cast<bool>(File);
}
bool Open(const std::filesystem::path& Path,std::uint32_t VoxelSizeMicrons,
const FVector& CameraVoxels,float YawDegrees,float PitchDegrees,
std::uint32_t ExpectedTiles)
{
std::error_code Error;
if(!Path.parent_path().empty())
std::filesystem::create_directories(Path.parent_path(),Error);
if(Error)return false;
File.open(Path,std::ios::binary|std::ios::trunc);
if(!File)return false;
constexpr char Magic[8]={'V','F','M','S','H','0','0','1'};
File.write(Magic,sizeof(Magic));
const std::uint32_t Version=1;
Write(Version);Write(VoxelSizeMicrons);Write(ExpectedTiles);
const double MicronsToMeters=static_cast<double>(VoxelSizeMicrons)/1000000.0;
const double Camera[3]={CameraVoxels.X*MicronsToMeters,
CameraVoxels.Y*MicronsToMeters,CameraVoxels.Z*MicronsToMeters};
for(const double Value:Camera)Write(Value);
const double Yaw=YawDegrees,Pitch=PitchDegrees;
Write(Yaw);Write(Pitch);
return bGood;
}
void Add(const FStandaloneCpuTile& Tile)
{
const std::int32_t Key[4]={Tile.Key.Coord.X,Tile.Key.Coord.Y,
Tile.Key.Coord.Z,Tile.Key.Level};
for(const auto Value:Key)Write(Value);
const std::uint32_t SurfaceVertexCount=Tile.SurfaceVertexCount;
const std::uint32_t SkirtTriangleCount=Tile.SkirtTriangleCount;
const std::uint32_t VertexCount=static_cast<std::uint32_t>(Tile.Vertices.size());
const std::uint32_t IndexCount=static_cast<std::uint32_t>(Tile.Indices.size());
const std::uint32_t MaskCount=static_cast<std::uint32_t>(Tile.TriangleSkirtFaceMasks.size());
Write(SurfaceVertexCount);Write(SkirtTriangleCount);
Write(VertexCount);Write(IndexCount);Write(MaskCount);
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
for(const float Value:Vertex.Position)Write(Value);
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
for(const float Value:Vertex.Normal)Write(Value);
if(IndexCount)
File.write(reinterpret_cast<const char*>(Tile.Indices.data()),
static_cast<std::streamsize>(sizeof(std::uint32_t)*Tile.Indices.size()));
if(MaskCount)
File.write(reinterpret_cast<const char*>(Tile.TriangleSkirtFaceMasks.data()),
static_cast<std::streamsize>(Tile.TriangleSkirtFaceMasks.size()));
bGood=bGood&&static_cast<bool>(File);
++TileCount;
}
bool Close(std::uint32_t ExpectedTiles)
{
File.flush();
const bool bComplete=bGood&&static_cast<bool>(File)&&TileCount==ExpectedTiles;
File.close();
return bComplete;
}
};
inline void HashWord(uint64& Hash,uint64 Word,int32 Bytes=8)
{
for(int32 I=0;I<Bytes;++I)
@@ -62,10 +135,92 @@ namespace StandaloneStreamBenchmark
VoxelForgeCore::DetailVariant DetailVariant,const VoxelForgeCore::JobScheduler& Scheduler,
bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,bool bSkipUV,bool bSkipColors,
std::chrono::steady_clock::time_point ColdStart,bool bProfileColumnOverlap,
int32 FarHorizonLOD8InteriorStepVoxels,bool bReportMeshCoverage=false)
int32 FarHorizonLOD8InteriorStepVoxels,bool bReportMeshCoverage=false,
const std::filesystem::path& MeshExportPath={},float CameraYawDegrees=0.0f,
float CameraPitchDegrees=0.0f,bool bScreenSpaceGate=false,
bool bApplyVisualDetailCutoff=false)
{
using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld;
const VoxelForgeCore::WorldAssemblyManifest* Assembly=CoreSnapshot.worldAssembly();
std::array<double,9> ClosestDisplayDistances{};
std::array<std::int64_t,9> PixelBudgetsSubvoxels{};
std::array<std::int64_t,9> AppliedPixelBudgetsSubvoxels{};
if(bScreenSpaceGate||bApplyVisualDetailCutoff)
{
ClosestDisplayDistances=bScreenSpaceGate
?StandaloneScreenSpaceGate::ClosestDisplayedDistancesMeters(
World,CameraPositionVoxels,World.CoreVoxelSizeMicrons)
:StandaloneScreenSpaceGate::ClipmapClosestDisplayedDistancesMeters(
World,World.CoreVoxelSizeMicrons);
const double VoxelMeters=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
for(int32 Lod=3;Lod<=World.MaxClipLevel&&Lod<9;++Lod)
PixelBudgetsSubvoxels[static_cast<std::size_t>(Lod)]=static_cast<std::int64_t>(std::floor(
ClosestDisplayDistances[static_cast<std::size_t>(Lod)]
*StandaloneScreenSpaceGate::OnePixelRadians/VoxelMeters
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
}
AppliedPixelBudgetsSubvoxels=PixelBudgetsSubvoxels;
if(Assembly&&(bScreenSpaceGate||bApplyVisualDetailCutoff))
{
for(int32 Lod=3;Lod<=World.MaxClipLevel&&Lod<9;++Lod)
{
const std::int32_t Cells=FMath::Max(1,World.CoarseTileCells);
const std::int32_t Step=FMath::Max(1,(CHUNK_SIZE<<Lod)/Cells);
VoxelForgeCore::VisualDetailCutoffV1 Probe;
Probe.pixelBudgetSubvoxels=PixelBudgetsSubvoxels[static_cast<std::size_t>(Lod)];
Probe.sampleStepSubvoxels=static_cast<std::int64_t>(Step)
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
std::uint64_t TermCount=0,EligibleTermCount=0,PotentialSkippedOctaves=0;
for(const auto& Plan:Assembly->plan.strates)
{
const VoxelForgeCore::Heightfield2D Field(Assembly->recipe,Plan);
for(const auto& Term:Field.visualDetailContract().terms)
{
++TermCount;
const auto Result=VoxelForgeCore::FindVisualDetailTailCutoffV1(Term,Probe);
if(Result.firstSkippedOctave==0)continue;
++EligibleTermCount;
PotentialSkippedOctaves+=Term.octaveCount-Result.firstSkippedOctave;
}
}
std::printf("[WorldAssemblerVisualDetailCutoffPlan] lod=%d terms=%llu eligible_terms=%llu potential_skipped_octaves=%llu per_call_budget_divisor=%u sample_step_vox=%d status=%s\n",
Lod,static_cast<unsigned long long>(TermCount),
static_cast<unsigned long long>(EligibleTermCount),
static_cast<unsigned long long>(PotentialSkippedOctaves),
Probe.callBudgetDivisor,Step,
EligibleTermCount==0?"exact-no-eligible-tail":"candidate");
if(bApplyVisualDetailCutoff&&EligibleTermCount==0)
AppliedPixelBudgetsSubvoxels[static_cast<std::size_t>(Lod)]=0;
}
}
if(bScreenSpaceGate&&Assembly)
{
for(const auto& Plan:Assembly->plan.strates)
{
const VoxelForgeCore::Heightfield2D Field(Assembly->recipe,Plan);
for(const auto& Term:Field.visualDetailContract().terms)
for(std::uint32_t Octave=0;Octave<Term.octaveCount;++Octave)
{
const std::int64_t Wavelength=Term.baseWavelengthSubvoxels
/static_cast<std::int64_t>(1ull<<Octave);
const long double Amplitude=static_cast<long double>(Term.maximumDisplacementSubvoxels)
*Term.maximumNoiseAbsQ16/65536.0L
/static_cast<long double>(1ull<<Octave);
std::printf("[WorldAssemblerVisualDetailTerm] stratum=%d id=%llu octave=%u wavelength_vox=%.3f max_abs_surface_vox=%.3f declared=1\n",
Plan.strateIndex,static_cast<unsigned long long>(Term.stableId),Octave,
static_cast<double>(Wavelength)/256.0,static_cast<double>(Amplitude));
}
}
for(const auto& Island:Assembly->floatingIslands)
{
const VoxelForgeCore::FloatingIslandFieldV1 Field(
Island.manifest.recipe,Island.manifest.plan);
const auto Contract=Field.visualDetailContract();
std::printf("[WorldAssemblerVisualDetailContract] recipe=floating-islands strate=%d declared_terms=%zu exact_path=%d\n",
Island.strateIndex,Contract.terms.size(),Contract.terms.empty()?1:0);
}
}
const bool bRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels;
const bool bEnhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls;
VoxelForgeCore::World Shape(CoreSnapshot);
@@ -154,6 +309,12 @@ namespace StandaloneStreamBenchmark
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
FarHorizonLOD8InteriorStepVoxels);
if(bScreenSpaceGate||bApplyVisualDetailCutoff)
{
Streamer.SetVisualDetailCutoffBudgets(AppliedPixelBudgetsSubvoxels,
bApplyVisualDetailCutoff);
Streamer.SetVisualDetailProfilingEnabled(bScreenSpaceGate);
}
const auto StreamStart=Clock::now();
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
@@ -162,6 +323,22 @@ namespace StandaloneStreamBenchmark
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles but queued %d.\n",
Desired.Tiles.size(),Update.DesiredTiles);return 7;
}
FSceneExportWriter SceneExport;
const bool bExportRequested=!MeshExportPath.empty();
bool bSceneExportPassing=true;
if(bExportRequested)
{
bSceneExportPassing=SceneExport.Open(MeshExportPath,World.CoreVoxelSizeMicrons,
CameraPositionVoxels,CameraYawDegrees,CameraPitchDegrees,
static_cast<std::uint32_t>(Update.DesiredTiles));
if(!bSceneExportPassing)
{
Streamer.Stop();
std::fprintf(stderr,"[MeshSceneExport] FAIL: could not open %s\n",
MeshExportPath.string().c_str());
return 8;
}
}
std::vector<FHashedTile> DensityRows,MeshRows,PayloadRows,TopologyRows;
int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0;
@@ -193,6 +370,11 @@ namespace StandaloneStreamBenchmark
std::array<bool,9> ColumnCaptureCompleteByLOD{};
ColumnCaptureCompleteByLOD.fill(true);
std::array<double,9> WorkerSecondsByLOD{};
std::array<std::array<std::uint64_t,8>,9> DetailOctaveEvaluationsByLOD{};
std::array<std::array<std::uint64_t,8>,9> DetailOctaveEligibleByLOD{};
std::array<std::array<std::uint64_t,8>,9> DetailOctaveSkipsByLOD{};
std::array<std::array<double,8>,9> DetailOctaveMillisecondsByLOD{};
std::array<std::array<double,8>,9> DetailOctaveEligibleMillisecondsByLOD{};
std::array<double,9> ColumnEvalMsByLOD{},MarchingExclusiveMsByLOD{};
std::array<double,9> GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{};
std::array<double,9> MeshAssemblyMsByLOD{};
@@ -214,6 +396,9 @@ namespace StandaloneStreamBenchmark
double NativeMeshingMilliseconds=0.0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level<World.FullResClipLevels)++FullDetailExpected;
std::array<std::optional<FStandaloneCpuTile>,9> GateSampleTiles{};
std::array<double,9> GateSampleDistances{};
GateSampleDistances.fill(std::numeric_limits<double>::infinity());
Clock::time_point NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
bool bNeighborhoodReported=false,bFullDetailReported=false;
while(Finished<Update.DesiredTiles)
@@ -222,6 +407,7 @@ namespace StandaloneStreamBenchmark
if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
for(const FStandaloneCpuTile& Tile:Ready)
{
if(bExportRequested)SceneExport.Add(Tile);
++Finished;
if(bReportMeshCoverage)
{
@@ -239,6 +425,34 @@ namespace StandaloneStreamBenchmark
GroundRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.groundRefinementExclusiveMilliseconds;
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
for(std::size_t Octave=0;Octave<8;++Octave)
{
DetailOctaveEvaluationsByLOD[LOD][Octave]+=
Tile.CoreDiagnostics.visualDetailOctaveEvaluations[Octave];
DetailOctaveEligibleByLOD[LOD][Octave]+=
Tile.CoreDiagnostics.visualDetailOctaveBudgetEligible[Octave];
DetailOctaveSkipsByLOD[LOD][Octave]+=
Tile.CoreDiagnostics.visualDetailOctaveSkips[Octave];
DetailOctaveMillisecondsByLOD[LOD][Octave]+=
Tile.CoreDiagnostics.visualDetailOctaveMilliseconds[Octave];
DetailOctaveEligibleMillisecondsByLOD[LOD][Octave]+=
Tile.CoreDiagnostics.visualDetailOctaveEligibleMilliseconds[Octave];
}
if(bScreenSpaceGate&&Assembly&&Tile.Key.Level>=3&&Tile.Key.Level<9
&&!Tile.Vertices.empty()
&&StandaloneScreenSpaceGate::TileHasNativeSurface(Tile.Key,*Assembly,
static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0))
{
const double Distance=StandaloneScreenSpaceGate::TileAabbDistanceMeters(
Tile.Key,CameraPositionVoxels,
static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0);
const bool bCloser=Distance<GateSampleDistances[LOD]-1e-9;
const bool bTied=std::abs(Distance-GateSampleDistances[LOD])<=1e-9;
const bool bKeyLess=!GateSampleTiles[LOD]
||TileKeyLessForHash(Tile.Key,GateSampleTiles[LOD]->Key);
if(bCloser||(bTied&&bKeyLess))
{GateSampleDistances[LOD]=Distance;GateSampleTiles[LOD]=Tile;}
}
}
if(bProfileColumnOverlap&&Tile.Key.Level>=0
&&Tile.Key.Level<static_cast<int32>(ColumnCaptureTilesByLOD.size()))
@@ -321,6 +535,27 @@ namespace StandaloneStreamBenchmark
}
}
Streamer.Stop();
bool bScreenSpaceGatePassing=true;
if(bScreenSpaceGate)
{
if(Assembly)
bScreenSpaceGatePassing=StandaloneScreenSpaceGate::Run(GateSampleTiles,
Streamer,*Assembly,ClosestDisplayDistances,World.CoreVoxelSizeMicrons,
World.MaxClipLevel,PixelBudgetsSubvoxels);
else
{std::fprintf(stderr,"[ScreenSpaceGateResult] no-world-assembly status=REJECT\n");bScreenSpaceGatePassing=false;}
}
if(bExportRequested)
{
bSceneExportPassing=SceneExport.Close(static_cast<std::uint32_t>(Update.DesiredTiles));
std::error_code FileSizeError;
const std::uintmax_t ExportBytes=std::filesystem::file_size(MeshExportPath,FileSizeError);
std::printf("[MeshSceneExport] tiles=%u expected=%d bytes=%llu status=%s path=%s\n",
SceneExport.TileCount,Update.DesiredTiles,
static_cast<unsigned long long>(FileSizeError?0:ExportBytes),
bSceneExportPassing?"PASS":"FAIL",MeshExportPath.string().c_str());
bSceneExportPassing=bSceneExportPassing&&!FileSizeError;
}
bool bColumnOverlapCapturePassing=true;
if(bProfileColumnOverlap)
{
@@ -345,6 +580,15 @@ namespace StandaloneStreamBenchmark
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),WorkerSecondsByLOD[LOD],
ColumnEvalMsByLOD[LOD],MarchingExclusiveMsByLOD[LOD],
GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD],MeshAssemblyMsByLOD[LOD]);
if(bScreenSpaceGate)
for(std::size_t Octave=0;Octave<8;++Octave)
std::printf("[WorldAssemblerLODDetailOctave] lod=%zu octave=%zu evaluated=%llu budget_eligible=%llu skipped=%llu eval_ms=%.6f eligible_ms=%.6f\n",
LOD,Octave,
static_cast<unsigned long long>(DetailOctaveEvaluationsByLOD[LOD][Octave]),
static_cast<unsigned long long>(DetailOctaveEligibleByLOD[LOD][Octave]),
static_cast<unsigned long long>(DetailOctaveSkipsByLOD[LOD][Octave]),
DetailOctaveMillisecondsByLOD[LOD][Octave],
DetailOctaveEligibleMillisecondsByLOD[LOD][Octave]);
}
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
const double NeighborhoodMeshSeconds=std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count();
@@ -393,9 +637,59 @@ namespace StandaloneStreamBenchmark
static_cast<unsigned long long>(HashTileRows(MeshRows)),
static_cast<unsigned long long>(HashTileRows(PayloadRows)),
static_cast<unsigned long long>(HashTileRows(TopologyRows)));
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
{
const auto FilterLOD=[LOD](const std::vector<FHashedTile>& Rows)
{
std::vector<FHashedTile> Selected;
for(const FHashedTile& Row:Rows)
if(Row.Key.Level==static_cast<int32>(LOD))Selected.push_back(Row);
return Selected;
};
auto LodDensity=FilterLOD(DensityRows),LodMesh=FilterLOD(MeshRows);
auto LodPayload=FilterLOD(PayloadRows),LodTopology=FilterLOD(TopologyRows);
std::printf("[PipelineLODHash] lod=%zu tiles=%llu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),
static_cast<unsigned long long>(HashTileRows(LodDensity)),
static_cast<unsigned long long>(HashTileRows(LodMesh)),
static_cast<unsigned long long>(HashTileRows(LodPayload)),
static_cast<unsigned long long>(HashTileRows(LodTopology)));
}
const std::array<VoxelForgeCore::Vec3d,9> QueryPoints={{
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X+8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X-8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y+8.0,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y-8.0,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z+8.0},
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z-8.0},
{CameraPositionVoxels.X+64.0,CameraPositionVoxels.Y-32.0,CameraPositionVoxels.Z+16.0},
{CameraPositionVoxels.X-128.0,CameraPositionVoxels.Y+96.0,CameraPositionVoxels.Z-64.0}}};
uint64 ExactDensityHash=14695981039346656037ull;
uint64 ExactUnclampedHash=14695981039346656037ull;
uint64 ExactDetailHash=14695981039346656037ull;
uint64 ExactCollisionHash=14695981039346656037ull;
for(const auto& Point:QueryPoints)
{
const float Density=Shape.densityAt(Point);
const float Unclamped=Shape.unclampedDensityAt(Point);
const auto Detail=Shape.detailSampleAt(Point);
HashWord(ExactDensityHash,std::bit_cast<uint32>(Density),4);
HashWord(ExactUnclampedHash,std::bit_cast<uint32>(Unclamped),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.displacement),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.caveInfluence),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.floorInfluence),4);
HashWord(ExactCollisionHash,Shape.isSolidAt(Point)?1u:0u,1);
}
std::printf("[PipelineExactQueryHash] probes=%zu density=0x%016llx unclamped=0x%016llx detail=0x%016llx collision=0x%016llx path=direct-Core-queries\n",
QueryPoints.size(),static_cast<unsigned long long>(ExactDensityHash),
static_cast<unsigned long long>(ExactUnclampedHash),
static_cast<unsigned long long>(ExactDetailHash),
static_cast<unsigned long long>(ExactCollisionHash));
}
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)?0:6;
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)
&&(!bExportRequested||bSceneExportPassing)&&bScreenSpaceGatePassing?0:6;
}
} // namespace StandaloneStreamBenchmark
+36 -2
View File
@@ -646,6 +646,18 @@ public:
int32 GetWorkerCount()const{return WorkerCount;}
uint64 GetCacheHits()const{return CacheHitCount.load(std::memory_order_relaxed);}
void SetVisualDetailCutoffBudgets(const std::array<std::int64_t,9>& Budgets,bool Apply)
{VisualDetailBudgetSubvoxels=Budgets;bEnableVisualDetailCutoff=true;bApplyVisualDetailCutoff=Apply;}
void SetVisualDetailProfilingEnabled(bool Enabled)
{bProfileVisualDetailOctaves=Enabled;}
FStandaloneCpuTile GenerateDiagnostic(const FVoxelTileKey& Key,
std::uint32_t GlobalOctaveDrop=0,std::uint32_t CellStride=1,
bool ForceExactVisualDetail=false)
{
FStandaloneTileJob Job;Job.Key=Key;Job.StartedAt=FClock::now();Job.QueuedAt=Job.StartedAt;
return Generate(Job,GlobalOctaveDrop,CellStride,0,ForceExactVisualDetail);
}
private:
FStandaloneStreamingUpdate UpdateDesiredSet(FStandaloneDesiredTileSet NewDesired,
const std::vector<FVoxelTileKey>& ResidentKeys,uint64 CrossingIndex)
@@ -761,12 +773,15 @@ private:
Wake.notify_all();
return Stats;
}
FStandaloneCpuTile Generate(const FStandaloneTileJob& Job)
FStandaloneCpuTile Generate(const FStandaloneTileJob& Job,
std::uint32_t DiagnosticGlobalOctaveDrop=0,std::uint32_t DiagnosticCellStride=1,
std::int64_t DiagnosticVisualBudgetSubvoxels=0,
bool ForceExactVisualDetail=false)
{
const auto StartTime=Job.StartedAt;
FStandaloneCpuTile Out;Out.Key=Job.Key;Out.RequestedCrossing=Job.RequestedCrossing;
Out.QueuedAt=Job.QueuedAt;Out.StartedAt=Job.StartedAt;
if(MeshCache)
if(MeshCache&&!ForceExactVisualDetail)
{
if(const FStandaloneCpuTile* Cached=MeshCache->Find(Job.Key))
{
@@ -805,6 +820,21 @@ private:
Options.skipMaterialGroups=bSkipMaterialGroups;Options.skipUv=bSkipUV;Options.skipColors=bSkipColors;
Options.captureColumnCoordinates=bCaptureColumnCoordinates;
Options.lod8HorizonInteriorStepVoxels=Lod8HorizonInteriorStepVoxels;
Options.visualDetailPixelBudgetSubvoxels=DiagnosticVisualBudgetSubvoxels;
if(DiagnosticVisualBudgetSubvoxels==0&&bEnableVisualDetailCutoff
&&Level>=3&&Level<static_cast<int32>(VisualDetailBudgetSubvoxels.size()))
Options.visualDetailPixelBudgetSubvoxels=
VisualDetailBudgetSubvoxels[static_cast<std::size_t>(Level)];
Options.visualDetailSampleStepVoxels=FMath::Max(1,Extent/Cells);
Options.profileVisualDetailOctaves=bProfileVisualDetailOctaves&&!ForceExactVisualDetail;
Options.visualDetailCutoffEnabled=bApplyVisualDetailCutoff
&&!ForceExactVisualDetail&&Level>=3
&&Options.visualDetailPixelBudgetSubvoxels>0;
Options.visualDetailContractVersion=Options.visualDetailCutoffEnabled
?VoxelForgeCore::CurrentVisualDetailCutoffContractVersion:0;
Options.diagnosticGlobalOctaveDrop=DiagnosticGlobalOctaveDrop;
Options.diagnosticColumnInterpolationStride=
std::max<std::uint32_t>(1,DiagnosticCellStride);
std::string Error;
auto Result=CoreWorld->generateTile(
{{Job.Key.Coord.X,Job.Key.Coord.Y,Job.Key.Coord.Z},Job.Key.Level},Options,Error);
@@ -977,6 +1007,10 @@ private:
bool bSkipColors=false;
bool bCaptureColumnCoordinates=false;
int32 Lod8HorizonInteriorStepVoxels=0;
std::array<std::int64_t,9> VisualDetailBudgetSubvoxels{};
bool bEnableVisualDetailCutoff=false;
bool bApplyVisualDetailCutoff=false;
bool bProfileVisualDetailOctaves=false;
std::atomic<uint64> CacheHitCount{0};
mutable std::mutex Mutex;
std::condition_variable Wake;