Migrate planetary geometry consumers

This commit is contained in:
Meta Vens 2026-07-22 04:12:41 +01:00
commit 42778c183a
39 changed files with 117 additions and 52 deletions

View file

@ -2,6 +2,7 @@
<ItemGroup>
<ProjectReference Include="..\Aquarium.Engine.Contracts\Aquarium.Engine.Contracts.csproj" />
<ProjectReference Include="..\..\..\CultLib\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
<PropertyGroup>

View file

@ -2,6 +2,7 @@ using System.Globalization;
using System.Numerics;
using Aquarium.Engine.Fractal;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Grammar;

View file

@ -1,4 +1,5 @@
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Grammar;

View file

@ -1,5 +1,6 @@
using System.Numerics;
using CultMath;
using GameCult.Geometry;
using Aquarium.Engine.Fractal.Grammar;
namespace Aquarium.Engine.Fractal.Lod;

View file

@ -1,5 +1,6 @@
using System.Numerics;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Projection;

View file

@ -1,5 +1,6 @@
using System.Numerics;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Projection;

View file

@ -1,4 +1,5 @@
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Projection;

View file

@ -1,5 +1,6 @@
using System.Numerics;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Projection;

View file

@ -2,6 +2,7 @@ using System.Globalization;
using System.Text;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Projection;

View file

@ -1,5 +1,6 @@
using System.Numerics;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Projection;

View file

@ -23,6 +23,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\CultMath\src\CultMath\CultMath.csproj" />
<ProjectReference Include="..\..\..\CultLib\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -7,6 +7,7 @@ using SharpGen.Runtime;
using Aquarium.Engine.Render.Ui;
using Aquarium.Engine.Ui;
using CultMath;
using GameCult.Geometry;
using Vortice;
using Vortice.D3DCompiler;
using Vortice.Direct3D;

View file

@ -65,6 +65,41 @@ internal static class D3D12ShaderCompiler
}
}
}
const string cultMathUnityPrefix = "Packages/org.gamecult.cultmath/shaders/";
if (normalized.StartsWith(cultMathUnityPrefix, StringComparison.Ordinal))
{
var relative = normalized[cultMathUnityPrefix.Length..].Replace('/', Path.DirectorySeparatorChar);
foreach (var start in new[] { directory, AppContext.BaseDirectory })
{
var current = Path.GetFullPath(start);
while (!string.IsNullOrEmpty(current))
{
var localPackage = Path.Combine(current, "CultMath", relative);
if (File.Exists(localPackage)) return localPackage;
var siblingRepository = Path.Combine(current, "CultMath", "shaders", relative);
if (File.Exists(siblingRepository)) return siblingRepository;
var parent = Path.GetDirectoryName(current);
if (string.IsNullOrEmpty(parent) || parent == current) break;
current = parent;
}
}
}
if (normalized.StartsWith("GameCult.Geometry/", StringComparison.Ordinal))
{
var relative = normalized["GameCult.Geometry/".Length..].Replace('/', Path.DirectorySeparatorChar);
foreach (var start in new[] { directory, AppContext.BaseDirectory })
{
var current = Path.GetFullPath(start);
while (!string.IsNullOrEmpty(current))
{
var candidate = Path.Combine(current, "CultLib", "src", "GameCult.Geometry", "Shaders", relative);
if (File.Exists(candidate)) return candidate;
var parent = Path.GetDirectoryName(current);
if (string.IsNullOrEmpty(parent) || parent == current) break;
current = parent;
}
}
}
return local;
}
}

View file

@ -1,4 +1,4 @@
#include "CultMath/CultMath.hlsl"
#include "GameCult.Geometry/GameCult.Geometry.hlsl"
struct ParityInput { float4 position_base; float4 slope_fade; float4 scalar0; float4 rounding; float4 onset; float4 scalar1; float4 scalar2; float4 scalar3; };
struct ParityOutput { float4 delta_magnitude; float4 ridge_fade; };
@ -11,13 +11,13 @@ void D3D12AdvancedErosionParityCS(uint3 id : SV_DispatchThreadID)
{
if (id.x >= input_count) return;
ParityInput input = inputs[id.x];
CultMathAdvancedErosionParameters p;
GameCultGeometryAdvancedErosionParameters p;
p.scale=input.scalar0.x; p.strength=input.scalar0.y; p.gully_weight=input.scalar0.z; p.detail=input.scalar0.w;
p.rounding=input.rounding; p.onset=input.onset; p.assumed_slope=input.scalar1.xy;
p.cell_scale=input.scalar1.z; p.normalization=input.scalar1.w; p.octaves=(int)input.scalar2.x;
p.lacunarity=input.scalar2.y; p.gain=input.scalar2.z;
CultMathErosionBandSelection band; band.active_octaves=(int)input.scalar3.x; band.final_octave_weight=input.scalar3.y; band.finest_included_wavelength=input.scalar3.z; band.unresolved_height_bound=input.scalar3.w;
CultMathAdvancedErosionResult r = cultmath_advanced_erosion_filter_banded(input.position_base.xy, float3(input.position_base.z, input.slope_fade.xy), input.slope_fade.z, p, band);
GameCultGeometryErosionBandSelection band; band.active_octaves=(int)input.scalar3.x; band.final_octave_weight=input.scalar3.y; band.finest_included_wavelength=input.scalar3.z; band.unresolved_height_bound=input.scalar3.w;
GameCultGeometryAdvancedErosionResult r = gamecult_geometry_advanced_erosion_filter_banded(input.position_base.xy, float3(input.position_base.z, input.slope_fade.xy), input.slope_fade.z, p, band);
outputs[id.x].delta_magnitude=float4(r.delta, r.magnitude);
outputs[id.x].ridge_fade=float4(r.ridge_map, r.fade_target, 0, 0);
}

View file

@ -1,4 +1,4 @@
#include "CultMath/CultMath.hlsl"
#include "GameCult.Geometry/GameCult.Geometry.hlsl"
struct PageOutput { float4 height_gradient; float4 masks; };
struct PageSummary { float4 bounds; float4 metadata; };
@ -10,11 +10,11 @@ cbuffer PageConstants : register(b0) { uint page_sample_count; uint page_sample_
void D3D12ZyphosTerrainPageSummaryCS(uint3 id : SV_DispatchThreadID)
{
if (id.x != 0 || page_sample_count == 0) return;
float4 summary = cultmath_planetary_summary_empty();
float4 summary = gamecult_geometry_planetary_summary_empty();
[loop] for (uint index = 0; index < page_sample_count; index++)
{
PageOutput sample = summary_inputs[page_sample_offset + index];
summary = cultmath_planetary_summary_accumulate(summary, sample.height_gradient, sample.masks.w);
summary = gamecult_geometry_planetary_summary_accumulate(summary, sample.height_gradient, sample.masks.w);
}
summary_outputs[page_summary_index].bounds = summary;
summary_outputs[page_summary_index].metadata = float4(page_sample_count, page_sample_offset, page_summary_index, 1.0);

View file

@ -1,4 +1,4 @@
#include "CultMath/CultMath.hlsl"
#include "GameCult.Geometry/GameCult.Geometry.hlsl"
struct PlanetaryTopologyInput
{
@ -26,47 +26,47 @@ void D3D12PlanetaryTopologyParityCS(uint3 id : SV_DispatchThreadID)
if (input.coordinate_mode.z < 0.5)
{
int face = (int)input.direction_face.w;
output.direction_face = float4(cultmath_planetary_face_direction(face, input.coordinate_mode.xy), (float)face);
output.direction_face = float4(gamecult_geometry_planetary_face_direction(face, input.coordinate_mode.xy), (float)face);
output.coordinate_valid = float4(input.coordinate_mode.xy, 0.0, 1.0);
}
else if (input.coordinate_mode.z < 1.5)
{
int face;
float2 coordinate = cultmath_planetary_face_coordinate(input.direction_face.xyz, face);
float2 coordinate = gamecult_geometry_planetary_face_coordinate(input.direction_face.xyz, face);
output.direction_face = float4(normalize(input.direction_face.xyz), (float)face);
output.coordinate_valid = float4(coordinate, 0.0, 1.0);
}
else if (input.coordinate_mode.z < 2.5)
{
output.direction_face = float4(normalize(input.direction_face.xyz), 0.0);
output.coordinate_valid = float4(cultmath_planetary_equirectangular_forward(input.direction_face.xyz), 0.0, 1.0);
output.coordinate_valid = float4(gamecult_geometry_planetary_equirectangular_forward(input.direction_face.xyz), 0.0, 1.0);
}
else if (input.coordinate_mode.z < 3.5)
{
output.direction_face = float4(cultmath_planetary_equirectangular_inverse(input.coordinate_mode.xy), 0.0);
output.direction_face = float4(gamecult_geometry_planetary_equirectangular_inverse(input.coordinate_mode.xy), 0.0);
output.coordinate_valid = float4(input.coordinate_mode.xy, 0.0, 1.0);
}
else if (input.coordinate_mode.z < 4.5)
{
output.direction_face = float4(normalize(input.direction_face.xyz), 0.0);
output.coordinate_valid = float4(cultmath_planetary_equal_earth_forward(input.direction_face.xyz), 0.0, 1.0);
output.coordinate_valid = float4(gamecult_geometry_planetary_equal_earth_forward(input.direction_face.xyz), 0.0, 1.0);
}
else if (input.coordinate_mode.z < 5.5)
{
output.direction_face = float4(cultmath_planetary_equal_earth_inverse(input.coordinate_mode.xy), 0.0);
output.direction_face = float4(gamecult_geometry_planetary_equal_earth_inverse(input.coordinate_mode.xy), 0.0);
output.coordinate_valid = float4(input.coordinate_mode.xy, 0.0, 1.0);
}
else if (input.coordinate_mode.z < 6.5)
{
float2 coordinate;
bool valid=cultmath_planetary_projection_forward(input.direction_face.xyz,(int)input.coordinate_mode.w,input.projection_parameters.xyz,coordinate);
bool valid=gamecult_geometry_planetary_projection_forward(input.direction_face.xyz,(int)input.coordinate_mode.w,input.projection_parameters.xyz,coordinate);
output.direction_face=float4(normalize(input.direction_face.xyz),0);
output.coordinate_valid=float4(coordinate,0,valid?1.0:0.0);
}
else
{
float3 direction;
bool valid=cultmath_planetary_projection_inverse(input.coordinate_mode.xy,(int)input.coordinate_mode.w,input.projection_parameters.xyz,direction);
bool valid=gamecult_geometry_planetary_projection_inverse(input.coordinate_mode.xy,(int)input.coordinate_mode.w,input.projection_parameters.xyz,direction);
output.direction_face=float4(direction,0);
output.coordinate_valid=float4(input.coordinate_mode.xy,0,valid?1.0:0.0);
}

View file

@ -12,6 +12,7 @@
<ItemGroup>
<ProjectReference Include="..\Aquarium.Engine.Contracts\Aquarium.Engine.Contracts.csproj" />
<ProjectReference Include="..\Aquarium.Engine.Fractal\Aquarium.Engine.Fractal.csproj" />
<ProjectReference Include="..\..\..\CultLib\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -3,7 +3,7 @@ static const int ZYPHOS_GEOMETRY_BRUSH_LIMIT = 4;
#include "D3D12SdfCommon.hlsli"
#include "D3D12SdfMath.hlsli"
#include "CultMath/CultMath.hlsl"
#include "GameCult.Geometry/GameCult.Geometry.hlsl"
#include "D3D12ZyphosTerrain.hlsli"
float3 zyRotateZ(float3 p, float angle)
@ -58,7 +58,7 @@ float zyCompactBrush(float2 delta, float2 radii, float rotation, float falloff,
float2 zyCubeFaceUv(float3 dir, out float face)
{
// Authored brush packets retain their legacy cube-ratio chart. Planetary
// page addressing and patch geometry use CultMath's QSC topology.
// Page addressing and patch geometry use GameCult.Geometry's QSC topology.
float3 a = abs(dir);
if (a.x >= a.y && a.x >= a.z)
{

View file

@ -1,7 +1,7 @@
#ifndef D3D12_ZYPHOS_TERRAIN_HLSLI
#define D3D12_ZYPHOS_TERRAIN_HLSLI
#include "CultMath/CultMath.hlsl"
#include "GameCult.Geometry/GameCult.Geometry.hlsl"
struct ZyPlanetPageOutput { float4 height_gradient; float4 masks; };
struct ZyPlanetPageMetadata { float4 address; float4 layout; float4 bounds; float4 state; };
@ -16,7 +16,7 @@ static const float ZY_TERRAIN_NON_EROSION_SLOPE_BOUND = 8.0;
bool zyTerrainPageLocal(float3 dir, ZyPlanetPageMetadata metadata, out float2 local)
{
return cultmath_planetary_page_local(dir,metadata.address,metadata.state.x,local);
return gamecult_geometry_planetary_page_local(dir,metadata.address,metadata.state.x,local);
}
void zySampleErosionPage(int pageIndex, float2 local, out float4 heightGradient, out float2 masks)
@ -28,12 +28,12 @@ void zySampleErosionPage(int pageIndex, float2 local, out float4 heightGradient,
int offset=(int)metadata.layout.x;
ZyPlanetPageOutput a=zy_planet_page[offset+p0.y*(int)storage+p0.x], b=zy_planet_page[offset+p0.y*(int)storage+p1.x];
ZyPlanetPageOutput c=zy_planet_page[offset+p1.y*(int)storage+p0.x], d=zy_planet_page[offset+p1.y*(int)storage+p1.x];
CultMathPlanetaryPageSample ca,cb,cc,cd;
GameCultGeometryPlanetaryPageSample ca,cb,cc,cd;
ca.height_gradient=a.height_gradient; ca.masks=a.masks.xy;
cb.height_gradient=b.height_gradient; cb.masks=b.masks.xy;
cc.height_gradient=c.height_gradient; cc.masks=c.masks.xy;
cd.height_gradient=d.height_gradient; cd.masks=d.masks.xy;
CultMathPlanetaryPageSample sample=cultmath_planetary_page_lerp(ca,cb,cc,cd,fraction);
GameCultGeometryPlanetaryPageSample sample=gamecult_geometry_planetary_page_lerp(ca,cb,cc,cd,fraction);
heightGradient=sample.height_gradient; masks=sample.masks;
}
@ -128,28 +128,28 @@ float3 zySphericalFieldGradient(float3 dir)
float3 gradient = float3(dx,dy,dz)/(2.0*epsilon); return gradient-dir*dot(gradient,dir);
}
CultMathAdvancedErosionParameters zyErosionParameters(float radius)
GameCultGeometryAdvancedErosionParameters zyErosionParameters(float radius)
{
CultMathAdvancedErosionParameters p;
GameCultGeometryAdvancedErosionParameters p;
p.scale=radius*0.075; p.strength=0.12; p.gully_weight=0.58; p.detail=1.45;
p.rounding=float4(0.1,0.015,0.1,2.0); p.onset=float4(1.25,1.25,2.8,1.5); p.assumed_slope=float2(0.7,0.85);
p.cell_scale=0.7; p.normalization=0.5; p.octaves=7; p.lacunarity=2.0; p.gain=0.5; return p;
}
CultMathPlanetarySurfaceSample zyAdvancedErosionSurface(float3 dir, float field, float radius, float sampleSpacing)
GameCultGeometryPlanetarySurfaceSample zyAdvancedErosionSurface(float3 dir, float field, float radius, float sampleSpacing)
{
CultMathPlanetaryFieldDefinition definition;
GameCultGeometryPlanetaryFieldDefinition definition;
definition.radius=radius; definition.seed=0; definition.erosion=zyErosionParameters(radius);
CultMathPlanetaryBaseFieldSample base_sample;
GameCultGeometryPlanetaryBaseFieldSample base_sample;
base_sample.radial_displacement=0.0; base_sample.radial_gradient=0.0;
base_sample.field_value=field; base_sample.field_gradient=zySphericalFieldGradient(dir)/radius;
base_sample.fade_target=saturate(field*0.5+0.5)*2.0-1.0;
return cultmath_planetary_field_sample(definition,dir,base_sample,sampleSpacing);
return gamecult_geometry_planetary_field_sample(definition,dir,base_sample,sampleSpacing);
}
float4 zyAdvancedErosion(float3 dir, float field, float radius, float sampleSpacing)
{
CultMathPlanetarySurfaceSample sample=zyAdvancedErosionSurface(dir,field,radius,sampleSpacing);
GameCultGeometryPlanetarySurfaceSample sample=zyAdvancedErosionSurface(dir,field,radius,sampleSpacing);
return float4(sample.radial_displacement,sample.ridge,sample.gully,sample.unresolved_height_bound);
}

View file

@ -6,15 +6,15 @@ StructuredBuffer<PageInput> page_inputs : register(t0);
RWStructuredBuffer<PageOutput> page_outputs : register(u0);
cbuffer PageConstants : register(b0) { uint page_sample_count; }
CultMathPlanetaryPageSample zyPageErosion(float3 direction, float radius, float spacing, float parent_spacing)
GameCultGeometryPlanetaryPageSample zyPageErosion(float3 direction, float radius, float spacing, float parent_spacing)
{
float3 dir=normalize(direction);
float field=zySphericalField(dir);
CultMathPlanetarySurfaceSample child=zyAdvancedErosionSurface(dir,field,radius,spacing);
CultMathPlanetarySurfaceSample parent=(CultMathPlanetarySurfaceSample)0;
GameCultGeometryPlanetarySurfaceSample child=zyAdvancedErosionSurface(dir,field,radius,spacing);
GameCultGeometryPlanetarySurfaceSample parent=(GameCultGeometryPlanetarySurfaceSample)0;
bool has_parent=parent_spacing>0.0;
if(has_parent)parent=zyAdvancedErosionSurface(dir,field,radius,parent_spacing);
return cultmath_planetary_residual_sample(child,parent,has_parent);
return gamecult_geometry_planetary_residual_sample(child,parent,has_parent);
}
@ -23,8 +23,8 @@ void D3D12ZyphosTerrainPageCS(uint3 id : SV_DispatchThreadID)
{
if(id.x>=page_sample_count) return;
PageInput input=page_inputs[id.x]; float3 dir=normalize(input.direction_radius.xyz); float radius=input.direction_radius.w; float spacing=input.sampling.x; float parent_spacing=input.sampling.y;
CultMathPlanetaryPageSample sample=zyPageErosion(dir,radius,spacing,parent_spacing);
CultMathPlanetarySurfaceSample child=zyAdvancedErosionSurface(dir,zySphericalField(dir),radius,spacing);
GameCultGeometryPlanetaryPageSample sample=zyPageErosion(dir,radius,spacing,parent_spacing);
GameCultGeometryPlanetarySurfaceSample child=zyAdvancedErosionSurface(dir,zySphericalField(dir),radius,spacing);
page_outputs[id.x].height_gradient=sample.height_gradient;
page_outputs[id.x].masks=float4(sample.masks,0,child.unresolved_height_bound);
}

View file

@ -1,4 +1,4 @@
#include "CultMath/CultMath.hlsl"
#include "GameCult.Geometry/GameCult.Geometry.hlsl"
struct PageOutput { float4 height_gradient; float4 masks; };
struct PageSummary { float4 bounds; float4 metadata; };
@ -10,11 +10,11 @@ cbuffer PageConstants : register(b0) { uint page_sample_count; uint page_sample_
void D3D12ZyphosTerrainPageSummaryCS(uint3 id : SV_DispatchThreadID)
{
if(id.x!=0 || page_sample_count==0) return;
float4 summary=cultmath_planetary_summary_empty();
float4 summary=gamecult_geometry_planetary_summary_empty();
[loop] for(uint index=0;index<page_sample_count;index++)
{
PageOutput sample=summary_inputs[page_sample_offset+index];
summary=cultmath_planetary_summary_accumulate(summary,sample.height_gradient,sample.masks.w);
summary=gamecult_geometry_planetary_summary_accumulate(summary,sample.height_gradient,sample.masks.w);
}
summary_outputs[page_summary_index].bounds=summary;
summary_outputs[page_summary_index].metadata=float4(page_sample_count,page_sample_offset,page_summary_index,1);

View file

@ -15,7 +15,7 @@ struct ZyPatchSceneOut
float3 zyPatchDirection(uint face,float2 local)
{
return cultmath_planetary_face_direction((int)face,local*2.0-1.0);
return gamecult_geometry_planetary_face_direction((int)face,local*2.0-1.0);
}
ZyPatchVertexOut D3D12ZyphosTerrainPatchVS(uint vertexId:SV_VertexID,uint instanceId:SV_InstanceID)
@ -43,7 +43,7 @@ ZyPatchSceneOut D3D12ZyphosTerrainPatchPS(ZyPatchVertexOut input)
{
float3 local=p-planet.centerRadius.xyz; float3 dir=zyPlanetDir(local,planet);
float targetRadius=planet.state.x+zyTerrainOffset(dir,planet);
p=cultmath_planetary_radial_refinement_step(p,ray,planet.centerRadius.xyz,targetRadius,0.2,0.08);
p=gamecult_geometry_planetary_radial_refinement_step(p,ray,planet.centerRadius.xyz,targetRadius,0.2,0.08);
}
if(!all(isfinite(p)))p=coarsePosition;
float travel=length(p-cameraPosition); if(!isfinite(travel)||travel<=0.0||travel>farDistance)discard;

View file

@ -1,6 +1,7 @@
using System.Numerics;
using Aquarium.Engine.Render;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Zyphos;

View file

@ -3,6 +3,7 @@
<ItemGroup>
<ProjectReference Include="..\Aquarium.Engine.Contracts\Aquarium.Engine.Contracts.csproj" />
<ProjectReference Include="..\Aquarium.Engine.Fractal\Aquarium.Engine.Fractal.csproj" />
<ProjectReference Include="..\..\..\CultLib\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
<PropertyGroup>

View file

@ -1,4 +1,5 @@
using CultMath;
using GameCult.Geometry;
using System.Numerics;
namespace Saga;

View file

@ -71,12 +71,12 @@ invariants:
terrain should be a quadtree of brush-painted surface tiles, subdivided by
projected footprint, curvature, brush/material detail, silhouettes, and
temporal uncertainty before SDF probes emit detail-adaptive surface splats.
- Deterministic planetary geometry is owned by CultMath's scale-aware
- Deterministic planetary geometry is owned by GameCult.Geometry's scale-aware
planetary field runtime. It owns field identity, point/batch and
double-position CPU queries, tangent/QSC cube-sphere topology, bordered
pages and child residual composition, projected-error LOD, residual
lifecycle, ray/path/region queries, coarse patch topology, and map
projections/tiles. CultMath maintains matching HLSL for field evaluation,
projections/tiles. GameCult.Geometry maintains matching HLSL for field evaluation,
topology, page interpolation/residuals, and radial refinement. Clients own
base fields, terrain parameters, gameplay meaning, and presentation policy.
- The production lowering for stateless planetary erosion is specified in
@ -86,7 +86,7 @@ invariants:
- CPU/GPU terrain parity is measured through a standalone D3D12 compute and
readback probe. Shader include expansion is owned by D3D12ShaderCompiler
and shared with the renderer; parity probes must not boot a swapchain or
duplicate CultMath equations.
duplicate GameCult.Geometry equations.
- Planetary erosion frequencies are selected in world-distance wavelengths
from the current sample footprint. The last resolvable octave fades
fractionally and reports its omitted-height bound; Zyphos lowers the planar
@ -97,10 +97,10 @@ invariants:
it may not change terrain at a shared boundary. Page borders evaluate the
spherical field beyond tile bounds without reading neighbor residency.
- D3D12 owns persistent planetary page input, output, metadata, and summary
buffers, their bindings, dispatch, and draw submission. CultMath owns the
buffers, their bindings, dispatch, and draw submission. GameCult.Geometry owns the
page layout, spherical sample directions, canonical GPU input/metadata
payload, residual semantics, interpolation, and summaries. Client adapters
only convert CultMath vectors to their host ABI. Client compute entry points bind the client base field to
only convert CultMath primitives to their host ABI. Client compute entry points bind the client base field to
those functions before GPU reduction. Zyphos registers planet, Umbros, and
star proxies in object index order and publishes all three SDF objects from
one scene builder.
@ -109,7 +109,7 @@ invariants:
field; covered pixels perform four bounded radial corrections against the
complete resident page field, then use the shared differential/material
contract. Missing pages lower to the nearest resident ancestor (the base
field at root). Direct CultMath evaluation and the bracketed planet SDF are
field at root). Direct GameCult.Geometry evaluation and the bracketed planet SDF are
verification oracles only; neither owns production visibility.
- D3D12 binds the page atlas, metadata, summaries, and page set to both patch
shader stages at t81-t84. Patch projection follows the renderer's established
@ -139,13 +139,13 @@ invariants:
filtered erosion against the summed page field at the selected spacing;
mode 28 exposes content fingerprint, spacing ratio, and deepest level.
The unresolved bound and measured direct error remain distinct signals.
- The bounded radial correction step is owned by CultMath in matching C# and
- The bounded radial correction step is owned by GameCult.Geometry in matching C# and
HLSL bodies. Zyphos composes four steps with its terrain-offset callback;
the renderer does not carry a private correction equation.
- Planetary page residency is owned by CultMath and separates content from
- Planetary page residency is owned by GameCult.Geometry and separates content from
presentation state. ContentVersion changes only when the resident tile set
changes; PresentationVersion carries arrival/departure weights without
regenerating erosion. Six root pages remain resident. CultMath's
regenerating erosion. Six root pages remain resident. GameCult.Geometry's
projected-error selector uses unresolved-height bounds against camera
footprint to request one ancestor chain, and its residual lifecycle keeps
departing chains addressable until their weights reach zero.

View file

@ -24,6 +24,7 @@
<ProjectReference Include="..\..\src\Aquarium.Engine.Contracts\Aquarium.Engine.Contracts.csproj" />
<ProjectReference Include="..\..\src\Aquarium.Fensalir\Aquarium.Fensalir.csproj" />
<ProjectReference Include="..\..\src\Aquarium.Zyphos\Aquarium.Zyphos.csproj" />
<ProjectReference Include="..\..\..\CultLib\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
</Project>

View file

@ -1,4 +1,5 @@
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -1,5 +1,6 @@
using Aquarium.Engine.Fractal;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -1,6 +1,7 @@
using Aquarium.Engine.Fractal.Grammar;
using Aquarium.Engine.Fractal.Lod;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -2,6 +2,7 @@ using System.Numerics;
using Aquarium.Engine.Fractal;
using Aquarium.Engine.Fractal.Grammar;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -4,6 +4,7 @@ using Aquarium.Engine.Fractal.Brushes;
using Aquarium.Engine.Fractal.Grammar;
using Aquarium.Engine.Fractal.Lod;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -4,6 +4,7 @@ using Aquarium.Engine.Fractal.Brushes;
using Aquarium.Engine.Fractal.Grammar;
using Aquarium.Engine.Fractal.Lod;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -1,4 +1,5 @@
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -2,6 +2,7 @@ using System.Numerics;
using Aquarium.Engine.Fractal;
using Aquarium.Engine.Fractal.Projection;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Fractal.Tests;

View file

@ -22,6 +22,7 @@
<ProjectReference Include="..\..\src\Aquarium.Engine\Aquarium.Engine.csproj" />
<ProjectReference Include="..\..\src\Aquarium.Engine.Fractal\Aquarium.Engine.Fractal.csproj" />
<ProjectReference Include="..\..\src\Aquarium.Zyphos\Aquarium.Zyphos.csproj" />
<ProjectReference Include="..\..\..\CultLib\src\GameCult.Geometry\GameCult.Geometry.csproj" />
</ItemGroup>
</Project>

View file

@ -2,13 +2,14 @@ using System.Numerics;
using System.Runtime.InteropServices;
using Aquarium.Engine.Render;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Tests;
public sealed class D3D12AdvancedErosionParityTests
{
[Fact]
public void AdvancedErosionMatchesCultMathCpuAcrossDeterministicCorpus()
public void AdvancedErosionMatchesGameCultGeometryCpuAcrossDeterministicCorpus()
{
if (!OperatingSystem.IsWindows()) return;
var parameters = AdvancedErosionParameters.Default;

View file

@ -3,6 +3,7 @@ using System.Runtime.InteropServices;
using Aquarium.Engine.Render;
using Aquarium.Zyphos;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Tests;
@ -214,6 +215,7 @@ public sealed class D3D12PlanetarySurfacePageTests
CopyShaderTree(Path.Combine(RepositoryRoot(), "src", "Aquarium.Engine", "Render", "Shaders"), temporaryRoot);
CopyShaderTree(Path.Combine(RepositoryRoot(), "src", "Aquarium.Zyphos", "Shaders"), temporaryRoot);
CopyShaderTree(Path.GetFullPath(Path.Combine(RepositoryRoot(), "..", "CultMath", "shaders")), Path.Combine(temporaryRoot, "CultMath"));
CopyShaderTree(Path.GetFullPath(Path.Combine(RepositoryRoot(), "..", "CultLib", "src", "GameCult.Geometry", "Shaders")), Path.Combine(temporaryRoot, "GameCult.Geometry"));
foreach (var shaderName in new[] { "D3D12ZyphosPlanet.hlsl", "D3D12ZyphosUmbros.hlsl", "D3D12ZyphosStar.hlsl" })
{
var bytecode = D3D12ShaderCompiler.Compile(Path.Combine(temporaryRoot, shaderName), "D3D12SdfProxyPS", "ps_5_0");

View file

@ -1,13 +1,14 @@
using System.Numerics;
using Aquarium.Engine.Render;
using CultMath;
using GameCult.Geometry;
namespace Aquarium.Engine.Tests;
public sealed class D3D12PlanetaryTopologyParityTests
{
[Fact]
public void QscFaceDirectionsAndInverseCoordinatesMatchCultMathCpu()
public void QscFaceDirectionsAndInverseCoordinatesMatchGameCultGeometryCpu()
{
var cases = new List<TopologyInput>();
foreach (var face in Enum.GetValues<PlanetaryCubeFace>())
@ -41,7 +42,7 @@ public sealed class D3D12PlanetaryTopologyParityTests
[Theory]
[InlineData(PlanetaryProjectionKind.Equirectangular, 2, 3)]
[InlineData(PlanetaryProjectionKind.EqualEarth, 4, 5)]
public void MapProjectionForwardAndInverseMatchCultMathCpu(PlanetaryProjectionKind kind, int forwardMode, int inverseMode)
public void MapProjectionForwardAndInverseMatchGameCultGeometryCpu(PlanetaryProjectionKind kind, int forwardMode, int inverseMode)
{
var projection = new PlanetaryProjectionParameters(kind);
var inputs = new List<TopologyInput>();