• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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