Rendering Notes
This document describes the current Stargate rendering implementation. The renderer is functional and visually close to the intended direction, but it is still a procedural prototype rather than a final model/rendering architecture.
Renderer Registration
LanteaCraftClient.registerRenderers registers:
ModBlockEntities.STARGATE_BASE -> StargateBaseRenderer
Only the base block has a block entity. The full rendered Stargate ring is therefore anchored to the base block entity, not to each individual frame block.
StargateBaseRenderer Responsibilities
StargateBaseRenderer currently owns all assembled-gate visual rendering:
procedural ring shell geometry
glyph ring overlay
chevron geometry
chevron lock lighting
ring rotation during dialing
active chevron state while connected
bottom-row camouflage blocks
event horizon disc
kawoosh burst
expanded render bounds/culling behavior
The normal stargate_base, stargate_ring, and stargate_chevron block models still exist, but the assembled gate's main visual identity is the BER.
Coordinate System
The renderer exits early unless the base block has assembled=true.
For assembled gates it:
translates to the base block center and raises the origin to the ring center:
rotates around Y by the negative base facing yaw
draws the procedural ring in local XY with depth on local Z
Important dimensions:
Textures And RenderTypes
Frame/ring/chevrons:
textures/tileentity/stargate.png
RenderType.entitySolid
Glyph ring:
textures/tileentity/stargate_glyphs.png
RenderType.entityCutout
Event horizon/kawoosh:
textures/fx/eventhorizon.png
RenderType.entityTranslucent
The frame texture is treated as a 16×16 tile atlas inside a 1024×1024 image. Tile constants select areas for outer ring, face, inner ring, unlit chevrons, and lit chevrons.
Shell Geometry
renderShell builds the ring from 38 radial segments.
For each segment it emits quads for:
outer cylindrical wall
inner cylindrical wall
center face band
moving/glyph ring band
front bevels
rear bevels
Lighting is forced to LightTexture.FULL_BRIGHT for the Stargate mesh, so the ring remains readable independent of world lighting.
Prototype Quality
Normals are currently simplified as (0,0,1) for all vertices.
Geometry is hand-authored in code and not backed by baked models.
Ring dimensions are tuned visually, not derived from the legacy model source as a formal port.
Glyph Ring And Dialing Rotation
renderGlyphRing draws a textured annular band over the moving ring area.
During dialing:
dialingState reads StargateBaseBlockEntity.dialingAddress
each address symbol maps to an angle using the legacy 38-glyph alphabet
ring rotation lerps to the target symbol angle
easing is cosine-based
When connected and not dialing:
Prototype Quality
The renderer has its own copy of the legacy glyph string instead of sharing StargateAddress.LEGACY_GLYPHS.
The glyph ring is texture-coordinate based, not individual symbol meshes.
Current behavior supports up to 9 chevron lock slots visually, but the gameplay address is currently 7 symbols.
Chevron Rendering
renderChevrons places nine chevrons around the ring.
Chevron constants:
count: 9
angular spacing: 360 / 9
lock order: { 8, 7, 6, 3, 2, 1, 0, 5, 4 }
Each chevron:
is rendered as two wedge-like front quads
moves slightly when locked
overlays lit quads when lock > 0
uses the lit chevron tile from stargate.png
Implemented
Chevrons light progressively during dialing.
Lit chevrons remain active while the gate is connected.
The destination/incoming gate is also put into a connected visual state by the dialing payload.
Prototype Quality
Chevron order is hand-tuned and should be checked against legacy/show expectations.
The final chevron placement/order was recently adjusted and needs another in-game pass.
Chevron geometry is stylized and procedural, not a model import.
Event Horizon
The event horizon is drawn only when:
renderEventHorizon draws:
The steady puddle:
is a procedural circular mesh
uses 10 radial bands and 38 angular segments
uses translucent event horizon texture
applies small Z displacement from horizonRipple
animates UVs through animatedU and animatedV
The puddle does not spin as a whole. It ripples by changing per-vertex Z offset and UV sampling over time.
Prototype Quality
It is a flat-ish translucent mesh with ripple displacement, not a fluid simulation.
It has no collision/portal surface block.
It renders from the base BER, so the base BE is the render anchor.
Alpha/depth sorting may need testing with terrain, water, and other translucent objects.
Kawoosh
The kawoosh is also procedural.
Current behavior:
lasts 18 ticks
starts immediately after dialing duration completes
expands from the center
protrudes forward along local Z
fades out as progress approaches 1
uses the same event horizon texture/render type
Core methods:
renderKawoosh
kawooshDisplacement
kawooshProfile
The shape is a center-heavy protrusion plus a smaller rim bulge and animated wave.
Prototype Quality
The kawoosh is visually tuned, not physically or canonically accurate.
It has no gameplay damage/destruction effect.
It does not currently mask, clip, or interact with world blocks/entities.
Timing is tied to BE dialing state, not an explicit server event packet.
Needs Testing
Whether the kawoosh appears exactly once on fresh connection.
Whether it incorrectly replays after chunk reload, dimension travel, or client reconnect.
Visual quality at low FPS and high latency.
Bottom Camouflage Rendering
Bottom-row camouflage is stored on StargateBaseBlockEntity as a single BlockState.
renderBottomCamouflage renders seven copies of that block across local x=-3..3, at the bottom row of the gate.
The renderer uses Minecraft's block renderer:
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(...)
Each rendered camouflage block is slightly scaled up (1.004) to reduce fighting with existing blocks/models.
Prototype Quality
Only one camouflage state is stored for the whole bottom row.
The state is reduced to the target block's default state, so orientation/properties are not preserved.
There is no clearing interaction yet besides code support on the BE.
Culling And Bounds
The renderer overrides:
shouldRenderOffScreen → true
getViewDistance → 128
shouldRender → distance check against expanded gate bounds
getRenderBoundingBox → expanded AABB around the base
The bounds are:
new AABB(basePos).inflate(5, 5, 5).expandTowards(0, 6, 0)
This was added because the gate mesh is much larger than the base block and otherwise disappears when the base block leaves the camera frustum.
Prototype Quality
The bounds are intentionally generous.
shouldRenderOffScreen=true helps avoid base-frustum clipping but can increase render cost.
More precise bounds could be computed per facing.
Sound-Driven Visual State
Visual state is primarily derived from StargateBaseBlockEntity:
dialingAddress
dialingStartGameTime
dialingDurationTicks
connectedAddress
Server-side BE tick plays sounds:
roll on dialing start
chevron lock as each symbol progresses
open after dialing completes
ambient while connected
close when connection clears
The renderer does not play sounds. It only visualizes the same BE state.
Known Risks And TODOs
Current Risks
The renderer uses a copied legacy glyph string instead of the central address constant.
The full ring depends on one block entity. If the base BE is missing or desynced, the whole visual disappears.
Full-bright rendering may not match desired lighting once final art direction settles.
Translucent event horizon sorting needs more testing.
Geometry normals are placeholder-quality.
Render cost should be profiled with many gates visible.
TODO Candidates
Share the glyph alphabet constant with StargateAddress.
Split rendering helpers into smaller classes once behavior stabilizes.
Add a proper model/baked-geometry path if procedural maintenance gets painful.
Add explicit client event/state for kawoosh instead of deriving it from persisted dialing time.
Add configurable render distance/detail for active gates.
Add a clear camouflage interaction and preserve more blockstate properties if needed.
Revisit chevron lock order against legacy implementation.