aether-engine 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aether/__init__.py +54 -0
- aether/audio/__init__.py +0 -0
- aether/audio/audio_manager.py +211 -0
- aether/audio/music.py +6 -0
- aether/audio/sound.py +6 -0
- aether/core/__init__.py +211 -0
- aether/core/achievement_system.py +304 -0
- aether/core/application.py +19 -0
- aether/core/config.py +75 -0
- aether/core/console.py +366 -0
- aether/core/engine.py +50 -0
- aether/core/event_bus.py +24 -0
- aether/core/input.py +58 -0
- aether/core/plugin_system.py +93 -0
- aether/core/save_system.py +409 -0
- aether/core/time_manager.py +25 -0
- aether/core/window.py +57 -0
- aether/graphics/__init__.py +0 -0
- aether/graphics/camera.py +69 -0
- aether/graphics/framebuffer.py +119 -0
- aether/graphics/light.py +32 -0
- aether/graphics/lod_system.py +170 -0
- aether/graphics/material.py +25 -0
- aether/graphics/mesh.py +83 -0
- aether/graphics/mesh_factory.py +67 -0
- aether/graphics/particle_system.py +268 -0
- aether/graphics/post_process.py +279 -0
- aether/graphics/renderer.py +135 -0
- aether/graphics/shader.py +61 -0
- aether/graphics/shader_library.py +157 -0
- aether/graphics/sky_atmosphere.py +309 -0
- aether/graphics/terrain.py +408 -0
- aether/graphics/texture.py +34 -0
- aether/graphics/water.py +432 -0
- aether/physics/__init__.py +0 -0
- aether/physics/bullet_backend.py +395 -0
- aether/physics/collider.py +22 -0
- aether/physics/physics_world.py +436 -0
- aether/physics/raycast.py +25 -0
- aether/physics/rigidbody.py +7 -0
- aether/resources/__init__.py +0 -0
- aether/resources/asset_database.py +76 -0
- aether/resources/resource_manager.py +147 -0
- aether/resources/serialization.py +114 -0
- aether/scene/__init__.py +0 -0
- aether/scene/component.py +368 -0
- aether/scene/entity.py +46 -0
- aether/scene/scene.py +33 -0
- aether/scene/scene_graph.py +252 -0
- aether/scene/scene_manager.py +191 -0
- aether/ui/__init__.py +0 -0
- aether/ui/button.py +297 -0
- aether/ui/canvas.py +11 -0
- aether/ui/text.py +286 -0
- aether/utils/__init__.py +0 -0
- aether/utils/logger.py +16 -0
- aether/utils/math_utils.py +31 -0
- aether/utils/object_pool.py +137 -0
- aether/utils/profiler.py +187 -0
- aether_engine-1.0.0.dist-info/METADATA +71 -0
- aether_engine-1.0.0.dist-info/RECORD +64 -0
- aether_engine-1.0.0.dist-info/WHEEL +5 -0
- aether_engine-1.0.0.dist-info/licenses/LICENSE +21 -0
- aether_engine-1.0.0.dist-info/top_level.txt +1 -0
aether/graphics/water.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
"""Система рендеринга воды с отражениями и волнами"""
|
|
2
|
+
import numpy as np
|
|
3
|
+
from OpenGL.GL import *
|
|
4
|
+
from typing import Optional, Tuple
|
|
5
|
+
from aether.graphics.shader import Shader
|
|
6
|
+
from aether.graphics.framebuffer import Framebuffer
|
|
7
|
+
from aether.graphics.mesh import Mesh
|
|
8
|
+
from aether.graphics.mesh_factory import MeshFactory
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WaveParameters:
|
|
12
|
+
"""Параметры волн (Gerstner waves)"""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
# Основные параметры
|
|
16
|
+
self.amplitude = 1.0
|
|
17
|
+
self.frequency = 0.5
|
|
18
|
+
self.speed = 1.0
|
|
19
|
+
self.direction = np.array([1.0, 0.0], dtype=np.float32)
|
|
20
|
+
self.steepness = 0.3
|
|
21
|
+
self.wavelength = 10.0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class WaterBody:
|
|
25
|
+
"""Водная поверхность"""
|
|
26
|
+
|
|
27
|
+
def __init__(self,
|
|
28
|
+
size: float = 100.0,
|
|
29
|
+
resolution: int = 256,
|
|
30
|
+
position: Tuple[float, float, float] = (0, 0, 0)):
|
|
31
|
+
|
|
32
|
+
self.size = size
|
|
33
|
+
self.resolution = resolution
|
|
34
|
+
self.position = np.array(position, dtype=np.float32)
|
|
35
|
+
|
|
36
|
+
# Меш
|
|
37
|
+
self.mesh: Optional[Mesh] = None
|
|
38
|
+
self._generate_mesh()
|
|
39
|
+
|
|
40
|
+
# Параметры
|
|
41
|
+
self.waves: list[WaveParameters] = []
|
|
42
|
+
self._create_default_waves()
|
|
43
|
+
|
|
44
|
+
# Отражения
|
|
45
|
+
self.reflection_enabled = True
|
|
46
|
+
self.reflection_fbo: Optional[Framebuffer] = None
|
|
47
|
+
self.reflection_clip_plane = (0.0, -1.0, 0.0, 0.0)
|
|
48
|
+
|
|
49
|
+
# Преломление
|
|
50
|
+
self.refraction_enabled = True
|
|
51
|
+
self.refraction_fbo: Optional[Framebuffer] = None
|
|
52
|
+
|
|
53
|
+
# Визуальные настройки
|
|
54
|
+
self.water_color = np.array([0.0, 0.3, 0.6], dtype=np.float32)
|
|
55
|
+
self.foam_color = np.array([1.0, 1.0, 1.0], dtype=np.float32)
|
|
56
|
+
self.transparency = 0.8
|
|
57
|
+
self.reflectivity = 0.6
|
|
58
|
+
self.fresnel_power = 3.0
|
|
59
|
+
|
|
60
|
+
# Анимация
|
|
61
|
+
self.time = 0.0
|
|
62
|
+
self.wave_speed = 1.0
|
|
63
|
+
|
|
64
|
+
# Шейдер
|
|
65
|
+
self._setup_shader()
|
|
66
|
+
|
|
67
|
+
print(f"[Water] Created {size}x{size} water body")
|
|
68
|
+
|
|
69
|
+
def _generate_mesh(self):
|
|
70
|
+
"""Генерирует плоский меш"""
|
|
71
|
+
vertices = []
|
|
72
|
+
normals = []
|
|
73
|
+
uvs = []
|
|
74
|
+
indices = []
|
|
75
|
+
|
|
76
|
+
step = self.size / (self.resolution - 1)
|
|
77
|
+
|
|
78
|
+
for z in range(self.resolution):
|
|
79
|
+
for x in range(self.resolution):
|
|
80
|
+
vx = x * step - self.size / 2
|
|
81
|
+
vz = z * step - self.size / 2
|
|
82
|
+
|
|
83
|
+
vertices.append([vx, 0.0, vz])
|
|
84
|
+
normals.append([0.0, 1.0, 0.0])
|
|
85
|
+
uvs.append([x / (self.resolution - 1), z / (self.resolution - 1)])
|
|
86
|
+
|
|
87
|
+
vertices = np.array(vertices, dtype=np.float32)
|
|
88
|
+
normals = np.array(normals, dtype=np.float32)
|
|
89
|
+
uvs = np.array(uvs, dtype=np.float32)
|
|
90
|
+
|
|
91
|
+
# Индексы
|
|
92
|
+
for z in range(self.resolution - 1):
|
|
93
|
+
for x in range(self.resolution - 1):
|
|
94
|
+
tl = z * self.resolution + x
|
|
95
|
+
tr = tl + 1
|
|
96
|
+
bl = (z + 1) * self.resolution + x
|
|
97
|
+
br = bl + 1
|
|
98
|
+
|
|
99
|
+
indices.extend([tl, bl, tr])
|
|
100
|
+
indices.extend([tr, bl, br])
|
|
101
|
+
|
|
102
|
+
indices = np.array(indices, dtype=np.uint32)
|
|
103
|
+
|
|
104
|
+
self.mesh = Mesh(vertices, indices, normals, uvs)
|
|
105
|
+
|
|
106
|
+
def _create_default_waves(self):
|
|
107
|
+
"""Создаёт волны по умолчанию"""
|
|
108
|
+
wave1 = WaveParameters()
|
|
109
|
+
wave1.amplitude = 0.5
|
|
110
|
+
wave1.frequency = 0.3
|
|
111
|
+
wave1.direction = np.array([1.0, 0.3], dtype=np.float32)
|
|
112
|
+
wave1.wavelength = 8.0
|
|
113
|
+
|
|
114
|
+
wave2 = WaveParameters()
|
|
115
|
+
wave2.amplitude = 0.3
|
|
116
|
+
wave2.frequency = 0.5
|
|
117
|
+
wave2.direction = np.array([-0.5, 0.7], dtype=np.float32)
|
|
118
|
+
wave2.wavelength = 5.0
|
|
119
|
+
|
|
120
|
+
wave3 = WaveParameters()
|
|
121
|
+
wave3.amplitude = 0.2
|
|
122
|
+
wave3.frequency = 0.7
|
|
123
|
+
wave3.direction = np.array([0.2, -0.8], dtype=np.float32)
|
|
124
|
+
wave3.wavelength = 3.0
|
|
125
|
+
|
|
126
|
+
self.waves = [wave1, wave2, wave3]
|
|
127
|
+
|
|
128
|
+
def _setup_shader(self):
|
|
129
|
+
"""Настройка шейдера воды"""
|
|
130
|
+
vertex_shader = """
|
|
131
|
+
#version 460 core
|
|
132
|
+
layout(location = 0) in vec3 aPos;
|
|
133
|
+
layout(location = 1) in vec3 aNormal;
|
|
134
|
+
layout(location = 2) in vec2 aTexCoord;
|
|
135
|
+
|
|
136
|
+
out vec3 FragPos;
|
|
137
|
+
out vec3 Normal;
|
|
138
|
+
out vec2 TexCoord;
|
|
139
|
+
out vec4 ClipSpace;
|
|
140
|
+
out vec3 ViewPos;
|
|
141
|
+
|
|
142
|
+
uniform mat4 model;
|
|
143
|
+
uniform mat4 view;
|
|
144
|
+
uniform mat4 projection;
|
|
145
|
+
uniform float time;
|
|
146
|
+
|
|
147
|
+
// Wave parameters
|
|
148
|
+
uniform int waveCount;
|
|
149
|
+
uniform float amplitudes[8];
|
|
150
|
+
uniform float frequencies[8];
|
|
151
|
+
uniform float speeds[8];
|
|
152
|
+
uniform vec2 directions[8];
|
|
153
|
+
uniform float steepnesses[8];
|
|
154
|
+
uniform float wavelengths[8];
|
|
155
|
+
|
|
156
|
+
float wave(int i, vec2 pos, float time) {
|
|
157
|
+
float freq = frequencies[i];
|
|
158
|
+
float amp = amplitudes[i];
|
|
159
|
+
float speed = speeds[i];
|
|
160
|
+
vec2 dir = normalize(directions[i]);
|
|
161
|
+
float steep = steepnesses[i];
|
|
162
|
+
float wl = wavelengths[i];
|
|
163
|
+
|
|
164
|
+
float f = 2.0 * 3.14159 / wl;
|
|
165
|
+
float phase = speed * 2.0 / wl;
|
|
166
|
+
float theta = dot(dir, pos) * f + time * phase;
|
|
167
|
+
|
|
168
|
+
return amp * sin(theta);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
float waveDerivativeX(int i, vec2 pos, float time) {
|
|
172
|
+
float freq = frequencies[i];
|
|
173
|
+
float amp = amplitudes[i];
|
|
174
|
+
float speed = speeds[i];
|
|
175
|
+
vec2 dir = normalize(directions[i]);
|
|
176
|
+
float steep = steepnesses[i];
|
|
177
|
+
float wl = wavelengths[i];
|
|
178
|
+
|
|
179
|
+
float f = 2.0 * 3.14159 / wl;
|
|
180
|
+
float phase = speed * 2.0 / wl;
|
|
181
|
+
float theta = dot(dir, pos) * f + time * phase;
|
|
182
|
+
|
|
183
|
+
return amp * dir.x * f * cos(theta);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
float waveDerivativeZ(int i, vec2 pos, float time) {
|
|
187
|
+
float freq = frequencies[i];
|
|
188
|
+
float amp = amplitudes[i];
|
|
189
|
+
float speed = speeds[i];
|
|
190
|
+
vec2 dir = normalize(directions[i]);
|
|
191
|
+
float steep = steepnesses[i];
|
|
192
|
+
float wl = wavelengths[i];
|
|
193
|
+
|
|
194
|
+
float f = 2.0 * 3.14159 / wl;
|
|
195
|
+
float phase = speed * 2.0 / wl;
|
|
196
|
+
float theta = dot(dir, pos) * f + time * phase;
|
|
197
|
+
|
|
198
|
+
return amp * dir.y * f * cos(theta);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void main() {
|
|
202
|
+
vec3 pos = aPos;
|
|
203
|
+
|
|
204
|
+
// Применяем волны
|
|
205
|
+
vec2 xz = pos.xz;
|
|
206
|
+
for (int i = 0; i < waveCount && i < 8; i++) {
|
|
207
|
+
pos.y += wave(i, xz, time);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Вычисляем нормаль
|
|
211
|
+
float dx = 0.0;
|
|
212
|
+
float dz = 0.0;
|
|
213
|
+
for (int i = 0; i < waveCount && i < 8; i++) {
|
|
214
|
+
dx += waveDerivativeX(i, xz, time);
|
|
215
|
+
dz += waveDerivativeZ(i, xz, time);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
vec3 calcNormal = normalize(vec3(-dx, 1.0, -dz));
|
|
219
|
+
|
|
220
|
+
vec4 worldPos = model * vec4(pos, 1.0);
|
|
221
|
+
|
|
222
|
+
FragPos = worldPos.xyz;
|
|
223
|
+
Normal = mat3(transpose(inverse(model))) * calcNormal;
|
|
224
|
+
TexCoord = aTexCoord;
|
|
225
|
+
ClipSpace = projection * view * worldPos;
|
|
226
|
+
ViewPos = (inverse(view) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
227
|
+
|
|
228
|
+
gl_Position = ClipSpace;
|
|
229
|
+
}
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
fragment_shader = """
|
|
233
|
+
#version 460 core
|
|
234
|
+
in vec3 FragPos;
|
|
235
|
+
in vec3 Normal;
|
|
236
|
+
in vec2 TexCoord;
|
|
237
|
+
in vec4 ClipSpace;
|
|
238
|
+
in vec3 ViewPos;
|
|
239
|
+
|
|
240
|
+
out vec4 FragColor;
|
|
241
|
+
|
|
242
|
+
uniform vec3 waterColor;
|
|
243
|
+
uniform vec3 foamColor;
|
|
244
|
+
uniform float transparency;
|
|
245
|
+
uniform float reflectivity;
|
|
246
|
+
uniform float fresnelPower;
|
|
247
|
+
uniform float time;
|
|
248
|
+
uniform sampler2D reflectionTexture;
|
|
249
|
+
uniform sampler2D refractionTexture;
|
|
250
|
+
uniform sampler2D foamTexture;
|
|
251
|
+
uniform sampler2D normalMap;
|
|
252
|
+
|
|
253
|
+
void main() {
|
|
254
|
+
vec3 N = normalize(Normal);
|
|
255
|
+
vec3 V = normalize(ViewPos - FragPos);
|
|
256
|
+
|
|
257
|
+
// Fresnel эффект
|
|
258
|
+
float fresnel = pow(1.0 - max(dot(N, V), 0.0), fresnelPower);
|
|
259
|
+
fresnel = mix(0.04, 1.0, fresnel);
|
|
260
|
+
|
|
261
|
+
// Отражение
|
|
262
|
+
vec2 ndc = (ClipSpace.xy / ClipSpace.w) * 0.5 + 0.5;
|
|
263
|
+
vec3 reflection = texture(reflectionTexture, ndc).rgb;
|
|
264
|
+
|
|
265
|
+
// Преломление
|
|
266
|
+
vec3 refraction = texture(refractionTexture, ndc).rgb;
|
|
267
|
+
|
|
268
|
+
// Искажение через normal map
|
|
269
|
+
vec2 distortion = texture(normalMap, TexCoord * 10.0 + time * 0.05).rg * 0.02;
|
|
270
|
+
vec2 distortedUV = ndc + distortion;
|
|
271
|
+
|
|
272
|
+
reflection = texture(reflectionTexture, distortedUV).rgb;
|
|
273
|
+
refraction = texture(refractionTexture, distortedUV).rgb;
|
|
274
|
+
|
|
275
|
+
// Комбинируем
|
|
276
|
+
vec3 color = mix(refraction, reflection, fresnel * reflectivity);
|
|
277
|
+
color = mix(color, waterColor, 0.3);
|
|
278
|
+
|
|
279
|
+
// Пена на гребнях волн
|
|
280
|
+
float foam = texture(foamTexture, TexCoord * 5.0 + time * 0.1).r;
|
|
281
|
+
foam *= pow(fresnel, 0.5);
|
|
282
|
+
color = mix(color, foamColor, foam * 0.3);
|
|
283
|
+
|
|
284
|
+
// Прозрачность на мелководье
|
|
285
|
+
float depthFactor = 1.0 - exp(-length(FragPos - ViewPos) * 0.1);
|
|
286
|
+
color = mix(waterColor, color, depthFactor);
|
|
287
|
+
|
|
288
|
+
FragColor = vec4(color, mix(0.8, 1.0, depthFactor));
|
|
289
|
+
}
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
from aether.graphics.shader import Shader
|
|
293
|
+
self.shader = Shader(vertex_shader, fragment_shader)
|
|
294
|
+
|
|
295
|
+
def create_reflection_fbo(self, width: int, height: int):
|
|
296
|
+
"""Создаёт FBO для отражений"""
|
|
297
|
+
self.reflection_fbo = Framebuffer(width, height)
|
|
298
|
+
|
|
299
|
+
def create_refraction_fbo(self, width: int, height: int):
|
|
300
|
+
"""Создаёт FBO для преломлений"""
|
|
301
|
+
self.refraction_fbo = Framebuffer(width, height)
|
|
302
|
+
|
|
303
|
+
def begin_reflection(self):
|
|
304
|
+
"""Начинает рендеринг отражения"""
|
|
305
|
+
if self.reflection_fbo:
|
|
306
|
+
self.reflection_fbo.bind()
|
|
307
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
|
308
|
+
# Здесь была бы отсекающая плоскость
|
|
309
|
+
|
|
310
|
+
def end_reflection(self):
|
|
311
|
+
"""Заканчивает рендеринг отражения"""
|
|
312
|
+
Framebuffer.unbind()
|
|
313
|
+
|
|
314
|
+
def begin_refraction(self):
|
|
315
|
+
"""Начинает рендеринг преломления"""
|
|
316
|
+
if self.refraction_fbo:
|
|
317
|
+
self.refraction_fbo.bind()
|
|
318
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
|
319
|
+
|
|
320
|
+
def end_refraction(self):
|
|
321
|
+
"""Заканчивает рендеринг преломления"""
|
|
322
|
+
Framebuffer.unbind()
|
|
323
|
+
|
|
324
|
+
def update(self, dt: float):
|
|
325
|
+
"""Обновляет анимацию воды"""
|
|
326
|
+
self.time += dt * self.wave_speed
|
|
327
|
+
|
|
328
|
+
def render(self, view: np.ndarray, projection: np.ndarray,
|
|
329
|
+
camera_position: np.ndarray):
|
|
330
|
+
"""Рендерит воду"""
|
|
331
|
+
if not self.mesh or not self.shader:
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
self.shader.use()
|
|
335
|
+
|
|
336
|
+
# Матрицы
|
|
337
|
+
model = np.identity(4, dtype=np.float32)
|
|
338
|
+
model[3, :3] = self.position
|
|
339
|
+
self.shader.set_mat4("model", model)
|
|
340
|
+
self.shader.set_mat4("view", view)
|
|
341
|
+
self.shader.set_mat4("projection", projection)
|
|
342
|
+
|
|
343
|
+
# Время
|
|
344
|
+
self.shader.set_float("time", self.time)
|
|
345
|
+
|
|
346
|
+
# Параметры волн
|
|
347
|
+
wave_count = min(len(self.waves), 8)
|
|
348
|
+
self.shader.set_int("waveCount", wave_count)
|
|
349
|
+
|
|
350
|
+
amplitudes = np.array([w.amplitude for w in self.waves[:8]] + [0] * (8 - wave_count), dtype=np.float32)
|
|
351
|
+
frequencies = np.array([w.frequency for w in self.waves[:8]] + [0] * (8 - wave_count), dtype=np.float32)
|
|
352
|
+
speeds = np.array([w.speed for w in self.waves[:8]] + [0] * (8 - wave_count), dtype=np.float32)
|
|
353
|
+
|
|
354
|
+
self.shader.set_vec4("amplitudes", amplitudes[:4])
|
|
355
|
+
self.shader.set_vec4("frequencies", frequencies[:4])
|
|
356
|
+
self.shader.set_vec4("speeds", speeds[:4])
|
|
357
|
+
|
|
358
|
+
# Визуальные параметры
|
|
359
|
+
self.shader.set_vec3("waterColor", self.water_color)
|
|
360
|
+
self.shader.set_vec3("foamColor", self.foam_color)
|
|
361
|
+
self.shader.set_float("transparency", self.transparency)
|
|
362
|
+
self.shader.set_float("reflectivity", self.reflectivity)
|
|
363
|
+
self.shader.set_float("fresnelPower", self.fresnel_power)
|
|
364
|
+
|
|
365
|
+
# Текстуры отражений/преломлений
|
|
366
|
+
if self.reflection_fbo:
|
|
367
|
+
glActiveTexture(GL_TEXTURE0)
|
|
368
|
+
glBindTexture(GL_TEXTURE_2D, self.reflection_fbo.color_texture)
|
|
369
|
+
self.shader.set_int("reflectionTexture", 0)
|
|
370
|
+
|
|
371
|
+
if self.refraction_fbo:
|
|
372
|
+
glActiveTexture(GL_TEXTURE1)
|
|
373
|
+
glBindTexture(GL_TEXTURE_2D, self.refraction_fbo.color_texture)
|
|
374
|
+
self.shader.set_int("refractionTexture", 1)
|
|
375
|
+
|
|
376
|
+
self.mesh.draw()
|
|
377
|
+
|
|
378
|
+
def cleanup(self):
|
|
379
|
+
"""Очищает ресурсы"""
|
|
380
|
+
if self.mesh:
|
|
381
|
+
self.mesh.cleanup()
|
|
382
|
+
if self.reflection_fbo:
|
|
383
|
+
self.reflection_fbo.cleanup()
|
|
384
|
+
if self.refraction_fbo:
|
|
385
|
+
self.refraction_fbo.cleanup()
|
|
386
|
+
print("[Water] Cleanup complete")
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
class Ocean:
|
|
390
|
+
"""Океан (бесконечная вода с LOD)"""
|
|
391
|
+
|
|
392
|
+
def __init__(self, size: float = 1000.0):
|
|
393
|
+
self.size = size
|
|
394
|
+
self.patches: dict = {}
|
|
395
|
+
self.patch_size = 128.0
|
|
396
|
+
self.load_radius = 3
|
|
397
|
+
|
|
398
|
+
print(f"[Ocean] Created infinite ocean")
|
|
399
|
+
|
|
400
|
+
def update(self, camera_position: np.ndarray):
|
|
401
|
+
"""Обновляет патчи вокруг камеры"""
|
|
402
|
+
# Определяем, какие патчи должны быть видны
|
|
403
|
+
cx = int(camera_position[0] // self.patch_size)
|
|
404
|
+
cz = int(camera_position[2] // self.patch_size)
|
|
405
|
+
|
|
406
|
+
active_patches = set()
|
|
407
|
+
|
|
408
|
+
for x in range(cx - self.load_radius, cx + self.load_radius + 1):
|
|
409
|
+
for z in range(cz - self.load_radius, cz + self.load_radius + 1):
|
|
410
|
+
active_patches.add((x, z))
|
|
411
|
+
|
|
412
|
+
# Удаляем невидимые патчи
|
|
413
|
+
for key in list(self.patches.keys()):
|
|
414
|
+
if key not in active_patches:
|
|
415
|
+
self.patches[key].cleanup()
|
|
416
|
+
del self.patches[key]
|
|
417
|
+
|
|
418
|
+
# Создаём новые патчи
|
|
419
|
+
for key in active_patches:
|
|
420
|
+
if key not in self.patches:
|
|
421
|
+
position = (
|
|
422
|
+
key[0] * self.patch_size,
|
|
423
|
+
0.0,
|
|
424
|
+
key[1] * self.patch_size
|
|
425
|
+
)
|
|
426
|
+
patch = WaterBody(self.patch_size, 64, position)
|
|
427
|
+
self.patches[key] = patch
|
|
428
|
+
|
|
429
|
+
def render(self, view, projection, camera_position):
|
|
430
|
+
"""Рендерит все видимые патчи"""
|
|
431
|
+
for patch in self.patches.values():
|
|
432
|
+
patch.render(view, projection, camera_position)
|
|
File without changes
|