fix(render): 修复白屏/黑屏——视图矩阵、UI着色器、网格构建性能与安装目录

- 相机视图矩阵按 R_cam^T·T(-pos) 正确推导(旧布局非正交,非零视角下场景塌缩为灰屏)
- UI 片元着色器改为纹理×颜色(旧实现丢弃纹理 RGB,彩色纹理全白)
- UI 纹理与图集 mipmap:图集补齐 2 次幂、UI 上传不生成 mipmap(NPOT 不完整纹理采样纯白)
- 网格构建持一次读锁(旧实现每格邻居查询各加锁约 40 万次/区块,出生区块迟迟无网格,
  玩家透过脚下的洞看到地下横截面——进游戏黑屏主因);脏区块按距离排序优先构建
- 开启背面剔除(CW 正面):区块边界面向未加载邻居的内侧面不再以暗色出现在视野里
- 出生逻辑:等区块加载后定位地表出生,相机略微俯视
- dev 截图测试:-shot 等待玩家所在 5×5 区块网格就绪再拍(48s 兜底),先测试后打包
- 安装器改为按用户安装到 LOCALAPPDATA(Program Files 无写权限导致启动即崩)
- dev 截图工具独立成 devshot_gl.go
This commit is contained in:
NianGao Dev
2026-08-16 08:33:08 +08:00
parent 6dd5a8122a
commit fc151e7c07
9 changed files with 207 additions and 50 deletions

View File

@@ -14,7 +14,7 @@ import (
// Build 打包纹理键列表为图集。
// resolve:纹理键 → PNG 文件路径;缺失纹理跳过(键不进入 uv 表,运行时用占位纹理)。
// 列数取「大于等于根号的整数」,使图集接近正方形(GPU 友好)。
// 尺寸取 2 的次幂(mipmap 兼容:非 2 次幂图集在部分驱动上 GenerateMipmap 失败会致纹理不完整)。
func Build(resolve func(key string) (string, bool), keys []string, tileSize int) (image.Image, map[string]image.Rectangle, error) {
if len(keys) == 0 {
return nil, nil, fmt.Errorf("atlas.Build: 纹理列表为空")
@@ -27,6 +27,9 @@ func Build(resolve func(key string) (string, bool), keys []string, tileSize int)
cols++
}
rows := (len(keys) + cols - 1) / cols
// 补齐到 2 的次幂(mipmap 要求)
cols = nextPow2(cols)
rows = nextPow2(rows)
img := image.NewRGBA(image.Rect(0, 0, cols*tileSize, rows*tileSize))
uv := make(map[string]image.Rectangle, len(keys))
@@ -50,6 +53,15 @@ func Build(resolve func(key string) (string, bool), keys []string, tileSize int)
return img, uv, nil
}
// nextPow2 返回不小于 n 的最小 2 次幂。
func nextPow2(n int) int {
p := 1
for p < n {
p <<= 1
}
return p
}
// loadPNG 解码 PNG。
func loadPNG(path string) (image.Image, error) {
f, err := os.Open(path)