Implement playable Mac client and rendering validation
This commit is contained in:
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user