1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "weather_system.h"
17
18 #include <ComponentTools/component_query.h>
19 #include <algorithm>
20 #include <cfloat>
21
22 #include <3d/ecs/components/camera_component.h>
23 #include <3d/ecs/components/environment_component.h>
24 #include <3d/ecs/components/material_component.h>
25 #include <3d/ecs/components/mesh_component.h>
26 #include <3d/ecs/components/name_component.h>
27 #include <3d/ecs/components/render_configuration_component.h>
28 #include <3d/ecs/components/render_handle_component.h>
29 #include <3d/ecs/components/render_mesh_component.h>
30 #include <3d/ecs/components/transform_component.h>
31 #include <3d/ecs/components/water_ripple_component.h>
32 #include <3d/ecs/components/weather_component.h>
33 #include <3d/ecs/components/world_matrix_component.h>
34 #include <3d/ecs/systems/intf_node_system.h>
35 #include <3d/ecs/systems/intf_weather_system.h>
36 #include <3d/implementation_uids.h>
37 #include <3d/intf_graphics_context.h>
38 #include <3d/render/default_material_constants.h>
39 #include <3d/util/intf_picking.h>
40 #include <core/ecs/intf_component_manager.h>
41 #include <core/ecs/intf_ecs.h>
42 #include <core/image/intf_image_loader_manager.h>
43 #include <core/implementation_uids.h>
44 #include <core/intf_engine.h>
45 #include <core/log.h>
46 #include <core/plugin/intf_class_factory.h>
47 #include <core/property/intf_property_api.h>
48 #include <core/property/intf_property_handle.h>
49 #include <core/property/scoped_handle.h>
50 #include <core/property_tools/property_macros.h>
51 #include <render/datastore/intf_render_data_store_default_staging.h>
52 #include <render/datastore/intf_render_data_store_manager.h>
53 #include <render/datastore/intf_render_data_store_pod.h>
54 #include <render/device/intf_gpu_resource_manager.h>
55 #include <render/device/intf_shader_manager.h>
56 #include <render/implementation_uids.h>
57 #include <render/intf_render_context.h>
58
59 #include "3d/shaders/common/water_ripple_common.h"
60 #include "ecs/systems/render_preprocessor_system.h"
61
62 using namespace BASE_NS;
63 using namespace CORE_NS;
64 using namespace RENDER_NS;
65 using namespace CORE3D_NS;
66
67 CORE3D_BEGIN_NAMESPACE()
68 namespace {
69 constexpr uint32_t RESOLUTION { 512u };
70
71 static constexpr string_view RENDER_DATA_STORE_DEFAULT_STAGING = "RenderDataStoreDefaultStaging";
72 static constexpr string_view RIPPLE_TEXTURE_NAME_0 { "RIPPLE_RENDER_NODE_TEXTURE_0" };
73 static constexpr string_view RIPPLE_TEXTURE_NAME_1 { "RIPPLE_RENDER_NODE_TEXTURE_1" };
74 static constexpr string_view RIPPLE_INPUT_BUFFER_NAME { "RIPPLE_RENDER_NODE_INPUTBUFFER" };
75
76 static constexpr string_view CLOUD_SHADER_NAME { "3dshaders://shader/clouds/core3d_dm_fw_cloud.shader" };
77
CreateTargetGpuImage(IEcs & ecs,IGpuResourceManager & gpuResourceMgr,const Math::UVec2 & size,const string_view name,BASE_NS::Format colorFormat)78 EntityReference CreateTargetGpuImage(IEcs& ecs, IGpuResourceManager& gpuResourceMgr, const Math::UVec2& size,
79 const string_view name, BASE_NS::Format colorFormat)
80 {
81 GpuImageDesc desc;
82 desc.width = size.x;
83 desc.height = size.y;
84 desc.depth = 1;
85 desc.format = colorFormat;
86 desc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
87 desc.usageFlags =
88 ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_STORAGE_BIT |
89 ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_DST_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_SRC_BIT;
90 desc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
91 desc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
92 desc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
93 desc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
94 auto rhr = gpuResourceMgr.Create(name, desc);
95
96 auto handleManager = GetManager<IRenderHandleComponentManager>(ecs);
97 return GetOrCreateEntityReference(ecs.GetEntityManager(), *handleManager, rhr);
98 }
99
CreateBuffer(IEcs & ecs,IGpuResourceManager & gpuResourceMgr,const string_view & name,const GpuBufferDesc & bufferDesc)100 EntityReference CreateBuffer(
101 IEcs& ecs, IGpuResourceManager& gpuResourceMgr, const string_view& name, const GpuBufferDesc& bufferDesc)
102 {
103 auto rhr = gpuResourceMgr.Create(name, bufferDesc);
104 auto handleManager = GetManager<IRenderHandleComponentManager>(ecs);
105 return GetOrCreateEntityReference(ecs.GetEntityManager(), *handleManager, rhr);
106 }
107
InitSimulationResources(IEcs & ecs,IGraphicsContext & graphicsContext,uint32_t inResolution)108 WeatherSystem::RipplePlaneResources InitSimulationResources(
109 IEcs& ecs, IGraphicsContext& graphicsContext, uint32_t inResolution)
110 {
111 auto& renderContext = graphicsContext.GetRenderContext();
112 auto& device = renderContext.GetDevice();
113 auto& gpuResourceMgr = device.GetGpuResourceManager();
114 WeatherSystem::RipplePlaneResources mTestRes;
115 // create textures for ripple simulation
116 {
117 mTestRes.rippleTextures[0] = CreateTargetGpuImage(ecs, gpuResourceMgr, { inResolution, inResolution },
118 RIPPLE_TEXTURE_NAME_0, Format::BASE_FORMAT_R32G32B32A32_SFLOAT);
119 mTestRes.rippleTextures[1] = CreateTargetGpuImage(ecs, gpuResourceMgr, { inResolution, inResolution },
120 RIPPLE_TEXTURE_NAME_1, Format::BASE_FORMAT_R32G32B32A32_SFLOAT);
121
122 GpuBufferDesc inputArgsBuffer;
123 inputArgsBuffer.engineCreationFlags = CORE_ENGINE_BUFFER_CREATION_DYNAMIC_BARRIERS;
124 inputArgsBuffer.memoryPropertyFlags =
125 CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT | CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
126 inputArgsBuffer.usageFlags = CORE_BUFFER_USAGE_STORAGE_BUFFER_BIT | CORE_BUFFER_USAGE_TRANSFER_DST_BIT;
127 inputArgsBuffer.byteSize = sizeof(DefaultWaterRippleDataStruct);
128 mTestRes.rippleArgsBufferHandle = CreateBuffer(ecs, gpuResourceMgr, RIPPLE_INPUT_BUFFER_NAME, inputArgsBuffer);
129 }
130
131 return mTestRes;
132 }
133
134 // nodeEntity should have material component
CreateSimulationResourcesForEntity(IEcs & ecs,IGraphicsContext & graphicsContext,const Entity & nodeEntity)135 WeatherSystem::RipplePlaneResources CreateSimulationResourcesForEntity(
136 IEcs& ecs, IGraphicsContext& graphicsContext, const Entity& nodeEntity)
137 {
138 WeatherSystem::RipplePlaneResources planeRes;
139
140 auto* renderMeshCM = GetManager<IRenderMeshComponentManager>(ecs);
141 auto* meshCM = GetManager<IMeshComponentManager>(ecs);
142 auto* matCM = GetManager<IMaterialComponentManager>(ecs);
143 auto* gpuHandleCM = GetManager<IRenderHandleComponentManager>(ecs);
144
145 auto& entityMgr = ecs.GetEntityManager();
146 auto& device = graphicsContext.GetRenderContext().GetDevice();
147 auto& gpuResourceMgr = device.GetGpuResourceManager();
148 IShaderManager& shaderMgr = device.GetShaderManager();
149 if (!(renderMeshCM && meshCM && matCM && gpuHandleCM)) {
150 return {};
151 }
152
153 planeRes = InitSimulationResources(ecs, graphicsContext, RESOLUTION);
154 planeRes.entityID = nodeEntity;
155
156 // create bilinear sampler
157 RenderHandleReference samplerRhr = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
158 EntityReference BilinearSampler =
159 GetOrCreateEntityReference(ecs.GetEntityManager(), *gpuHandleCM, BASE_NS::move(samplerRhr));
160
161 if (const auto rmcHandle = renderMeshCM->Read(nodeEntity); rmcHandle) {
162 const RenderMeshComponent& rmc = *rmcHandle;
163 if (const auto meshHandle = meshCM->Read(rmc.mesh); meshHandle) {
164 const MeshComponent& meshComponent = *meshHandle;
165 if (!meshComponent.submeshes.empty()) {
166 if (auto matHandle = matCM->Write(meshComponent.submeshes[0].material); matHandle) {
167 MaterialComponent& matComponent = *matHandle;
168 matComponent.materialShader.shader = GetOrCreateEntityReference(entityMgr, *gpuHandleCM,
169 shaderMgr.GetShaderHandle("3dshaders://shader/ripple/custom_water_ripple.shader"));
170
171 // default settings fro custom_reflection_water shader.
172 matComponent.materialLightingFlags &= ~MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT;
173 matComponent.textures[MaterialComponent::TextureIndex::BASE_COLOR].factor =
174 Math::Vec4(0.1f, 0.1f, 0.25f, 0.8f);
175 // go higher for mirror
176 matComponent.textures[MaterialComponent::TextureIndex::MATERIAL].factor =
177 Math::Vec4(0.f, 0.01f, 0.0f, 0.3f);
178 matComponent.textures[MaterialComponent::TextureIndex::NORMAL].factor.x = 1.0f;
179 matComponent.textures[MaterialComponent::TextureIndex::EMISSIVE].factor = { 10.0f, 10.0f, 10.0f,
180 1.0f };
181
182 // set RippleEffect texture as material component's texture.
183 matComponent.textures[MaterialComponent::TextureIndex::AO].image = planeRes.rippleTextures[0];
184 matComponent.textures[MaterialComponent::TextureIndex::AO].sampler = BASE_NS::move(BilinearSampler);
185 }
186 }
187 }
188 }
189
190 return planeRes;
191 }
192
GetCloudRenderingType(const WeatherComponent::CloudRenderingType ct)193 constexpr RenderDataStoreWeather::CloudRenderingType GetCloudRenderingType(
194 const WeatherComponent::CloudRenderingType ct)
195 {
196 switch (ct) {
197 case WeatherComponent::CloudRenderingType::FULL:
198 return RenderDataStoreWeather::CloudRenderingType::FULL;
199 break;
200 case WeatherComponent::CloudRenderingType::DOWNSCALED:
201 return RenderDataStoreWeather::CloudRenderingType::DOWNSCALED;
202 break;
203 case WeatherComponent::CloudRenderingType::REPROJECTED:
204 return RenderDataStoreWeather::CloudRenderingType::REPROJECTED;
205 break;
206 default:
207 return RenderDataStoreWeather::CloudRenderingType::FULL;
208 }
209 }
210 } // namespace
211
WeatherSystem(IEcs & ecs)212 WeatherSystem::WeatherSystem(IEcs& ecs)
213 : ecs_(ecs),
214 materialManager_(*GetManager<IMaterialComponentManager>(ecs)),
215 meshManager_(*GetManager<IMeshComponentManager>(ecs)),
216 renderMeshManager_(*GetManager<IRenderMeshComponentManager>(ecs)),
217 renderHandleManager_(*GetManager<IRenderHandleComponentManager>(ecs)),
218 transformationManager_(*GetManager<ITransformComponentManager>(ecs)),
219 renderConfigManager_(*GetManager<IRenderConfigurationComponentManager>(ecs)),
220 camManager_(*GetManager<ICameraComponentManager>(ecs)),
221 envManager_(*GetManager<IEnvironmentComponentManager>(ecs)),
222 weatherManager_(*GetManager<IWeatherComponentManager>(ecs)),
223 rippleComponentManager_(*GetManager<IWaterRippleComponentManager>(ecs))
224 {
225 IClassRegister *cr = ecs.GetClassFactory().GetInterface<IClassRegister>();
226 if (cr) {
227 renderContext_ = GetInstance<IRenderContext>(*cr, UID_RENDER_CONTEXT);
228 if (renderContext_) {
229 auto rcClassReg = renderContext_->GetInterface<IClassRegister>();
230 if (rcClassReg) {
231 graphicsContext_ = GetInstance<IGraphicsContext>(*rcClassReg, UID_GRAPHICS_CONTEXT);
232 }
233 gpuResourceManager_ = &renderContext_->GetDevice().GetGpuResourceManager();
234 renderDataStoreManager_ = &renderContext_->GetRenderDataStoreManager();
235 }
236 } else {
237 CORE_LOG_E("get null ClassRegister");
238 }
239
240 ecs.AddListener(rippleComponentManager_, *this);
241 Initialize();
242 }
243
GetMaterialEntity(const Entity & entity)244 Entity WeatherSystem::GetMaterialEntity(const Entity& entity)
245 {
246 Entity materialEntity;
247 if (const auto rmcHandle = renderMeshManager_.Read(entity); rmcHandle) {
248 const RenderMeshComponent& rmc = *rmcHandle;
249 if (const auto meshHandle = meshManager_.Read(rmc.mesh); meshHandle) {
250 const MeshComponent& meshComponent = *meshHandle;
251 if (!meshComponent.submeshes.empty()) {
252 materialEntity = meshComponent.submeshes[0].material;
253 }
254 }
255 }
256 return materialEntity;
257 }
258
GetOrCreateSimulationResources(const Entity & entity)259 WeatherSystem::RipplePlaneResources WeatherSystem::GetOrCreateSimulationResources(const Entity& entity)
260 {
261 if (!graphicsContext_) {
262 CORE_LOG_E("null graphicsContext");
263 return {};
264 }
265 auto iter = handleResources_.find(entity);
266 if (iter != handleResources_.end()) {
267 return iter->second;
268 }
269 auto res = CreateSimulationResourcesForEntity(ecs_, *graphicsContext_, entity);
270 handleResources_.insert({ entity, res });
271 return res;
272 }
273
Initialize()274 void WeatherSystem::Initialize()
275 {
276 const ComponentQuery::Operation operations[] = { { rippleComponentManager_, ComponentQuery::Operation::OPTIONAL } };
277 query_.SetEcsListenersEnabled(true);
278 query_.SetupQuery(rippleComponentManager_, operations);
279 prevPlanePos_ = Math::Vec3(0.0f, 0.0f, 0.0f);
280
281 // NOTE: data store is done deferred way in the update
282 }
283
Uninitialize()284 void WeatherSystem::Uninitialize()
285 {
286 query_.SetEcsListenersEnabled(false);
287 }
288
~WeatherSystem()289 WeatherSystem ::~WeatherSystem()
290 {
291 Uninitialize();
292 ecs_.RemoveListener(rippleComponentManager_, *this);
293 for (auto& kvpair : handleResources_) {
294 kvpair.second = {};
295 }
296 }
297
SetActive(bool state)298 void WeatherSystem::SetActive(bool state)
299 {
300 active_ = state;
301 }
302
IsActive() const303 bool WeatherSystem::IsActive() const
304 {
305 return active_;
306 }
307
GetName() const308 string_view WeatherSystem::GetName() const
309 {
310 return ::GetName(this);
311 }
312
GetUid() const313 Uid WeatherSystem::GetUid() const
314 {
315 return UID;
316 }
317
GetProperties()318 IPropertyHandle* WeatherSystem::GetProperties()
319 {
320 return nullptr;
321 }
322
GetProperties() const323 const IPropertyHandle* WeatherSystem::GetProperties() const
324 {
325 return nullptr;
326 }
327
SetProperties(const IPropertyHandle & dataHandle)328 void WeatherSystem::SetProperties(const IPropertyHandle& dataHandle) {}
329
GetECS() const330 const IEcs& WeatherSystem::GetECS() const
331 {
332 return ecs_;
333 }
334
GetResDivider(RenderDataStoreWeather::CloudRenderingType crt)335 inline constexpr uint32_t GetResDivider(RenderDataStoreWeather::CloudRenderingType crt)
336 {
337 if (crt == RenderDataStoreWeather::CloudRenderingType::REPROJECTED) {
338 return 4U;
339 } else if (crt == RenderDataStoreWeather::CloudRenderingType::DOWNSCALED) {
340 return 2U;
341 } else {
342 return 1U;
343 }
344 }
345
Update(bool frameRenderingQueued,uint64_t,uint64_t delta)346 bool WeatherSystem::Update(bool frameRenderingQueued, uint64_t /* time */, uint64_t delta)
347 {
348 if (!renderContext_ || !renderDataStoreManager_) {
349 CORE_LOG_E("null renderContext or renderDataStoreManager");
350 return false;
351 }
352 if (!active_) {
353 return false;
354 }
355
356 if (!dataStoreWeather_) {
357 string dsName;
358 if (IRenderPreprocessorSystem* rpSystem = GetSystem<IRenderPreprocessorSystem>(ecs_); rpSystem) {
359 if (const auto in = ScopedHandle<IRenderPreprocessorSystem::Properties>(rpSystem->GetProperties()); in) {
360 dsName = in->dataStorePrefix;
361 }
362 }
363 dsName += RenderDataStoreWeather::TYPE_NAME;
364 dataStoreWeather_ = refcnt_ptr<RenderDataStoreWeather>(
365 renderDataStoreManager_->Create(RenderDataStoreWeather::UID, dsName.c_str()));
366 }
367 if (!dataStoreWeather_) {
368 return false;
369 }
370
371 query_.Execute();
372
373 ProcessWaterRipples();
374
375 if (const auto weatherGeneration = weatherManager_.GetGenerationCounter();
376 weatherGeneration_ != weatherGeneration) {
377 weatherGeneration_ = weatherGeneration;
378 const auto weatherComponents = weatherManager_.GetComponentCount();
379 for (auto id = 0U; id < weatherComponents; ++id) {
380 auto handle = weatherManager_.Read(id);
381 if (!handle) {
382 continue;
383 }
384 RenderDataStoreWeather::WeatherSettings settings;
385 settings.windSpeed = handle->windSpeed;
386 settings.density = handle->density;
387 settings.cloudType = handle->cloudType;
388 settings.coverage = handle->coverage;
389 settings.precipitation = handle->precipitation;
390
391 settings.windDir[0] = handle->windDir.x;
392 settings.windDir[1] = handle->windDir.y;
393 settings.windDir[2] = handle->windDir.z;
394
395 settings.sunPos[0] = handle->sunPos.x;
396 settings.sunPos[1] = handle->sunPos.y;
397 settings.sunPos[2] = handle->sunPos.z;
398
399 settings.silverIntensity = handle->silverIntensity;
400 settings.silverSpread = handle->silverSpread;
401 settings.direct = handle->direct;
402 settings.ambient = handle->ambient;
403 settings.lightStep = handle->lightStep;
404 settings.scatteringDist = handle->scatteringDist;
405 settings.precipitation = handle->precipitation;
406
407 settings.domain[0] = handle->domain[0];
408 settings.domain[1] = handle->domain[1];
409 settings.domain[2] = handle->domain[2];
410 settings.domain[3] = handle->domain[3];
411 settings.domain[4] = handle->domain[4];
412
413 settings.anvil_bias = handle->anvilBias;
414 settings.brightness = handle->brightness;
415 settings.eccintricity = handle->eccintricity;
416
417 settings.cloudRenderingType = GetCloudRenderingType(handle->cloudRenderingType);
418
419 // store
420 cloudMatData_.cloudRenderingType = settings.cloudRenderingType;
421
422 if (auto* rhm = GetManager<IRenderHandleComponentManager>(ecs_)) {
423 settings.lowFrequencyImage = rhm->GetRenderHandle(handle->lowFrequencyImage);
424 settings.highFrequencyImage = rhm->GetRenderHandle(handle->highFrequencyImage);
425 settings.curlNoiseImage = rhm->GetRenderHandle(handle->curlNoiseImage);
426 settings.cirrusImage = rhm->GetRenderHandle(handle->cirrusImage);
427 settings.weatherMapImage = rhm->GetRenderHandle(handle->weatherMapImage);
428 }
429 dataStoreWeather_->SetWeatherSettings(weatherManager_.GetEntity(id).id, settings);
430 }
431 }
432
433 // get largest camera resolution
434
435 // first check if there are any weather components
436 const auto wcCount = weatherManager_.GetComponentCount();
437 // then check the usage with cameras
438 Math::UVec2 maxRes { 0U, 0U };
439 Entity camEntity;
440 if (wcCount > 0) {
441 bool usesWeather { false };
442 if (const auto count = renderConfigManager_.GetComponentCount(); count > 0U) {
443 if (const auto rcHandle = renderConfigManager_.Read(renderConfigManager_.GetEntity(0U)); rcHandle) {
444 if (const auto envHandle = envManager_.Read(rcHandle->environment); envHandle) {
445 if (envHandle->weather) {
446 usesWeather = true;
447 }
448 }
449 }
450 }
451 const auto cameraCount = camManager_.GetComponentCount();
452 for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
453 ScopedHandle<const CameraComponent> handle = camManager_.Read(id);
454 const CameraComponent& component = *handle;
455 bool checkRes = usesWeather;
456 if (auto envHandle = envManager_.Read(component.environment); envHandle) {
457 if (envHandle->weather) {
458 checkRes = true;
459 }
460 }
461 if (checkRes) {
462 maxRes.x = Math::max(maxRes.x, component.renderResolution.x);
463 maxRes.y = Math::max(maxRes.y, component.renderResolution.y);
464
465 camEntity = camManager_.GetEntity(id);
466 }
467 }
468
469 // possible resize
470 auto& cm = cloudMatData_;
471
472 const uint32_t resDevider = GetResDivider(cm.cloudRenderingType);
473 maxRes.x = maxRes.x / resDevider;
474 maxRes.y = maxRes.y / resDevider;
475
476 const bool nonZero = (maxRes.x > 0) && (maxRes.y > 0);
477 if (nonZero && ((cm.gpuImageDesc.width != maxRes.x) || (cm.gpuImageDesc.height != maxRes.y))) {
478 cm.gpuImageDesc.width = maxRes.x;
479 cm.gpuImageDesc.height = maxRes.y;
480
481 cm.cloudTexHandle = renderContext_->GetDevice().GetGpuResourceManager().Create(
482 DefaultMaterialCameraConstants::CAMERA_COLOR_PREFIX_NAME + "CLOUD", cm.gpuImageDesc);
483 cm.cloudPrevTexHandle = renderContext_->GetDevice().GetGpuResourceManager().Create(
484 DefaultMaterialCameraConstants::CAMERA_COLOR_PREFIX_NAME + "CLOUD_PREV", cm.gpuImageDesc);
485 cm.cloudTexture = GetOrCreateEntityReference(ecs_, cm.cloudTexHandle);
486 cm.cloudPrevTexture = GetOrCreateEntityReference(ecs_, cm.cloudPrevTexHandle);
487
488 UpdateCloudMaterial(camEntity);
489 }
490 }
491
492 return frameRenderingQueued;
493 }
494
ProcessWaterRipples()495 void WeatherSystem::ProcessWaterRipples()
496 {
497 if (!graphicsContext_) {
498 CORE_LOG_E("null graphicsContext");
499 return;
500 }
501 const auto queryResult = query_.GetResults();
502 if (queryResult.empty()) {
503 return;
504 }
505
506 auto* nodeSystem = GetSystem<INodeSystem>(ecs_);
507 // find a water plane name "water effect plane"
508 if (!EntityUtil::IsValid(waterEffectsPlane.entity)) {
509 if (auto find = nodeSystem->GetRootNode().LookupNodeByName("water effect plane"); find) {
510 auto e = find->GetEntity();
511 waterEffectsPlane.entity = e;
512 waterEffectsPlane.matEntity = GetMaterialEntity(e);
513 }
514 }
515
516 Math::Vec3 planeCenter;
517
518 if (auto transComponentHandle = transformationManager_.Read(waterEffectsPlane.entity)) {
519 const TransformComponent& transComponent = *transComponentHandle;
520 planeCenter = transComponent.position;
521 Math::Vec2 offset = Math::Vec2(planeCenter.x - prevPlanePos_.x, planeCenter.z - prevPlanePos_.z);
522
523 const IClassRegister* cr = graphicsContext_->GetRenderContext().GetInterface<IClassRegister>();
524 if (cr == nullptr) {
525 CORE_LOG_E("get null ClassRegister");
526 return;
527 }
528 const auto pickingUtil = GetInstance<IPicking>(*cr, UID_PICKING);
529 if (pickingUtil == nullptr) {
530 CORE_LOG_E("get null IPicking");
531 return;
532 }
533 const auto mam = pickingUtil->GetWorldMatrixComponentAABB(waterEffectsPlane.entity, false, ecs_);
534
535 const Math::Vec3 aabbMin = mam.minAABB;
536 const Math::Vec3 aabbMax = mam.maxAABB;
537 const float width = Math::max(aabbMax.x - aabbMin.x, 1.0f);
538 const float depth = Math::max(aabbMax.z - aabbMin.z, 1.0f);
539
540 vec2 texelPerMeter = vec2(float(RESOLUTION), float(RESOLUTION));
541 offset.x = Math::round(offset.x * texelPerMeter.x / width);
542 offset.y = Math::round(offset.y * texelPerMeter.y / depth);
543
544 dataStoreWeather_->SetWaterEffect(waterEffectsPlane.entity.id, offset);
545 prevPlanePos_ = planeCenter;
546 }
547
548 const auto IntersectAabb = [this](const Math::Vec3& worldXYZ, Math::Vec2& inPlaneUv) -> bool {
549 IClassRegister* cr = graphicsContext_->GetRenderContext().GetInterface<IClassRegister>();
550 if (cr == nullptr) {
551 CORE_LOG_E("get null ClassRegister");
552 return false;
553 }
554 const auto pickingUtil = GetInstance<IPicking>(*cr, UID_PICKING);
555 if (pickingUtil == nullptr) {
556 CORE_LOG_E("get null IPicking");
557 return false;
558 }
559 const auto mam = pickingUtil->GetWorldMatrixComponentAABB(waterEffectsPlane.entity, false, ecs_);
560
561 Math::Vec3 aabbMin = mam.minAABB;
562 Math::Vec3 aabbMax = mam.maxAABB;
563 constexpr float epsilon = FLT_EPSILON;
564
565 bool xInRange = worldXYZ.x >= (aabbMin.x - epsilon) && worldXYZ.x <= (aabbMax.x + epsilon);
566 bool yInRange = worldXYZ.y >= (aabbMin.y - epsilon) && worldXYZ.y <= (aabbMax.y + epsilon);
567 bool zInRange = worldXYZ.z >= (aabbMin.z - epsilon) && worldXYZ.z <= (aabbMax.z + epsilon);
568
569 if (xInRange && yInRange && zInRange) {
570 inPlaneUv.x = (worldXYZ.x - aabbMin.x) / (aabbMax.x - aabbMin.x);
571 inPlaneUv.y = (worldXYZ.z - aabbMin.z) / (aabbMax.z - aabbMin.z);
572 return true;
573 } else {
574 return false;
575 }
576 };
577
578 for (const auto& row : queryResult) {
579 const auto& entityWithRippleComponent = row.entity;
580
581 if (EntityUtil::IsValid(entityWithRippleComponent)) {
582 // get position from node system
583 auto nodePtr = nodeSystem->GetNode(entityWithRippleComponent);
584 Math::Vec3 nodePosition = nodePtr->GetPosition();
585 auto parentNode = nodePtr->GetParent();
586 while (parentNode) {
587 nodePosition += parentNode->GetPosition();
588 parentNode = parentNode->GetParent();
589 }
590
591 if (auto componentHandle = rippleComponentManager_.Read(row.components[0U]); componentHandle) {
592 const WaterRippleComponent& rippleComponent = *componentHandle;
593 constexpr bool active = true;
594 if (active) {
595 Math::Vec3 rippleWorldPosition = rippleComponent.position + nodePosition;
596 Math::Vec2 inUv;
597 if (IntersectAabb(rippleWorldPosition, inUv)) {
598 const auto intersectXGrid = uint32_t((1.f - inUv.x) * RESOLUTION);
599 const auto intersectYGrid = uint32_t((1.f - inUv.y) * RESOLUTION);
600 const Math::UVec2 newPos = { intersectXGrid, intersectYGrid };
601
602 newRippleToAdd_.push_back({ entityWithRippleComponent, newPos });
603 }
604 }
605 }
606 }
607 }
608
609 // update ripple input args buffer for compute shader
610 DefaultWaterRippleDataStruct inputArgs;
611 inputArgs.inArgs = { 0U, 0U, RESOLUTION, RESOLUTION };
612
613 if (!newRippleToAdd_.empty()) {
614 const auto newToAdd = uint32_t(newRippleToAdd_.size());
615 uint32_t idx = 0U;
616 for (; idx < newToAdd && idx < 8U; idx++) {
617 inputArgs.newRipplePositions[idx] = newRippleToAdd_[idx].second;
618 }
619
620 newRippleToAdd_.erase(newRippleToAdd_.cbegin(), newRippleToAdd_.cbegin() + idx);
621 inputArgs.inArgs.x = 1;
622 }
623
624 RipplePlaneResources res = GetOrCreateSimulationResources(waterEffectsPlane.entity);
625
626 auto& dataStoreManager = graphicsContext_->GetRenderContext().GetRenderDataStoreManager();
627 if (auto rdsDefaultStaging = refcnt_ptr<IRenderDataStoreDefaultStaging>(
628 dataStoreManager.GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING))) {
629 const auto& inputArgsBufferHandle = renderHandleManager_.GetRenderHandleReference(res.rippleArgsBufferHandle);
630 array_view<const uint8_t> data((const uint8_t*)&inputArgs, sizeof(DefaultWaterRippleDataStruct));
631 const BufferCopy bufferCopy { 0, 0, sizeof(DefaultWaterRippleDataStruct) };
632 rdsDefaultStaging->CopyDataToBuffer(data, inputArgsBufferHandle, bufferCopy);
633 }
634 }
635
UpdateCloudMaterial(const CORE_NS::Entity camEntity)636 void WeatherSystem::UpdateCloudMaterial(const CORE_NS::Entity camEntity)
637 {
638 if (!renderContext_) {
639 CORE_LOG_E("null renderContext");
640 return;
641 }
642 // create only once
643 if (!EntityUtil::IsValid(cloudMatData_.renderMeshEntity)) {
644 IEntityManager& em = ecs_.GetEntityManager();
645 cloudMatData_.meshEntity = em.CreateReferenceCounted();
646 cloudMatData_.matEntity = em.CreateReferenceCounted();
647
648 materialManager_.Create(cloudMatData_.matEntity);
649 meshManager_.Create(cloudMatData_.meshEntity);
650
651 // node for render processing
652 if (auto* nodeSystem = GetSystem<INodeSystem>(ecs_); nodeSystem) {
653 if (auto* cloudScene = nodeSystem->CreateNode(); cloudScene) {
654 cloudMatData_.renderMeshEntity = cloudScene->GetEntity();
655 }
656 }
657 renderMeshManager_.Create(cloudMatData_.renderMeshEntity);
658
659 // material
660 if (auto handle = materialManager_.Write(cloudMatData_.matEntity); handle) {
661 IShaderManager& shaderMgr = renderContext_->GetDevice().GetShaderManager();
662 const auto shader = shaderMgr.GetShaderHandle(CLOUD_SHADER_NAME);
663 handle->materialShader.shader = GetOrCreateEntityReference(ecs_, shader);
664 handle->textures[MaterialComponent::BASE_COLOR].image = cloudMatData_.cloudTexture;
665 handle->textures[MaterialComponent::NORMAL].image = cloudMatData_.cloudPrevTexture;
666 handle->materialLightingFlags = 0U; // disable all lighting
667
668 // camera effect
669 handle->cameraEntity = camEntity;
670 }
671 if (auto handle = meshManager_.Write(cloudMatData_.meshEntity); handle) {
672 handle->submeshes.clear();
673 handle->submeshes.push_back({});
674 if (!handle->submeshes.empty()) {
675 handle->submeshes[0U].instanceCount = 1U;
676 handle->submeshes[0U].vertexCount = 3U;
677 handle->submeshes[0U].material = cloudMatData_.matEntity;
678 }
679 }
680 if (auto handle = renderMeshManager_.Write(cloudMatData_.renderMeshEntity); handle) {
681 handle->mesh = cloudMatData_.meshEntity;
682 }
683 }
684 // update material textures
685 // should not come here if the textures are not changed
686 if (auto handle = materialManager_.Write(cloudMatData_.matEntity); handle) {
687 // flip info should be provided in the shader
688 handle->textures[MaterialComponent::BASE_COLOR].image = cloudMatData_.cloudTexture;
689 handle->textures[MaterialComponent::NORMAL].image = cloudMatData_.cloudPrevTexture;
690 }
691 }
692
OnComponentEvent(EventType type,const IComponentManager & componentManager,const array_view<const Entity> entities)693 void WeatherSystem::OnComponentEvent(
694 EventType type, const IComponentManager& componentManager, const array_view<const Entity> entities)
695 {}
696
IWeatherSystemInstance(IEcs & ecs)697 CORE_NS::ISystem* IWeatherSystemInstance(IEcs& ecs)
698 {
699 return new WeatherSystem(ecs);
700 }
701
IWeatherSystemDestroy(CORE_NS::ISystem * instance)702 void IWeatherSystemDestroy(CORE_NS::ISystem* instance)
703 {
704 delete static_cast<WeatherSystem*>(instance);
705 }
706 CORE3D_END_NAMESPACE()
707