summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/SceneDetail.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-28 20:58:24 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-28 20:58:24 +0800
commite46f1ddda07fc9c3d2617663ed28a3d1391c198b (patch)
tree01c5b074622a8d5ea58f6b11308165145c71b8d8 /src/LivingVillage.Desktop/SceneDetail.fs
parentf571b56359e4bb152b414a61527c4e9c6ef4cd53 (diff)
downloadliving-village-e46f1ddda07fc9c3d2617663ed28a3d1391c198b.tar.gz
p47: 整改 — 倒影改暖色垂直光柱(gap-skip穿桥面落水面,最长≥3格)+近景接入倒影+近景屋顶受光/背光双档luma
Diffstat (limited to 'src/LivingVillage.Desktop/SceneDetail.fs')
-rw-r--r--src/LivingVillage.Desktop/SceneDetail.fs74
1 files changed, 57 insertions, 17 deletions
diff --git a/src/LivingVillage.Desktop/SceneDetail.fs b/src/LivingVillage.Desktop/SceneDetail.fs
index c51c47a..50313ac 100644
--- a/src/LivingVillage.Desktop/SceneDetail.fs
+++ b/src/LivingVillage.Desktop/SceneDetail.fs
@@ -17,14 +17,24 @@ module SceneDetail =
x >= 0 && x < map.Width && y >= 0 && y < map.Height
&& map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water
+ /// 可倒影水面:河面(Water)与水田(PaddyField,同样走水面动画渲染)。
+ let isWaterSurface (map: MapGen.Result) (x: int) (y: int) : bool =
+ x >= 0 && x < map.Width && y >= 0 && y < map.Height
+ && (map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water
+ || map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.PaddyField)
+
// ---------------- 河道水面倒影 ----------------
- let reflectionMaxAlpha = 128
- let reflectionRange = 3
+ let reflectionMaxAlpha = 200
+ let reflectionRange = 4
+ /// 倒影射线允许穿过的非水面格数(如灯笼所立的桥面/岸沿),使「桥下红灯笼」的倒影
+ /// 仍落在其正下方的河面,而不是被桥面格截断。
+ let reflectionGap = 3
- /// 倒影 alpha 随离光源距离递减;到 0 即止,绝不留下硬块。
+ /// 倒影 alpha 随离光源距离递减;最低仍保持 96,保证整条暖色光柱在蓝灰水面上
+ /// 始终可辨(不会淡到被水面波纹吞掉)。
let reflectionAlphaAt (distance: int) : int =
- max 0 (reflectionMaxAlpha - distance * 34)
+ max 96 (reflectionMaxAlpha - (distance - 1) * 26)
/// 倒影微抖:复用 waterFrameTickAt 的 3 相位,映射到 -1 / 0 / +1 像素水平位移。
let reflectionWobbleAt (tick: int64) (x: int) (y: int) : int =
@@ -33,20 +43,50 @@ module SceneDetail =
| 1 -> 0
| _ -> 1
- /// 岸上光源:桥头灯笼 + 主路石灯笼 + 门口红灯笼,去重后即倒影源。
+ /// 光源类型:桥头灯笼 / 主路石灯笼 / 门口红灯笼。倒影按类型着色。
+ type LightKind =
+ | BridgeLantern
+ | RoadLantern
+ | RedLantern
+
+ /// 岸上光源(含类型),按位置去重。
+ let lightSources (map: MapGen.Result) : (int * int * LightKind) list =
+ let bridge = VillageArt.bridgeLanternTiles map |> List.map (fun (x, y) -> x, y, BridgeLantern)
+ let road = VillageArt.cc0LanternTiles map 12 |> List.map (fun (x, y) -> x, y, RoadLantern)
+ let red = VillageArt.cc0RedLanternTiles map |> List.map (fun (x, y) -> x, y, RedLantern)
+ (bridge @ road @ red)
+ |> List.distinctBy (fun (x, y, _) -> x, y)
+
let lightSourceTiles (map: MapGen.Result) : (int * int) list =
- (VillageArt.bridgeLanternTiles map
- @ VillageArt.cc0LanternTiles map 12
- @ VillageArt.cc0RedLanternTiles map)
- |> List.distinct
-
- /// 每个光源在其正下方连续水面格生成一条垂直倒影 (x, y, alpha)。
- let reflectionStreaks (map: MapGen.Result) : (int * int * int) list =
- lightSourceTiles map
- |> List.collect (fun (sx, sy) ->
- [ for d in 1 .. reflectionRange do
- let y = sy + d
- if isWater map sx y then yield (sx, y, reflectionAlphaAt d) ])
+ lightSources map |> List.map (fun (x, y, _) -> x, y)
+
+ /// 某个光源向下的倒影:先穿过至多 reflectionGap 格非水面(桥面/岸沿),落到正下方
+ /// 水面上,再沿连续水面画最多 reflectionRange 格;返回 (x, y, alpha, kind)。
+ let reflectionStreakFor (map: MapGen.Result) (sx: int) (sy: int) (kind: LightKind) : (int * int * int * LightKind) list =
+ let mutable start = sy + 1
+ let mutable gap = 0
+ while gap <= reflectionGap && start < map.Height && not (isWaterSurface map sx start) do
+ start <- start + 1
+ gap <- gap + 1
+ if start >= map.Height || gap > reflectionGap || not (isWaterSurface map sx start) then
+ []
+ else
+ [ for d in 0 .. reflectionRange - 1 do
+ let y = start + d
+ if isWaterSurface map sx y then yield (sx, y, reflectionAlphaAt (d + 1), kind) ]
+
+ /// 光源正下方倒影的格数(用于挑选倒影长度足够的取证机位)。
+ let reflectionLength (map: MapGen.Result) (x: int) (sy: int) : int =
+ lightSources map
+ |> List.filter (fun (sx, syy, _) -> sx = x && syy = sy)
+ |> List.tryHead
+ |> Option.map (fun (sx, syy, kind) -> reflectionStreakFor map sx syy kind |> List.length)
+ |> Option.defaultValue 0
+
+ /// 每个光源在其正下方连续水面格生成一条垂直倒影 (x, y, alpha, kind),最长 4 格。
+ let reflectionStreaks (map: MapGen.Result) : (int * int * int * LightKind) list =
+ lightSources map
+ |> List.collect (fun (sx, sy, kind) -> reflectionStreakFor map sx sy kind)
// ---------------- 岸边植被加密度 ----------------