Help us shape the future of Go! Take the 2026 Go Developer Survey

worldchunk

package
v0.0.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2026 License: MIT Imports: 14 Imported by: 0

README

Chunked world contract

world/chunks@1 keeps one complete compiled world in the root level and stores immutable render assets in independently fetched child KLD modules. It does not change compiled world versions 1–3, their bytes, or the 256-sector limit. Larger topology requires a separate versioned contract.

The root retains @world/main, authored contents, lighting, sector connections, shared albedo/material atlases and @world/chunks/catalog. The catalog contains global sector ownership, exact child SHA-256 and module byte size, packed mesh scalar size, decoded straight RGBA RNM image size, bounds and conservative candidate chunks for every sector. SDK 0.0.11 also stores BakedLights, the sorted unique union of authored source indexes from completed child prebakes. Hosts remove these sources from direct-light slots before any child is loaded. Every removed source must be steady, inside a physical component, and covered by baked descriptors throughout that component. Child metadata uses kartyWorldChunk, chunkID and geometrySha256; root metadata uses kartyWorldChunks. Child modules contain @world/chunks/mesh and, when enabled, the ordinary lightmap layout, completed prebake manifest and RNM QOI entries. Shared textures are referenced by their root material identity, without copies.

In the unreleased SDK 0.0.11 candidate, the catalog, mesh and shadow entries use fixed binary records. Earlier candidate JSON chunk payloads are rejected and must be rebuilt. TOML/YAML authoring and the established world, lightmap and level-envelope metadata formats retain their existing contracts.

Before instantiating a downloaded child, hosts call level.ValidatePassiveModule. It accepts only exact level.WrapModule output, including its bounded initial memory, three constant ABI functions and one validated data envelope. Extra imports, start functions, loops, memory growth, custom sections and noncanonical encodings are rejected without executing Wasm. Input remains bounded to 32 MiB. Hosts reserve the input plus the bounded canonical-module and data-construction buffers during this check. Legacy level execution retains its existing contract.

Plan grows connected groups deterministically in sector order through ordinary coincident reciprocal portals. It never grows across a transformed or one-way edge. Such an edge's endpoints can still share a chunk when an ordinary route connects them. Each proposal must fit the declared mesh scalar budget and the requested lightmap density, page capacity and padding. Defaults are 4 MiB mesh, 8 MiB encoded mesh, 256 sectors, and existing lightmap defaults. MaxSectors is a secondary limit. A single oversized sector fails with its identity; the planner never lowers density. Encoded mesh entries retain the 8 MiB level entry bound. Builders must additionally check the complete baked child module against the encoded budget and the existing 16 MiB envelope / 32 MiB module bounds. NoLightmap supports mesh-only levels without inventing a lighting recipe. Its planner prepares surfaces and physical-component junctions once, emits each sector and solid once, and tests growing groups with exact final scalar and binary byte counts. Liquid subdivision factors still come from the complete physical patch. Final meshes retain the standalone compiler's bytes and full semantic/coverage validation; preparation does not require the complete world's geometry to fit a single child mesh. This path performs no bake and creates no lightmap layout, image or recipe.

For chunks, Options.Lightmap.PageSize is the maximum page size. A configured 1024 maximum (also the default) first attempts a 512 page for each selected receiver group at the same density and padding. It retries 1024 only when those charts exceed page capacity. A configured 512 maximum remains a hard limit. The chosen layout defines the mesh's RNM UVs and exact LightmapBytes; the full geometry digest, global bindings, component lighting context and recipe are retained. Legacy worldlightmap.Compile and direct CompileReceivers keep fixed page sizes. worldlightmap.ErrPageCapacity also wraps ErrLayout; malformed geometry, options and recipes never trigger the larger-page retry.

Options.SectorGroups optionally preserves authored areas during build-time grouping. A nonnil list must assign every global sector an integer group ID in [0,256). The planner grows only through ordinary adjacency within the seed's group; disconnected areas or hard budget limits still produce separate chunks. Nil retains the original budget-only partitioning. Groups are producer inputs and do not add catalog, child or runtime fields. They affect mesh ownership, while visibility candidates and lighting transport still follow the complete topology and physical component across authored-area boundaries.

Candidate SDK 0.0.12 adds Options.CompactLightmaps, an optional build policy used by environment variant cartridges. After ordinary greedy planning, it tries exact page merges of complete receiver groups within one ordinary physical component, ordered by occupied chart area. Each accepted merge retains the sector, decoded/encoded mesh, page, texel and complete mesh-validation bounds; the total decoded lightmap reservation cannot increase. Authored sector groups remain boundaries. Resulting sector/chunk indexes and visibility candidates are rebuilt deterministically. The default planner produces the same output.

The candidate accepts nonadjacent receiver sectors connected through intervening ordinary sectors assigned to other chunks. Both mesh and catalog validators traverse the complete physical component with buffers bounded by the validated world sector count. Every selected sector must belong to that component; transformed portals and disconnected spaces remain rejected. This widens receiver-group validation without changing wire fields. Produced environment cartridges require world/lightmaps-environment-variants@1, so older hosts reject the unsupported feature before mounting these resources. See the CLI's versioned environment-lightmap-variants-v1 decision for this producer policy.

Candidate sets are directed graph reachability, including transformed links. They are a conservative worst-case visibility superset, not geometric portal PVS pruning. A connected map's candidate set can include every chunk, but it is an optional prefetch hint and does not require those assets to remain resident. Required residency follows actual runtime portal traversal and aperture clipping. An open view can still expose every chunk at once, so this contract does not promise bounded residency for an open world. Future producer versions can introduce conservative aperture pruning. Candidate storage is bounded by the existing sector bound. A runtime retains the complete topology and expands actual portal paths with accumulated transforms and separate apertures; a chunk is fetched once but can appear in several render views.

Mesh schema karty.world-chunk-mesh@1 contains final float32 authored positions, primary/frame/secondary UVs, RNM UVs, wave UVs, uint32 triangle indices and per-triangle semantic/material bases and global owner identities. It uses a center fan after inserting all collinear physical-component junctions, so separately built chunks retain the same boundary vertices. Host preparation may pack existing triangles for its GPU, but must never triangulate polygons or tessellate loaded geometry. Winding uses the stored float32 positions, and fan triangles with exactly zero stored area are omitted. Complete receiver coverage is still validated. Bounds are exact minima/maxima of stored positions. DecodedMeshBytes counts 84 bytes per vertex, 4 per index and 220 fixed scalar bytes per triangle; it excludes the binary header/ownership lists, Go object padding and a host's GPU representation. Hosts must account for their upload representation separately. LightmapBytes is zero or exactly 3 times page width times page height times 4; RGBA16F GPU storage requires twice that image size in addition to CPU pixels.

Candidate SDK 0.0.12 retains finite upper sky masks between outdoor portal sectors with different ceiling heights, matching the ordinary renderer. Both plain and compiled-frame upper spans carry Sky=true and Chart=-1; physical lower spans and indoor lintels remain opaque receivers. Complete mesh validation requires the sky-mask coverage and correct flags, rejecting missing or mistagged upper spans. These render masks remain absent from lightmap transport and shadow casters, so existing layout and condition pixels retain their identities. The CLI complete-chunk cache revision 3 invalidates earlier mesh containers; pixel cache identities and released manifests remain unchanged. Hosts reserve both before decoding, rather than estimating from compressed QOI. The mesh also binds materials and authored projections with surface_sha256, using the public offline surface digest independently of its topology digest. Bound displaced liquids additionally hash the karty.world-chunk-liquid-tessellation@1 domain, that digest, and effective material/frequency/surface-amplitude inputs sorted by material. Runtime timing, opacity and shading-only wave controls do not change the rest mesh identity.

Every decoder checks the exact binary version, length, reserved zeros, scalar enums/flags, full document identity, complete owner lists, all final indices and attributes, triangle winding, bounds and complete receiver area coverage before publication. ValidateMeshBinding additionally checks every semantic chart and affine RNM coordinate against the child's layout. Catalog validation recomputes the conservative reachability sets and rejects omissions. Chunk identities never create new gameplay actor identities.

ValidateBakedSelection(catalog, chunkID, document, layout) binds a completed child recipe to exactly the parent's source union filtered to the child's ordinary physical component. A mere subset is rejected because removing a source without its coefficients would lose lighting. Recipe ordering remains part of the existing prebake digest; membership does not impose a different order. Transformed portals remain physical lighting boundaries. Mesh-only descriptors accept no lightmap layout.

Mesh validation also checks vertices against their authored receiver planes and domains. Supplied triangle edges cancel internally; their remaining directed boundary must cover every authored boundary interval once, including separate wall strips. Equal-area duplicate triangles, overlaps and holes are rejected without reconstructing or subdividing triangles. Authored projection bases, secondary weights and frame metadata are checked exactly; primary, secondary, frame and wave UVs are checked against their affine projections with bounded float32 packing/interpolation tolerance applied independently per coordinate. A large authored X never relaxes a precise Z plane. Unused attribute slots remain zero.

All array counts and the exact complete byte length are checked before typed slice allocation, using bounded integer arithmetic on native, 386 and Wasm. There is no JSON parsing or re-encoding for these payloads. On js/wasm, fixed record decoding and mesh validation periodically sleep for one millisecond to return control to JavaScript; native execution does not sleep. Actual Wasm tests check JavaScript timer progress; they do not measure graphics frame rate.

Binary records

Every integer and IEEE-754 float is little-endian. Hashes contain 32 raw SHA-256 bytes. Public schema strings are implied by the magic and version, rather than stored as strings. All payloads remain bounded to 8 MiB, and trailing bytes are rejected. Surface enums are 1=sector-floor, 2=sector-ceiling, 3=sector-wall, 4=solid-top, 5=solid-bottom, 6=solid-side; other values are invalid. Boolean words must be exactly zero or one. Mapping counts and coverage occupy uint32 words and are checked before conversion to their public uint8 fields. All floating-point attributes must be finite and pass their semantic checks.

The catalog has a 64-byte header:

Offset Type Value
0 4 bytes KCC2
4 uint16 version 2
6 uint16 header size 64
8 uint32 chunk count
12 uint32 global sector count
16 uint32 total candidate chunk IDs
20 uint32 baked source index count
24 32 bytes geometry SHA-256
56 uint64 reserved zero

All 120-byte chunk descriptors follow the header. Each stores ID, sector count, solid count and reserved zero as four uint32 words; child SHA-256 at offset 16; module size, decoded mesh bytes and decoded lightmap bytes as uint64 at offsets 48, 56 and 64; and six float64 bounds at offset 72. The remaining payload is, in order: every chunk's sector int32 list, every chunk's solid int32 list, the global sector-to-chunk uint32 list, then one candidate list per global sector. Each candidate list is a uint32 count followed by uint32 chunk IDs. The final array contains sorted unique int32 baked source indexes, bounded to 4,096 entries and to the root world's source count. Version-1 KCC1 catalogs are rejected and must be rebuilt; KCM1 meshes and KCS1 shadow proxies retain their version-1 bytes. The complete baked-index list is scanned before any catalog slice allocation, including its last record. Descriptor ownership totals and candidate totals must fit their public bounds and match the complete payload length before allocation.

The mesh has a 144-byte header:

Offset Type Value
0 4 bytes KCM1
4 uint16 version 1
6 uint16 header size 144
8 5 uint32 sector, solid, vertex, index, triangle counts
28 uint32 reserved zero
32 32 bytes geometry SHA-256
64 32 bytes surface SHA-256
96 6 float64 bounds

The body stores sector int32 IDs, solid int32 IDs, 84-byte vertex records, uint32 indices and 220-byte triangle records. A vertex contains 21 float32 values in this order: position (3), primary UVs (6), band UV (2), secondary UVs (6), lightmap UV (2), wave UV (2). A triangle stores fields in public struct order: sector/solid int32, surface uint32 enum, edge int32; normal/tangent/ bitangent (9 float32); material and mapping count uint32; weights (3 float32); three projection bases (18 float32); band material/coverage/repeatU/repeatV uint32 and basis (6 float32); secondary material uint32, strength float32, mapping count uint32 and weights (3 float32); sky/outdoor uint32 and chart int32. Each basis stores tangent followed by bitangent. Index and vertex counts must both equal three times the triangle count.

The shadow header is 80 bytes: KCS1, uint16 version 1, uint16 header size 80, uint32 triangle count, uint32 reserved zero, geometry SHA-256 at offset 16 and surface SHA-256 at offset 48. Each 68-byte triangle stores positions (9 float32), normal (3 float32), material uint32, sector/solid int32, surface uint32 enum and edge int32. Empty shadow arrays are valid when the world has no opaque caster geometry; mesh chunks remain nonempty.

Lightmap receiver algorithm 2 selects global sectors and solids while retaining the entire ordinary physical component for shadow and diffuse transport. Charts merge only through selected adjacent sectors. Lights in other physical spaces are excluded; a selected space without a local light stores covered black. Transformed portals are explicit lighting boundaries, without light transport through them. Chunk lightmaps preserve authored RNM bases across portal views. Volumes touching multiple physical spaces are rejected because authored XY overlap cannot establish their physical-space ownership.

Static frames, secondary materials, sky masks and material animations preserve their public semantics. Displaced horizontal upward liquid faces are tessellated offline with karty.world-chunk-liquid-tessellation@1. The two authored sine waves choose a barycentric subdivision factor from their frequency, amplitude and primary UV spans, targeting 0.005 metres interpolation error where the patch budget permits. The factor is capped at 32. A connected subtle-wave patch has a 256-triangle target; amplitude above 0.05 metres raises the target with amplitude and the square root of frequency, capped at 1024. Existing source triangles are always retained, even if their count already exceeds that target. The final chunk's 65536-triangle limit and all decoded/encoded budgets remain hard bounds.

The compiler plans the complete ordinary physical component's liquid patches before selecting chunk owners. Shared edges use one factor and canonical endpoint interpolation, so independently compiled neighboring chunks have matching boundary samples. Disconnected pools refine independently. Every material, secondary, band, wave and RNM UV coordinate is interpolated with the rest positions; semantic owners and differential bases remain unchanged. Hosts only pack these final triangles. They never run the tessellator. Validation checks authored rest elevations, affine wave coordinates, complete rest area and every affine RNM chart coordinate without generating geometry.

New chunked roots normally also contain @world/chunks/shadow, schema karty.world-chunk-shadow@1. This immutable asset holds the entire world's opaque authored rest caster geometry independently of render-chunk residency. It uses a corner fan without material seam junctions, center vertices or liquid subdivision, retaining the ordinary portal-opening profiles and static solid faces. Sky, liquid materials with opacity below one and gameplay actors are excluded. Wall-frame material bands retain the underlying wall/opening caster shape, matching the existing shadow path.

The proxy has at most 8192 triangles, each with final float32 positions, normal, material and global semantic owner. Compilation returns ErrShadowBudget above that bound. Builders may omit this optional asset only for that typed budget condition, preserving the larger render-chunk geometry bound. A host must reject requested shadows when the proxy is absent; missing proxy data never silently enables partial casters. DecodedShadowBytes counts 68 scalar bytes per triangle; hosts separately account for their owned object representation and GPU position/normal/index buffers. The entry remains bounded to 8 MiB before decoding, and the decoder checks the triangle record count before allocating owned records. It verifies source digests and the complete canonical authored polygon-corner sequence without creating a mesh. The surface digest binds the ordinary offline surface identity and sorted effective transparent-liquid material IDs. Older candidate roots without the entry remain valid with the shadow path disabled. A proxy does not extend shadow topology support: transformed/directed portal spaces and multiple ordinary components still need a separately versioned shadow contract.

Optional solid receiver ownership, version 1

Candidate SDK 0.0.12 adds build-only Options.SolidOwners. Nil retains the existing first-overlap policy. An explicit list must contain one valid sector index per static solid; each chosen sector must conservatively intersect that solid in XY and belong to its unambiguous ordinary physical component. Missing, out-of-range, nonintersecting and ambiguous assignments fail before planning. Geometry, density, page limits and chunk wire formats remain unchanged.

BalancedSolidOwners(document, lightmapOptions) supplies an optional deterministic policy for buildings with several overlapping roofs, cornices and decorations. It considers largest receiver chart sets first, then tries exact packing into eligible sectors ordered by occupied texels. Every single-sector layout must fit the requested page; inability to place a solid is an explicit page-capacity error. It never lowers density or moves geometry. The CLI enables this policy for environment lightmap variants so large decorative structures do not all consume the first observation sector's receiver page.

Within this opt-in policy, narrow grounded solids then prefer the first exact-fitting overlapping sector in authored order. Eligibility uses geometry and the current receiver floor: longest XY extent at least 2 units and four times the shortest, shortest extent at most 0.6, height at most 1.25, top at most 1 above that floor, and bottom reaching the floor or buried. IDs and material names have no effect. Other balanced owners remain unchanged. Complete owner validation still rejects disconnected or transformed physical membership; if the concentration cannot fit, the original balanced list is retained. This is a bounded candidate 0.0.12 build heuristic, without a wire or default Plan ownership change.

Documentation

Overview

Package worldchunk defines build-generated render assets and conservative streaming visibility for one logical world. Geometry stays in authored space; a host may show one immutable asset through several transformed portal paths.

Index

Constants

View Source
const (
	Schema           = "karty.world-chunks@1"
	MeshSchema       = "karty.world-chunk-mesh@1"
	Feature          = cartridge.FeatureWorldChunksV1
	CatalogEntryName = "@world/chunks/catalog"
	MeshEntryName    = "@world/chunks/mesh"
	MetadataKey      = "kartyWorldChunks"
	ChunkMetadataKey = "kartyWorldChunk"
	MaxEncodedSize   = level.MaxEntrySize
	MaxEncodedBytes  = level.MaxEnvelopeSize * 2
	MaxVertices      = 196608
	MaxTriangles     = MaxVertices / 3
)
View Source
const (
	ShadowSchema         = "karty.world-chunk-shadow@1"
	ShadowEntryName      = "@world/chunks/shadow"
	MaxShadowEncodedSize = MaxEncodedSize
	MaxShadowTriangles   = 8192
)

Variables

View Source
var ErrChunk = errors.New("world chunk is invalid")
View Source
var ErrShadowBudget = fmt.Errorf("opaque caster triangle budget: %w", ErrChunk)

ErrShadowBudget identifies a valid world whose complete opaque caster asset exceeds the supported bound. Producers may omit this optional root asset for render-only worlds; malformed source and other errors must still fail.

Functions

func BalancedSolidOwners added in v0.0.14

func BalancedSolidOwners(document world.Document, options worldlightmap.Options) ([]int, error)

BalancedSolidOwners is an opt-in build policy for decorative structures that overlap several receiver sectors. Largest chart sets are placed first, then assigned to the least occupied eligible sector whose exact receiver layout fits. Narrow low solids grounded at the receiver floor then prefer the first exact-fitting owner so perimeter details do not fragment adjacent pages. It never changes density, page limits, geometry or physical components. The returned complete list can be supplied as Options.SolidOwners. The default Plan ownership remains unchanged.

func DecodedMeshBytes

func DecodedMeshBytes(mesh Mesh) uint64

DecodedMeshBytes is the packed scalar array size, independent of Go padding: 21 float32 attributes per vertex, uint32 indices and 55 scalar words per triangle (including fixed identity/flags slots). It excludes the binary header and sector/solid ownership lists.

func DecodedShadowBytes

func DecodedShadowBytes(proxy ShadowProxy) uint64

DecodedShadowBytes counts 12 float32 coordinates and five fixed scalar identity words per triangle. Hosts account for their object and GPU storage separately, rather than estimating from the encoded payload size.

func EncodeCatalog

func EncodeCatalog(catalog Catalog, document *world.Document) ([]byte, error)

func EncodeMesh

func EncodeMesh(mesh Mesh, document *world.Document) ([]byte, error)

func EncodeShadowProxy

func EncodeShadowProxy(proxy ShadowProxy, document *world.Document) ([]byte, error)

func GeometryDigest

func GeometryDigest(document *world.Document) (string, error)

func ValidateBakedSelection

func ValidateBakedSelection(catalog *Catalog, chunkID int, document *world.Document, layout *worldlightmap.Layout) error

ValidateBakedSelection binds a child's source membership to its parent catalog. The recipe must contain exactly the parent union filtered to this ordinary physical component; ordering remains part of the prebake identity. A nil layout is valid only for a descriptor with no lightmap.

func ValidateCatalog

func ValidateCatalog(catalog *Catalog, document *world.Document) error

func ValidateMesh

func ValidateMesh(mesh *Mesh, document *world.Document) error

func ValidateMeshBinding

func ValidateMeshBinding(mesh *Mesh, layout *worldlightmap.Layout) error

ValidateMeshBinding checks every final RNM coordinate against its semantic chart. Geometry validation is separate and never regenerates triangles.

func ValidateShadowProxy

func ValidateShadowProxy(proxy *ShadowProxy, document *world.Document) error

ValidateShadowProxy checks each supplied triangle directly against its canonical authored polygon corners. It checks complete semantic coverage and winding without constructing a mesh or any new triangle/vertex arrays.

Types

type Band

type Band struct {
	Material uint32
	Coverage uint8
	RepeatU  bool
	RepeatV  bool
	Basis    Basis
}

type Basis

type Basis struct {
	Tangent   [3]float32
	Bitangent [3]float32
}

type Catalog

type Catalog struct {
	Schema         string
	GeometrySHA256 string
	Chunks         []Chunk
	SectorChunks   []int
	// Candidates is directed graph reachability, a worst-case visibility
	// superset. It is deduplicated by immutable chunk ID, not by portal path.
	Candidates [][]int
	// BakedLights is the sorted unique union of authored light indexes carried
	// by completed child prebakes. Hosts partition these sources before loading
	// children; they never consume runtime direct-light slots.
	BakedLights []int
}

func DecodeCatalog

func DecodeCatalog(encoded []byte, document *world.Document) (Catalog, error)

type Chunk

type Chunk struct {
	ID            int
	Sectors       []int
	Solids        []int
	ContentSHA256 string
	Size          uint64
	MeshBytes     uint64
	LightmapBytes uint64
	Bounds        [6]float64
}

type Mesh

type Mesh struct {
	Schema         string
	GeometrySHA256 string
	SurfaceSHA256  string
	Sectors        []int
	Solids         []int
	Vertices       []Vertex
	Indices        []uint32
	Triangles      []Triangle
	Bounds         [6]float64
}

func CompileMesh

func CompileMesh(document world.Document, sectors, solids []int, layout worldlightmap.Layout) (Mesh, error)

CompileMesh triangulates immutable authored receiver polygons offline. Every boundary vertex, including collinear junctions, gets its own triangle edge. The runtime reads final arrays and never constructs or tessellates a face.

func DecodeMesh

func DecodeMesh(encoded []byte, document *world.Document) (Mesh, error)

type Options

type Options struct {
	MaxMeshBytes    uint64
	MaxEncodedBytes uint64
	MaxSectors      int
	// Lightmap.PageSize is a maximum: 1024 (or zero) first tries 512, then
	// retries 1024 only when the receiver charts exceed page capacity.
	Lightmap   worldlightmap.Options
	NoLightmap bool
	// SectorGroups is an optional build-only authored-area preference. Nil keeps
	// budget-only grouping. Otherwise every global sector has an ID in [0,256).
	// Ordinary connectivity and hard budgets can still split an authored area.
	SectorGroups []int
	// SolidOwners optionally assigns every static solid to one overlapping
	// receiver sector. Nil preserves first-overlap ownership. It is build policy
	// only; complete bounds and ordinary-space validation remain mandatory.
	SolidOwners []int
	// CompactLightmaps optionally repacks complete valid receiver groups within
	// one ordinary physical component. It preserves all hard budgets and never
	// increases their total decoded lightmap cost. Nil/default policy is unchanged.
	CompactLightmaps bool
}

type PlanResult

type PlanResult struct {
	Chunks       []PlannedChunk
	SectorChunks []int
	Candidates   [][]int
}

func Plan

func Plan(document world.Document, options Options) (PlanResult, error)

Plan grows connected chunks deterministically in authored sector order. A budget failure never lowers density. An oversized single sector is an error. MaxEncodedBytes limits the mesh entry here; builders must also check the final child module including compressed lightmaps against that exact byte budget. Lightmap.PageSize is a maximum here: a 1024 maximum first tries a 512 page at identical density and padding, then retries 1024 only on page capacity.

type PlannedChunk

type PlannedChunk struct {
	ID              int
	Sectors, Solids []int
	Mesh            Mesh
	Layout          worldlightmap.Layout
	Bounds          [6]float64
	MeshBytes       uint64
	LightmapBytes   uint64
}

type Secondary

type Secondary struct {
	Material     uint32
	Strength     float32
	MappingCount uint8
	Weights      [3]float32
}

type ShadowProxy

type ShadowProxy struct {
	Schema         string
	GeometrySHA256 string
	SurfaceSHA256  string
	Triangles      []ShadowTriangle
}

ShadowProxy is one bounded root-owned caster asset, independent of render chunk residency. It contains authored opaque rest geometry, without material seam junctions, center vertices, displaced-liquid subdivision or actors.

func CompileShadowProxy

func CompileShadowProxy(document world.Document) (ShadowProxy, error)

CompileShadowProxy triangulates the complete opaque authored caster surfaces offline. Corner fans preserve legacy shadow semantics: static wall-frame UV bands do not change the underlying opening, sky has no caster, and a liquid material with opacity below one does not cast an opaque shadow.

func DecodeShadowProxy

func DecodeShadowProxy(encoded []byte, document *world.Document) (ShadowProxy, error)

type ShadowTriangle

type ShadowTriangle struct {
	Positions   [3][3]float32
	Normal      [3]float32
	Material    uint32
	Sector      int
	Solid       int
	Surface     string
	SurfaceEdge int
}

type Triangle

type Triangle struct {
	Sector          int
	Solid           int
	Surface         string
	SurfaceEdge     int
	Normal          [3]float32
	Tangent         [3]float32
	Bitangent       [3]float32
	Material        uint32
	MappingCount    uint8
	Weights         [3]float32
	ProjectionBases [3]Basis
	Band            Band
	Secondary       Secondary
	Sky             bool
	Outdoor         bool
	Chart           int
}

type Vertex

type Vertex struct {
	Position    [3]float32
	UV          [3][2]float32
	BandUV      [2]float32
	SecondaryUV [3][2]float32
	LightmapUV  [2]float32
	WaveUV      [2]float32
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL