fix(rendering): restore retail terrain texture tiling
Carry TerrainTex.TexTiling through the terrain atlas and upload a layer-indexed table to the modern bindless shader so base, overlay, and road textures repeat at retail scale. Keep alpha masks cell-scaled and preserve retail's verified source-level-zero high-detail selection. Add the named-retail pseudocode, WorldBuilder/ACE/ACME cross-reference, adapter conformance tests, and inventory documentation so a future renderer migration keeps the contract. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
84b7d2d7cd
commit
bb5acab9e6
7 changed files with 297 additions and 7 deletions
|
|
@ -64,6 +64,8 @@ public sealed unsafe class TerrainModernRenderer : IDisposable
|
|||
// Cached uvec2-handle uniform locations (matrix uniforms are set by name via Shader.SetMatrix4).
|
||||
private int _uTerrainHandleLoc;
|
||||
private int _uAlphaHandleLoc;
|
||||
private int _uTexTilingLoc;
|
||||
private bool _textureTilingUploaded;
|
||||
|
||||
// Reusable per-frame buffers.
|
||||
private readonly List<int> _visibleSlots = new();
|
||||
|
|
@ -90,6 +92,9 @@ public sealed unsafe class TerrainModernRenderer : IDisposable
|
|||
|
||||
_uTerrainHandleLoc = _gl.GetUniformLocation(_shader.Program, "uTerrainHandle");
|
||||
_uAlphaHandleLoc = _gl.GetUniformLocation(_shader.Program, "uAlphaHandle");
|
||||
_uTexTilingLoc = _gl.GetUniformLocation(_shader.Program, "uTexTiling[0]");
|
||||
if (_uTexTilingLoc < 0)
|
||||
throw new InvalidOperationException("terrain_modern.frag is missing the required uTexTiling uniform.");
|
||||
|
||||
_globalVao = _gl.GenVertexArray();
|
||||
_globalVbo = _gl.GenBuffer();
|
||||
|
|
@ -267,6 +272,7 @@ public sealed unsafe class TerrainModernRenderer : IDisposable
|
|||
// pre-positions terrain to the outdoor landcell, but acdream uses the
|
||||
// unified camera matrix everywhere, so no separate viewpoint divergence can occur.
|
||||
_shader.Use();
|
||||
UploadTextureTilingOnce();
|
||||
_shader.SetMatrix4("uView", camera.View);
|
||||
_shader.SetMatrix4("uProjection", camera.Projection);
|
||||
|
||||
|
|
@ -331,6 +337,34 @@ public sealed unsafe class TerrainModernRenderer : IDisposable
|
|||
// Private helpers
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Upload the texture-array adapter for retail's per-surface repeat count.
|
||||
/// Retail passes <c>TerrainTex::tex_tiling</c> directly to
|
||||
/// <c>ImgTex::TileCSI</c> / <c>ImgTex::MergeTexture</c>
|
||||
/// (`TexMerge::CopyAndTile` 0x00503580, `TexMerge::Merge` 0x005038C0).
|
||||
/// Uniform values persist for the lifetime of this linked shader program,
|
||||
/// so the immutable atlas table is uploaded on its first bound draw.
|
||||
/// </summary>
|
||||
private void UploadTextureTilingOnce()
|
||||
{
|
||||
if (_textureTilingUploaded)
|
||||
return;
|
||||
|
||||
if (_atlas.TilingByLayer.Count != TerrainTextureTilingTable.LayerCapacity)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Terrain tiling table has {_atlas.TilingByLayer.Count} entries; " +
|
||||
$"expected {TerrainTextureTilingTable.LayerCapacity}.");
|
||||
}
|
||||
|
||||
Span<float> values = stackalloc float[TerrainTextureTilingTable.LayerCapacity];
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
values[i] = _atlas.TilingByLayer[i];
|
||||
|
||||
_gl.Uniform1(_uTexTilingLoc, values);
|
||||
_textureTilingUploaded = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Phase U.3: bind the terrain clip UBO to binding=2. Prefers the shared
|
||||
/// <see cref="ClipFrame"/> UBO (<see cref="SetClipUbo"/>); otherwise lazily
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue