Implement playable Mac client and rendering validation

This commit is contained in:
shen
2026-09-11 14:58:22 +08:00
parent 1ab68bd06e
commit 374d4165d8
233 changed files with 6546 additions and 284 deletions
+35 -16
View File
@@ -1,4 +1,5 @@
#include "water_builder.h"
#include "water_motion.h"
#include "asset_io.h"
#include "dxt.h"
@@ -7,6 +8,8 @@
#include <godot_cpp/classes/shader.hpp>
#include <godot_cpp/classes/shader_material.hpp>
#include <godot_cpp/classes/texture2d_array.hpp>
#include <godot_cpp/classes/time.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/variant/packed_byte_array.hpp>
#include <godot_cpp/variant/packed_color_array.hpp>
#include <godot_cpp/variant/packed_int32_array.hpp>
@@ -29,32 +32,30 @@ namespace {
// 30 帧序列 + 逐顶点水深 alpha(顶点 COLOR.a) + 轻微高度浮动。
// UV = 世界米;平铺频率在 shader 里按 1/(CELLSCALE*4 cm) = 1/8m。
const char *SRC_WATER = R"(shader_type spatial;
render_mode blend_mix, cull_disabled, depth_draw_never, diffuse_lambert, specular_schlick_ggx;
render_mode blend_mix, cull_disabled, depth_draw_never, unshaded;
uniform sampler2DArray frames : source_color, filter_linear_mipmap, repeat_enable;
uniform vec3 tint : source_color = vec3(0.10, 0.22, 0.26);
uniform float uv_per_meter = 0.125; // 1/8m,= 原客户端 1/(CELLSCALE*4)
uniform float bob_amp = 0.06; // 高度浮动幅度(米),近似 MapOutdoorWater 0..-15cm
uniform float height_offset = 0.0; // Shared reference water translation, metres.
void vertex() {
VERTEX.y += sin(TIME * 0.6 + VERTEX.x * 0.01 + VERTEX.z * 0.013) * bob_amp;
VERTEX.y += height_offset;
}
void fragment() {
int f = int(mod(TIME * 1000.0 / 70.0, 30.0)); // 70ms/帧
vec2 uv = UV * uv_per_meter;
vec3 tex = texture(frames, vec3(uv, float(f))).rgb;
float fres = pow(1.0 - clamp(dot(normalize(VIEW), NORMAL), 0.0, 1.0), 3.0);
ALBEDO = mix(tint, tex, 0.6) + fres * 0.15;
ALPHA = clamp(COLOR.a + fres * 0.25, 0.12, 0.95);
ROUGHNESS = 0.08;
METALLIC = 0.0;
SPECULAR = 0.6;
// MapOutdoorWater selects texture RGB and vertex diffuse alpha directly.
// Do not introduce PBR lighting, invented tint or view-dependent opacity.
ALBEDO = tex;
ALPHA = COLOR.a;
}
)";
Ref<Shader> g_water_shader;
Ref<ShaderMaterial> g_water_mat; // 30 帧数组只建一次
WaterMotion g_water_motion;
Ref<ShaderMaterial> water_material(const fmt::AssetResolver &res) {
if (g_water_mat.is_valid())
@@ -107,6 +108,19 @@ Ref<ShaderMaterial> water_material(const fmt::AssetResolver &res) {
void cleanup_water_shader() {
g_water_shader.unref();
g_water_mat.unref();
g_water_motion = WaterMotion{};
}
void update_water_animation() {
if (g_water_mat.is_null()) return;
const uint64_t now = Time::get_singleton()->get_ticks_msec();
uint64_t duration = 1000;
double depth = 0;
if (g_water_motion.initialized && now - g_water_motion.start_ms > g_water_motion.duration_ms) {
duration = UtilityFunctions::randi_range(1000, 3000);
if (g_water_motion.end == 0) depth = UtilityFunctions::randi_range(0, 15);
}
g_water_mat->set_shader_parameter("height_offset", g_water_motion.sample(now, duration, depth));
}
std::vector<WaterPiece> build_chunk_water(const fmt::WaterMap &wm, const fmt::HeightMap &hm,
@@ -126,8 +140,9 @@ std::vector<WaterPiece> build_chunk_water(const fmt::WaterMap &wm, const fmt::He
double ly = tex_y * double(fmt::m2coord::CELLSCALE);
double th = fmt::terrain_height_at(hm, lx, ly, height_scale); // cm
double depth_cm = water_h_cm - th;
float a = float(depth_cm / 60.0); // 60cm 深 -> 接近不透明
return a < 0.12f ? 0.12f : (a > 0.9f ? 0.9f : a);
// AreaTerrain uses RAW height differences, before HeightScale, with
// OpaqueWaterDepth=400 and clamps at 80% (not a 12% shoreline floor).
return water_depth_alpha(depth_cm, height_scale);
};
for (int layer = 0; layer < wm.layer_count; ++layer) {
@@ -147,8 +162,14 @@ std::vector<WaterPiece> build_chunk_water(const fmt::WaterMap &wm, const fmt::He
continue;
}
int xs = x;
while (x < W && wm.ids[y * W + x] == layer)
++x;
// Keep each cell's four shoreline samples. Merging a whole row
// discarded interior terrain peaks and bridged dry banks with water.
++x;
float aLL = depth_alpha(xs, y, h_cm), aLR = depth_alpha(x, y, h_cm);
float aUR = depth_alpha(x, y + 1, h_cm), aUL = depth_alpha(xs, y + 1, h_cm);
// AreaTerrain skips the quad when every diffuse alpha is zero.
if (aLL == 0 && aLR == 0 && aUR == 0 && aUL == 0)
continue;
double x0 = X0 + xs * CELL_M, x1 = X0 + x * CELL_M;
double z0 = Z0 + y * CELL_M, z1 = Z0 + (y + 1) * CELL_M;
int base = v.size();
@@ -162,8 +183,6 @@ std::vector<WaterPiece> build_chunk_water(const fmt::WaterMap &wm, const fmt::He
uv.push_back(Vector2(float(x1), float(z0)));
uv.push_back(Vector2(float(x1), float(z1)));
uv.push_back(Vector2(float(x0), float(z1)));
float aLL = depth_alpha(xs, y, h_cm), aLR = depth_alpha(x, y, h_cm);
float aUR = depth_alpha(x, y + 1, h_cm), aUL = depth_alpha(xs, y + 1, h_cm);
col.push_back(Color(1, 1, 1, aLL));
col.push_back(Color(1, 1, 1, aLR));
col.push_back(Color(1, 1, 1, aUR));