载入中...
搜索中...
未找到
Water.cpp
浏览该文件的文档.
1#include "graphics/Water.h"
2
3#include "graphics/Graphics.h"
4#include "graphics/Mesh.h"
5#include "graphics/shaders/water_frag_spv.inc"
6
7#include <cmath>
8#include <string>
9#include <vector>
10
11namespace eve::graphics {
12
13namespace {
14
15// Push-constant layout (data[32]):
16// 0 time, 1 waveSpeed, 2 waveAmp, 3 rippleAmp, 4 edgeFalloff,
17// 5 reflIntensity, 6 rippleCount, 7 rippleInterval, 8 waveScale,
18// 9..11 waterColor, 12..14 reflTint, 15 sunIntensity,
19// 16 viewportW, 17 viewportH, 18 ssrEnabled, 19 ssrStrength.
20const char *kWtrShaderFrag = R"GLSL(#version 450
21layout(location = 0) in vec3 vNormal;
22layout(location = 1) in vec2 vUV;
23layout(location = 2) in vec4 vTint;
24layout(location = 3) in vec3 vWorldPos;
25layout(location = 4) in vec3 vCameraPos;
26layout(location = 5) in vec3 vViewPos;
27
28struct Light3D { vec4 posRadius; vec4 color; };
29layout(set = 0, binding = 0, std140) uniform Frame {
30 mat4 mvp;
31 mat4 model;
32 vec4 lightDirIntensity;
33 vec4 lightColor;
34 vec4 tint;
35 vec4 cameraPos;
36 vec4 ambient;
37 Light3D lights[8];
38 vec4 texBomb;
39 vec4 parallax;
40 mat4 view;
41 vec4 clipInfo;
42} ubo;
43
44layout(set = 0, binding = 1) uniform sampler2D albedo;
45layout(set = 0, binding = 3) uniform samplerCube env;
46layout(set = 0, binding = 6) uniform sampler2D ssrTex; // screen-space reflection (optional)
47
48layout(push_constant) uniform Externals { float data[32]; } u;
49layout(location = 0) out vec4 outColor;
50
51const float PI = 3.14159265;
52
53float hash(float n) { return fract(sin(n) * 43758.5453123); }
54vec2 hash2(int i) { return vec2(hash(float(i) * 7.31), hash(float(i) * 13.17 + 1.0)); }
55
56// Expanding damped-wavelet ripple from a periodic drop (smooth, water-like).
57float rippleRing(vec2 uv, int i) {
58 float period = max(u.data[7], 1e-3); // rippleInterval
59 float local = mod(u.data[0], period);
60 float startPhase = hash(float(i) * 3.7) * period;
61 float age = local - startPhase;
62 if (age < 0.0) return 0.0;
63 float life = period * 0.8;
64 if (age > life) return 0.0;
65 vec2 center = hash2(i);
66 center = mix(vec2(0.5), center, 0.72); // keep drops near the middle
67 float r = length(uv - center);
68 float radius = age * 0.22; // expanding ring
69 float wavelength = 0.10; // spacing between crests
70 float x = (r - radius) / wavelength;
71 // Soft damped wavelet: smooth gaussian envelope, a crest + trough pair.
72 float envelope = exp(-(x * x) * 0.9);
73 float wave = cos(x * 6.28318);
74 float fade = exp(-age * 1.6); // fade out as it grows
75 return u.data[3] * envelope * wave * fade; // rippleAmp
76}
77
78// Water height displacement over UV.
79float waterHeight(vec2 uv) {
80 float t = u.data[0];
81 float ws = u.data[8];
82 vec2 edgeDist = min(uv, vec2(1.0) - uv);
83 float edgeFactor = 1.0 - clamp(min(edgeDist.x, edgeDist.y) / max(u.data[4], 1e-4), 0.0, 1.0);
84 float w = 0.0;
85 // Shore-edge waves, strongest at the border and fading inward.
86 w += edgeFactor * u.data[2] * (sin((uv.x * ws + t * u.data[1]) * PI * 2.0) +
87 0.5 * sin((uv.y * ws * 0.7 - t * u.data[1] * 1.3) * PI * 2.0));
88 // Fine detail everywhere.
89 w += u.data[2] * 0.10 * sin((uv.x * 31.0 + uv.y * 17.0 + t * u.data[1] * 2.0) * PI * 2.0);
90 // Occasional middle drop ripples.
91 int n = int(u.data[6] + 0.5);
92 for (int i = 0; i < 8; ++i) {
93 if (i >= n) break;
94 w += rippleRing(uv, i);
95 }
96 return w;
97}
98
99void main() {
100 // Surface normal from the analytic displacement (finite differences).
101 float eps = 1e-3;
102 float hL = waterHeight(vUV - vec2(eps, 0.0));
103 float hR = waterHeight(vUV + vec2(eps, 0.0));
104 float hD = waterHeight(vUV - vec2(0.0, eps));
105 float hU = waterHeight(vUV + vec2(0.0, eps));
106 vec2 grad = vec2((hR - hL) / (2.0 * eps), (hU - hD) / (2.0 * eps));
107 vec3 N = normalize(vec3(-grad.x, 1.0, -grad.y));
108
109 vec3 V = normalize(ubo.cameraPos.xyz - vWorldPos);
110 vec3 R = reflect(-V, N);
111
112 // Sky reflection via the env cubemap, blurred more at grazing angles.
113 // Clamp LOD to available mip levels so a non-mipmapped env is still safe.
114 float ndv = max(dot(V, N), 0.0);
115 float maxLod = float(max(textureQueryLevels(env) - 1, 0));
116 float lod = min(1.0 + (1.0 - ndv) * 4.0, maxLod);
117 vec3 refl = textureLod(env, R, lod).rgb * vec3(u.data[12], u.data[13], u.data[14]);
118 float fresnel = 0.02 + 0.98 * pow(1.0 - ndv, 5.0);
119
120 vec3 waterCol = vec3(u.data[9], u.data[10], u.data[11]);
121 float reflectAmt = clamp(fresnel * u.data[5] + 0.30, 0.0, 1.0);
122 vec3 color = mix(waterCol, refl, reflectAmt);
123
124 // Sun glint highlight.
125 vec3 L = normalize(ubo.lightDirIntensity.xyz);
126 vec3 H = normalize(V + L);
127 float spec = pow(max(dot(N, H), 0.0), 96.0);
128 color += ubo.lightColor.rgb * spec * u.data[15];
129
130 // Soft foam where waves meet the edge.
131 vec2 edgeDist = min(vUV, vec2(1.0) - vUV);
132 float edgeFactor = 1.0 - clamp(min(edgeDist.x, edgeDist.y) / max(u.data[4], 1e-4), 0.0, 1.0);
133 color = mix(color, vec3(0.85, 0.93, 1.0), edgeFactor * 0.22);
134
135 // Optional screen-space reflection overlay (bound via the height slot,
136 // binding 6). Sample the SSR pass result at this fragment's screen UV and
137 // blend it over the env reflection where SSR found a hit (ssr.a > 0).
138 if (u.data[18] > 0.5 && u.data[16] > 1.0 && u.data[17] > 1.0) {
139 vec2 sUV = vec2(gl_FragCoord.x / u.data[16], gl_FragCoord.y / u.data[17]);
140 vec4 ssr = texture(ssrTex, sUV);
141 color = mix(color, ssr.rgb, clamp(ssr.a * u.data[19], 0.0, 1.0));
142 }
143
144 outColor = vec4(color, 1.0);
145}
146)GLSL";
147
148const char *kUniformNames[] = {
149 "time", "waveSpeed", "waveAmp", "rippleAmp", "edgeFalloff",
150 "reflInten", "rippleCnt", "rippleInt", "waveScale", "waterCol",
151 "reflTint", "sunInten", "viewportW", "viewportH", "ssrEnabled",
152 "ssrStrength",
153};
154const int kUniformCount = int(sizeof(kUniformNames) / sizeof(kUniformNames[0]));
155
156} // namespace
157
159 // Use precompiled SPIR-V (not runtime glslc) so the water shader also works
160 // on platforms without a runtime compiler (e.g. Windows).
161 std::vector<uint32_t> frag(water_frag_spv, water_frag_spv + water_frag_spv_count);
162 Shader *sh = gfx->newMeshShaderFromSpv({}, frag);
163 for (int i = 0; i < kUniformCount; ++i) {
164 if (std::string(kUniformNames[i]) == "waterCol")
165 sh->declareVec3(kUniformNames[i]);
166 else if (std::string(kUniformNames[i]) == "reflTint")
167 sh->declareVec3(kUniformNames[i]);
168 else
169 sh->declareFloat(kUniformNames[i]);
170 }
171 return sh;
172}
173
174int Water::paramCount() { return kUniformCount; }
175
176std::string Water::paramName(int index) {
177 if (index < 0 || index >= kUniformCount) return {};
178 return kUniformNames[index];
179}
180
181Water::Water(Graphics *gfx) : gfx_(gfx) {
182 shader_ = newWaterShader(gfx);
183 bindParams();
184}
185
186void Water::createPlane(float sizeX, float sizeZ, int segX, int segZ) {
187 segX = std::max(1, segX);
188 segZ = std::max(1, segZ);
189 std::vector<float> pos, nrm, uv;
190 std::vector<uint32_t> idx;
191 for (int z = 0; z <= segZ; ++z) {
192 for (int x = 0; x <= segX; ++x) {
193 pos.push_back(-sizeX * 0.5f + sizeX * float(x) / segX);
194 pos.push_back(0.f);
195 pos.push_back(-sizeZ * 0.5f + sizeZ * float(z) / segZ);
196 nrm.push_back(0.f);
197 nrm.push_back(1.f);
198 nrm.push_back(0.f);
199 uv.push_back(float(x) / segX);
200 uv.push_back(float(z) / segZ);
201 }
202 }
203 for (int z = 0; z < segZ; ++z) {
204 for (int x = 0; x < segX; ++x) {
205 const uint32_t a = uint32_t(z * (segX + 1) + x);
206 const uint32_t b = a + 1;
207 const uint32_t c = a + uint32_t(segX + 1);
208 const uint32_t d = c + 1;
209 idx.push_back(a);
210 idx.push_back(c);
211 idx.push_back(b);
212 idx.push_back(b);
213 idx.push_back(c);
214 idx.push_back(d);
215 }
216 }
217 mesh_ = gfx_->newMeshFromArrays(pos.data(), nrm.data(), uv.data(), int(pos.size() / 3),
218 idx.data(), int(idx.size()));
219}
220
221void Water::update(float dt) {
222 time_ += dt;
223 bindParams();
224}
225
226void Water::setTime(float seconds) {
227 time_ = seconds;
228 bindParams();
229}
230
231void Water::setWaveSpeed(float v) { waveSpeed_ = v; }
232void Water::setWaveAmplitude(float v) { waveAmplitude_ = v; }
233void Water::setRippleAmplitude(float v) { rippleAmplitude_ = v; }
234void Water::setEdgeFalloff(float v) { edgeFalloff_ = std::max(0.001f, v); }
235void Water::setRippleCount(int v) { rippleCount_ = std::max(0, v); }
236void Water::setRippleInterval(float v) { rippleInterval_ = std::max(0.05f, v); }
237void Water::setWaveScale(float v) { waveScale_ = std::max(0.1f, v); }
238void Water::setWaterColor(float r, float g, float b) {
239 waterColor_[0] = r;
240 waterColor_[1] = g;
241 waterColor_[2] = b;
242}
243void Water::setReflectionTint(float r, float g, float b) {
244 reflectionTint_[0] = r;
245 reflectionTint_[1] = g;
246 reflectionTint_[2] = b;
247}
248void Water::setReflectionIntensity(float v) { reflectionIntensity_ = std::max(0.f, v); }
249void Water::setSunIntensity(float v) { sunIntensity_ = std::max(0.f, v); }
250void Water::setScreenSpaceReflection(bool enabled, float strength) {
251 ssrEnabled_ = enabled;
252 ssrStrength_ = std::max(0.f, strength);
253}
254void Water::setViewport(float w, float h) {
255 viewportW_ = std::max(0.f, w);
256 viewportH_ = std::max(0.f, h);
257}
258
260 if (!shader_) return;
261 shader_->sendFloat("time", time_);
262 shader_->sendFloat("waveSpeed", waveSpeed_);
263 shader_->sendFloat("waveAmp", waveAmplitude_);
264 shader_->sendFloat("rippleAmp", rippleAmplitude_);
265 shader_->sendFloat("edgeFalloff", edgeFalloff_);
266 shader_->sendFloat("reflInten", reflectionIntensity_);
267 shader_->sendFloat("rippleCnt", float(rippleCount_));
268 shader_->sendFloat("rippleInt", rippleInterval_);
269 shader_->sendFloat("waveScale", waveScale_);
270 shader_->sendVec3("waterCol", waterColor_[0], waterColor_[1], waterColor_[2]);
271 shader_->sendVec3("reflTint", reflectionTint_[0], reflectionTint_[1], reflectionTint_[2]);
272 shader_->sendFloat("sunInten", sunIntensity_);
273 shader_->sendFloat("viewportW", viewportW_);
274 shader_->sendFloat("viewportH", viewportH_);
275 shader_->sendFloat("ssrEnabled", ssrEnabled_ ? 1.f : 0.f);
276 shader_->sendFloat("ssrStrength", ssrStrength_);
277}
278
280 if (!gfx_ || !mesh_ || !shader_) return;
281 gfx_->drawMeshShader(mesh_, glm::mat4(1.f), nullptr, glm::vec4(1.f), shader_);
282}
283
284} // namespace eve::graphics
vk::ShaderModule frag
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
int h
int w
uint32_t a
uint32_t b
uint32_t c
int idx
bool enabled
int d
int v
virtual Shader * newMeshShaderFromSpv(const std::vector< uint32_t > &vertSpv, const std::vector< uint32_t > &fragSpv)=0
Create a Mesh3D custom shader (MeshVertex + Frame UBO + albedo). Empty vert → default mesh3d....
virtual void drawMeshShader(Mesh *mesh, const glm::mat4 &model, Texture *texture, const Color &tint, Shader *shader)=0
Draw mesh with an explicit Mesh3D Shader (nullptr = default PBR pipeline).
virtual Mesh * newMeshFromArrays(const float *posXYZ, const float *nrmXYZ, const float *uvST, int vertexCount, const uint32_t *indices, int indexCount)=0
Upload a triangle mesh from packed CPU arrays. Owned by Graphics. posXYZ required (vertexCount*3)....
Custom GPU program.
Definition Shader.h:30
void sendFloat(const std::string &name, float x)
Definition Shader.cpp:82
void sendVec3(const std::string &name, float x, float y, float z)
Definition Shader.cpp:89
int declareVec3(const std::string &name)
Definition Shader.cpp:32
int declareFloat(const std::string &name)
Reserve sequential float slots in the push-constant block. Returns start index.
Definition Shader.cpp:30
void setScreenSpaceReflection(bool enabled, float strength=0.85f)
Optional screen-space reflection overlay. When enabled, the shader samples the SSR pass result (bound...
Definition Water.cpp:250
void setWaveAmplitude(float amp)
Amplitude of the shore-edge waves.
Definition Water.cpp:232
static std::string paramName(int index)
Definition Water.cpp:176
void setRippleAmplitude(float amp)
Amplitude of the occasional middle drop ripples.
Definition Water.cpp:233
void setWaveSpeed(float speed)
Definition Water.cpp:231
Water(Graphics *gfx)
Definition Water.cpp:181
void update(float dt)
Advance the animation clock by dt seconds.
Definition Water.cpp:221
void draw()
Draw the water plane (uses default mesh3d camera / lighting state).
Definition Water.cpp:279
void setEdgeFalloff(float edge)
Width (in UV, 0..1) of the edge wave band.
Definition Water.cpp:234
void createPlane(float sizeX, float sizeZ, int segX, int segZ)
Build a flat XZ plane (Y-up) sized sizeX × sizeZ with UVs in [0,1]².
Definition Water.cpp:186
void setSunIntensity(float intensity)
Definition Water.cpp:249
void setReflectionTint(float r, float g, float b)
Definition Water.cpp:243
void setTime(float seconds)
Definition Water.cpp:226
void setReflectionIntensity(float intensity)
Definition Water.cpp:248
static int paramCount()
Names of the push-constant parameters (for UI / inspection).
Definition Water.cpp:174
void setWaveScale(float scale)
Definition Water.cpp:237
void setRippleInterval(float seconds)
Seconds between drop ripples.
Definition Water.cpp:236
void bindParams()
Upload current params to the shader push constants.
Definition Water.cpp:259
void setViewport(float width, float height)
Window / target size in pixels, used to compute screen-space UVs.
Definition Water.cpp:254
void setRippleCount(int count)
How many expanding drop ripples exist.
Definition Water.cpp:235
void setWaterColor(float r, float g, float b)
Definition Water.cpp:238
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition AnimTrail.h:6
Shader * newWaterShader(Graphics *gfx)
Create the embedded water fragment shader (owned by Graphics).
Definition Water.cpp:158