no message
This commit is contained in:
210
cocos/scene/Ambient.cpp
Normal file
210
cocos/scene/Ambient.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Ambient.h"
|
||||
#include "core/Root.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/RenderPipeline.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
|
||||
namespace {
|
||||
cc::Color col;
|
||||
|
||||
// Normalize HDR color
|
||||
void normalizeHDRColor(cc::Vec4 &color) {
|
||||
const float intensity = 1.F / std::max(std::max(std::max(color.x, color.y), color.z), 0.0001F);
|
||||
if (intensity < 1.F) {
|
||||
color.x *= intensity;
|
||||
color.y *= intensity;
|
||||
color.z *= intensity;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
void AmbientInfo::setSkyLightingColor(const Color &val) {
|
||||
Vec4 v4(static_cast<float>(val.r) / 255.F, static_cast<float>(val.g) / 255.F, static_cast<float>(val.b) / 255.F, static_cast<float>(val.a) / 255.F);
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_skyColorHDR.set(v4);
|
||||
} else {
|
||||
_skyColorLDR.set(v4);
|
||||
}
|
||||
if (_resource != nullptr) {
|
||||
_resource->setSkyColor(v4);
|
||||
}
|
||||
}
|
||||
|
||||
const Color &AmbientInfo::getSkyLightingColor() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
Vec4 v4(isHDR ? _skyColorHDR : _skyColorLDR);
|
||||
normalizeHDRColor(v4);
|
||||
col.set(static_cast<uint8_t>(v4.x * 255.F), static_cast<uint8_t>(v4.y * 255.F), static_cast<uint8_t>(v4.z * 255.F), 255);
|
||||
return col;
|
||||
}
|
||||
|
||||
void AmbientInfo::setSkyColor(const Vec4 &val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_skyColorHDR.set(val);
|
||||
} else {
|
||||
_skyColorLDR.set(val);
|
||||
}
|
||||
if (_resource != nullptr) {
|
||||
_resource->setSkyColor(val);
|
||||
}
|
||||
}
|
||||
|
||||
void AmbientInfo::setSkyIllum(float val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_skyIllumHDR = val;
|
||||
|
||||
} else {
|
||||
_skyIllumLDR = val;
|
||||
}
|
||||
|
||||
if (_resource != nullptr) {
|
||||
_resource->setSkyIllum(val);
|
||||
}
|
||||
}
|
||||
|
||||
float AmbientInfo::getSkyIllum() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _skyIllumHDR : _skyIllumLDR;
|
||||
}
|
||||
|
||||
void AmbientInfo::setGroundLightingColor(const Color &val) {
|
||||
const Vec4 v4(static_cast<float>(val.r) / 255.F, static_cast<float>(val.g) / 255.F, static_cast<float>(val.b) / 255.F, static_cast<float>(val.a) / 255.F);
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_groundAlbedoHDR.set(v4);
|
||||
} else {
|
||||
_groundAlbedoLDR.set(v4);
|
||||
}
|
||||
|
||||
if (_resource != nullptr) {
|
||||
_resource->setGroundAlbedo(v4);
|
||||
}
|
||||
}
|
||||
|
||||
const Color &AmbientInfo::getGroundLightingColor() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
Vec4 v4(isHDR ? _groundAlbedoHDR : _groundAlbedoLDR);
|
||||
normalizeHDRColor(v4);
|
||||
col.set(static_cast<uint8_t>(v4.x * 255.F), static_cast<uint8_t>(v4.y * 255.F), static_cast<uint8_t>(v4.z * 255.F), 255);
|
||||
return col;
|
||||
}
|
||||
|
||||
void AmbientInfo::setGroundAlbedo(const Vec4 &val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_groundAlbedoHDR.set(val);
|
||||
} else {
|
||||
_groundAlbedoLDR.set(val);
|
||||
}
|
||||
|
||||
if (_resource != nullptr) {
|
||||
_resource->setGroundAlbedo(val);
|
||||
}
|
||||
}
|
||||
|
||||
void AmbientInfo::activate(Ambient *resource) {
|
||||
_resource = resource;
|
||||
_resource->initialize(this);
|
||||
}
|
||||
|
||||
//
|
||||
void Ambient::initialize(AmbientInfo *info) {
|
||||
// setSkyColor(info->getSkyColor());
|
||||
// setGroundAlbedo(info->getGroundAlbedo());
|
||||
// _skyIllum = info->getSkyIllum();
|
||||
|
||||
// Init HDR/LDR from serialized data on load
|
||||
_skyColorHDR = info->getSkyColorHDR();
|
||||
_groundAlbedoHDR.set(info->getGroundAlbedoHDR());
|
||||
_skyIllumHDR = info->getSkyIllumHDR();
|
||||
_skyColorLDR = info->getSkyColorLDR();
|
||||
_groundAlbedoLDR.set(info->getGroundAlbedoLDR());
|
||||
_skyIllumLDR = info->getSkyIllumLDR();
|
||||
}
|
||||
|
||||
Vec4 &Ambient::getSkyColor() {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _skyColorHDR : _skyColorLDR;
|
||||
}
|
||||
|
||||
const Vec4 &Ambient::getSkyColor() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _skyColorHDR : _skyColorLDR;
|
||||
}
|
||||
|
||||
void Ambient::setSkyColor(const Vec4 &color) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_skyColorHDR.set(color);
|
||||
} else {
|
||||
_skyColorLDR.set(color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Sky illuminance
|
||||
* @zh 天空亮度
|
||||
*/
|
||||
float Ambient::getSkyIllum() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _skyIllumHDR : _skyIllumLDR;
|
||||
}
|
||||
void Ambient::setSkyIllum(float illum) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_skyIllumHDR = illum;
|
||||
} else {
|
||||
_skyIllumLDR = illum;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Ground color
|
||||
* @zh 地面颜色
|
||||
*/
|
||||
const Vec4 &Ambient::getGroundAlbedo() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _groundAlbedoHDR : _groundAlbedoLDR;
|
||||
}
|
||||
|
||||
void Ambient::setGroundAlbedo(const Vec4 &color) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_groundAlbedoHDR.set(color);
|
||||
} else {
|
||||
_groundAlbedoLDR.set(color);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
196
cocos/scene/Ambient.h
Normal file
196
cocos/scene/Ambient.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/array.h"
|
||||
#include "math/Color.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class AmbientInfo;
|
||||
|
||||
class Ambient final {
|
||||
public:
|
||||
friend class Skybox;
|
||||
|
||||
static constexpr float SUN_ILLUM{65000.0F};
|
||||
static constexpr float SKY_ILLUM{20000.0F};
|
||||
|
||||
Ambient(/* args */) = default;
|
||||
~Ambient() = default;
|
||||
|
||||
void initialize(AmbientInfo *info);
|
||||
|
||||
/**
|
||||
* @en Enable ambient
|
||||
* @zh 是否开启环境光
|
||||
*/
|
||||
inline void setEnabled(bool val) { _enabled = val; }
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
|
||||
/**
|
||||
* @en Sky color
|
||||
* @zh 天空颜色
|
||||
*/
|
||||
|
||||
Vec4 &getSkyColor();
|
||||
const Vec4 &getSkyColor() const;
|
||||
void setSkyColor(const Vec4 &color);
|
||||
|
||||
/**
|
||||
* @en Sky illuminance
|
||||
* @zh 天空亮度
|
||||
*/
|
||||
float getSkyIllum() const;
|
||||
void setSkyIllum(float illum);
|
||||
|
||||
/**
|
||||
* @en Ground color
|
||||
* @zh 地面颜色
|
||||
*/
|
||||
const Vec4 &getGroundAlbedo() const;
|
||||
void setGroundAlbedo(const Vec4 &color);
|
||||
|
||||
inline uint8_t getMipmapCount() const { return _mipmapCount; }
|
||||
inline void setMipmapCount(uint8_t count) { _mipmapCount = count; }
|
||||
|
||||
protected:
|
||||
Vec4 _groundAlbedoHDR{0.2F, 0.2F, 0.2F, 1.F};
|
||||
Vec4 _skyColorHDR{0.2F, 0.5F, 0.8F, 1.F};
|
||||
float _skyIllumHDR{0.F};
|
||||
|
||||
Vec4 _groundAlbedoLDR{0.2F, 0.2F, 0.2F, 1.F};
|
||||
Vec4 _skyColorLDR{0.2F, 0.5F, 0.8F, 1.F};
|
||||
float _skyIllumLDR{0.F};
|
||||
uint8_t _mipmapCount{1};
|
||||
|
||||
bool _enabled{false};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Ambient);
|
||||
};
|
||||
|
||||
/**
|
||||
* @en Environment lighting information in the Scene
|
||||
* @zh 场景的环境光照相关信息
|
||||
*/
|
||||
// @ccclass('cc.AmbientInfo')
|
||||
// @help('i18n:cc.Ambient')
|
||||
class AmbientInfo : public RefCounted {
|
||||
public:
|
||||
AmbientInfo(/* args */) = default;
|
||||
~AmbientInfo() override = default;
|
||||
|
||||
inline void setSkyColorHDR(const Vec4 &val) { _skyColorHDR.set(val); };
|
||||
inline const Vec4 &getSkyColorHDR() const { return _skyColorHDR; };
|
||||
inline const Vec4 &getSkyColorLDR() const { return _skyColorLDR; };
|
||||
|
||||
inline void setGroundAlbedoHDR(const Vec4 &val) { _groundAlbedoHDR.set(val); };
|
||||
inline const Vec4 &getGroundAlbedoHDR() const { return _groundAlbedoHDR; };
|
||||
inline const Vec4 &getGroundAlbedoLDR() const { return _groundAlbedoLDR; };
|
||||
|
||||
inline void setSkyIllumHDR(float val) { _skyIllumHDR = val; };
|
||||
inline const float &getSkyIllumHDR() const { return _skyIllumHDR; };
|
||||
inline const float &getSkyIllumLDR() const { return _skyIllumLDR; };
|
||||
|
||||
/**
|
||||
* @en Sky lighting color configurable in editor with color picker
|
||||
* @zh 编辑器中可配置的天空光照颜色(通过颜色拾取器)
|
||||
*/
|
||||
// @visible(() => {
|
||||
// const scene = legacyCC.director.getScene();
|
||||
// const skybox = scene.globals.skybox;
|
||||
// if (skybox.useIBL && skybox.applyDiffuseMap) {
|
||||
// return false;
|
||||
// } else {
|
||||
// return true;
|
||||
// }
|
||||
// })
|
||||
// @editable
|
||||
// @tooltip('i18n:ambient.skyLightingColor')
|
||||
void setSkyLightingColor(const Color &val);
|
||||
const Color &getSkyLightingColor() const;
|
||||
|
||||
void setSkyColor(const Vec4 &val);
|
||||
|
||||
/**
|
||||
* @en Sky illuminance
|
||||
* @zh 天空亮度
|
||||
*/
|
||||
// @editable
|
||||
// @type(CCFloat)
|
||||
// @tooltip('i18n:ambient.skyIllum')
|
||||
void setSkyIllum(float val);
|
||||
float getSkyIllum() const;
|
||||
|
||||
/**
|
||||
* @en Ground lighting color configurable in editor with color picker
|
||||
* @zh 编辑器中可配置的地面光照颜色(通过颜色拾取器)
|
||||
*/
|
||||
// @visible(() => {
|
||||
// const scene = legacyCC.director.getScene();
|
||||
// const skybox = scene.globals.skybox;
|
||||
// if (skybox.useIBL && skybox.applyDiffuseMap) {
|
||||
// return false;
|
||||
// } else {
|
||||
// return true;
|
||||
// }
|
||||
// })
|
||||
// @editable
|
||||
// @tooltip('i18n:ambient.groundLightingColor')
|
||||
void setGroundLightingColor(const Color &val);
|
||||
const Color &getGroundLightingColor() const;
|
||||
|
||||
void setGroundAlbedo(const Vec4 &val);
|
||||
|
||||
void activate(Ambient *resource);
|
||||
|
||||
// cjh JSB need to bind the property, so need to make it public
|
||||
// @serializable
|
||||
// @formerlySerializedAs('_skyColor'));
|
||||
Vec4 _skyColorHDR{0.2F, 0.5F, 0.8F, 1.F};
|
||||
// @serializable
|
||||
// @formerlySerializedAs('_skyIllum')
|
||||
float _skyIllumHDR{Ambient::SKY_ILLUM};
|
||||
// @serializable
|
||||
// @formerlySerializedAs('_groundAlbedo')
|
||||
Vec4 _groundAlbedoHDR{0.2F, 0.2F, 0.2F, 1.F};
|
||||
|
||||
// @serializable
|
||||
Vec4 _skyColorLDR{0.2F, 0.5F, 0.8F, 1.F};
|
||||
|
||||
// @serializable
|
||||
float _skyIllumLDR{Ambient::SKY_ILLUM};
|
||||
// @serializable
|
||||
Vec4 _groundAlbedoLDR{0.2F, 0.2F, 0.2F, 1.F};
|
||||
|
||||
private:
|
||||
Ambient *_resource{nullptr};
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
486
cocos/scene/Camera.cpp
Normal file
486
cocos/scene/Camera.cpp
Normal file
@@ -0,0 +1,486 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Camera.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "math/MathUtil.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
#if CC_USE_GEOMETRY_RENDERER
|
||||
#include "renderer/pipeline/GeometryRenderer.h"
|
||||
#endif
|
||||
#include "application/ApplicationManager.h"
|
||||
#include "platform/interfaces/modules/IXRInterface.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
namespace {
|
||||
ccstd::array<Mat4, 4> correctionMatrices;
|
||||
|
||||
void assignMat4(Mat4 &mat4, float m0, float m1, float m2, float m3, float m4, float m5) {
|
||||
mat4.m[0] = m0;
|
||||
mat4.m[1] = m1;
|
||||
mat4.m[2] = m2;
|
||||
mat4.m[3] = m3;
|
||||
mat4.m[4] = m4;
|
||||
mat4.m[5] = m5;
|
||||
}
|
||||
|
||||
constexpr ccstd::array<ccstd::array<float, 4>, 4> PRE_TRANSFORMS = {{
|
||||
{{1, 0, 0, 1}}, // SurfaceTransform.IDENTITY
|
||||
{{0, 1, -1, 0}}, // SurfaceTransform.ROTATE_90
|
||||
{{-1, 0, 0, -1}}, // SurfaceTransform.ROTATE_180
|
||||
{{0, -1, 1, 0}} // SurfaceTransform.ROTATE_270
|
||||
}};
|
||||
|
||||
} // namespace
|
||||
|
||||
const ccstd::vector<float> Camera::FSTOPS{1.8F, 2.0F, 2.2F, 2.5F, 2.8F, 3.2F, 3.5F, 4.0F, 4.5F, 5.0F, 5.6F, 6.3F, 7.1F, 8.0F, 9.0F, 10.0F, 11.0F, 13.0F, 14.0F, 16.0F, 18.0F, 20.0F, 22.0F};
|
||||
const ccstd::vector<float> Camera::SHUTTERS{1.0F, 1.0F / 2.0F, 1.0F / 4.0F, 1.0F / 8.0F, 1.0F / 15.0F, 1.0F / 30.0F, 1.0F / 60.0F, 1.0F / 125.0F,
|
||||
1.0F / 250.0F, 1.0F / 500.0F, 1.0F / 1000.0F, 1.0F / 2000.0F, 1.0F / 4000.0F};
|
||||
const ccstd::vector<float> Camera::ISOS{100.0F, 200.0F, 400.0F, 800.0F};
|
||||
|
||||
Camera::Camera(gfx::Device *device)
|
||||
: _device(device) {
|
||||
_apertureValue = Camera::FSTOPS.at(static_cast<int>(_aperture));
|
||||
_shutterValue = Camera::SHUTTERS.at(static_cast<int>(_shutter));
|
||||
_isoValue = Camera::ISOS[static_cast<int>(_iso)];
|
||||
|
||||
_aspect = _screenScale = 1.F;
|
||||
_frustum = ccnew geometry::Frustum();
|
||||
_frustum->addRef();
|
||||
_frustum->setAccurate(true);
|
||||
|
||||
if (correctionMatrices.empty()) {
|
||||
float ySign = _device->getCapabilities().clipSpaceSignY;
|
||||
assignMat4(correctionMatrices[static_cast<int>(gfx::SurfaceTransform::IDENTITY)], 1.F, 0, 0, 0, 0, ySign);
|
||||
assignMat4(correctionMatrices[static_cast<int>(gfx::SurfaceTransform::ROTATE_90)], 0, 1.F, 0, 0, -ySign, 0);
|
||||
assignMat4(correctionMatrices[static_cast<int>(gfx::SurfaceTransform::ROTATE_180)], -1, 0, 0, 0, 0, -ySign);
|
||||
assignMat4(correctionMatrices[static_cast<int>(gfx::SurfaceTransform::ROTATE_270)], 0, -1, 0, 0, ySign, 0);
|
||||
}
|
||||
_xr = CC_GET_XR_INTERFACE();
|
||||
}
|
||||
|
||||
Camera::~Camera() = default;
|
||||
|
||||
bool Camera::initialize(const ICameraInfo &info) {
|
||||
_usage = info.usage;
|
||||
_trackingType = info.trackingType;
|
||||
_cameraType = info.cameraType;
|
||||
_node = info.node;
|
||||
_width = 1.F;
|
||||
_height = 1.F;
|
||||
_clearFlag = gfx::ClearFlagBit::NONE;
|
||||
_clearDepth = 1.0F;
|
||||
_visibility = pipeline::CAMERA_DEFAULT_MASK;
|
||||
_name = info.name;
|
||||
_proj = info.projection;
|
||||
_priority = info.priority;
|
||||
_aspect = _screenScale = 1.F;
|
||||
updateExposure();
|
||||
changeTargetWindow(info.window);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Camera::destroy() {
|
||||
detachFromScene();
|
||||
if (_window) {
|
||||
_window->detachCamera(this);
|
||||
_window = nullptr;
|
||||
}
|
||||
_name.clear();
|
||||
#if CC_USE_GEOMETRY_RENDERER
|
||||
CC_SAFE_DESTROY_NULL(_geometryRenderer);
|
||||
#endif
|
||||
CC_SAFE_RELEASE_NULL(_frustum);
|
||||
}
|
||||
|
||||
void Camera::attachToScene(RenderScene *scene) {
|
||||
_enabled = true;
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
void Camera::detachFromScene() {
|
||||
_enabled = false;
|
||||
_scene = nullptr;
|
||||
}
|
||||
|
||||
void Camera::resize(uint32_t width, uint32_t height) {
|
||||
if (!_window) {
|
||||
return;
|
||||
}
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
updateAspect();
|
||||
}
|
||||
|
||||
void Camera::setFixedSize(uint32_t width, uint32_t height) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
updateAspect(false);
|
||||
_isWindowSize = false;
|
||||
}
|
||||
|
||||
// Editor specific gizmo camera logic
|
||||
void Camera::syncCameraEditor(const Camera *camera) {
|
||||
#if CC_EDITOR
|
||||
_position = camera->_position;
|
||||
_forward = camera->_forward;
|
||||
_matView = camera->_matView;
|
||||
_matProj = camera->_matProj;
|
||||
_matProjInv = camera->_matProjInv;
|
||||
_matViewProj = camera->_matViewProj;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Camera::update(bool forceUpdate /*false*/) {
|
||||
if (!_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool viewProjDirty = false;
|
||||
// view matrix
|
||||
if (_node->getChangedFlags() || forceUpdate) {
|
||||
_matView = _node->getWorldMatrix().getInversed();
|
||||
_forward.set(-_matView.m[2], -_matView.m[6], -_matView.m[10]);
|
||||
Mat4 scaleMat{};
|
||||
scaleMat.scale(_node->getWorldScale());
|
||||
// remove scale
|
||||
Mat4::multiply(scaleMat, _matView, &_matView);
|
||||
_position.set(_node->getWorldPosition());
|
||||
viewProjDirty = true;
|
||||
}
|
||||
|
||||
// projection matrix
|
||||
auto *swapchain = _window->getSwapchain();
|
||||
const auto &orientation = swapchain ? swapchain->getSurfaceTransform() : gfx::SurfaceTransform::IDENTITY;
|
||||
if (swapchain) {
|
||||
_systemWindowId = swapchain->getWindowId();
|
||||
}
|
||||
|
||||
if (_isProjDirty || _curTransform != orientation) {
|
||||
_curTransform = orientation;
|
||||
const float projectionSignY = _device->getCapabilities().clipSpaceSignY;
|
||||
// Only for rendertexture processing
|
||||
if (_proj == CameraProjection::PERSPECTIVE) {
|
||||
Mat4::createPerspective(_fov, _aspect, _nearClip, _farClip,
|
||||
_fovAxis == CameraFOVAxis::VERTICAL, _device->getCapabilities().clipSpaceMinZ, projectionSignY, static_cast<int>(orientation), &_matProj);
|
||||
} else {
|
||||
const float x = _orthoHeight * _aspect;
|
||||
const float y = _orthoHeight;
|
||||
Mat4::createOrthographicOffCenter(-x, x, -y, y, _nearClip, _farClip,
|
||||
_device->getCapabilities().clipSpaceMinZ, projectionSignY,
|
||||
static_cast<int>(orientation), &_matProj);
|
||||
}
|
||||
_matProjInv = _matProj.getInversed();
|
||||
viewProjDirty = true;
|
||||
_isProjDirty = false;
|
||||
}
|
||||
|
||||
if (_xr) {
|
||||
xr::XREye wndXREye = _xr->getXREyeByRenderWindow(_window);
|
||||
if (wndXREye != xr::XREye::NONE && _xr->getXRConfig(xr::XRConfigKey::SESSION_RUNNING).getBool()) {
|
||||
// xr flow
|
||||
if (_proj == CameraProjection::PERSPECTIVE) {
|
||||
const auto &projFloat = _xr->getXRViewProjectionData(static_cast<uint32_t>(wndXREye), _nearClip, _farClip);
|
||||
std::memcpy(_matProj.m, projFloat.data(), sizeof(float) * 16);
|
||||
} else {
|
||||
const ccstd::array<float, 4> &preTransform = PRE_TRANSFORMS[static_cast<int>(orientation)];
|
||||
_xr->adaptOrthographicMatrix(this, preTransform, _matProj, _matView);
|
||||
}
|
||||
_matProjInv = _matProj.getInversed();
|
||||
viewProjDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// view-projection
|
||||
if (viewProjDirty) {
|
||||
Mat4::multiply(_matProj, _matView, &_matViewProj);
|
||||
_matViewProjInv = _matViewProj.getInversed();
|
||||
_frustum->update(_matViewProj, _matViewProjInv);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::changeTargetWindow(RenderWindow *window) {
|
||||
if (_window) {
|
||||
_window->detachCamera(this);
|
||||
}
|
||||
RenderWindow *win = window ? window : Root::getInstance()->getMainWindow();
|
||||
if (win) {
|
||||
win->attachCamera(this);
|
||||
_window = win;
|
||||
|
||||
// window size is pre-rotated
|
||||
auto *swapchain = win->getSwapchain();
|
||||
const auto orientation = swapchain ? swapchain->getSurfaceTransform() : gfx::SurfaceTransform::IDENTITY;
|
||||
if (static_cast<int32_t>(orientation) % 2) {
|
||||
resize(win->getHeight(), win->getWidth());
|
||||
} else {
|
||||
resize(win->getWidth(), win->getHeight());
|
||||
}
|
||||
|
||||
if (swapchain) {
|
||||
_systemWindowId = swapchain->getWindowId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::initGeometryRenderer() {
|
||||
#if CC_USE_GEOMETRY_RENDERER
|
||||
if (!_geometryRenderer) {
|
||||
_geometryRenderer = ccnew pipeline::GeometryRenderer();
|
||||
_geometryRenderer->activate(_device);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Camera::detachCamera() {
|
||||
if (_window) {
|
||||
_window->detachCamera(this);
|
||||
}
|
||||
}
|
||||
|
||||
geometry::Ray Camera::screenPointToRay(float x, float y) {
|
||||
CC_ASSERT_NOT_NULL(_node);
|
||||
const float cx = _orientedViewport.x * static_cast<float>(_width);
|
||||
const float cy = _orientedViewport.y * static_cast<float>(_height);
|
||||
const float cw = _orientedViewport.z * static_cast<float>(_width);
|
||||
const float ch = _orientedViewport.w * static_cast<float>(_height);
|
||||
const bool isProj = _proj == CameraProjection::PERSPECTIVE;
|
||||
const float ySign = _device->getCapabilities().clipSpaceSignY;
|
||||
const ccstd::array<float, 4> &preTransform = PRE_TRANSFORMS[static_cast<int>(_curTransform)];
|
||||
|
||||
Vec3 tmpVec3{
|
||||
(x - cx) / cw * 2 - 1.F,
|
||||
(y - cy) / ch * 2 - 1.F,
|
||||
isProj ? 1.F : -1.F};
|
||||
float tmpX = tmpVec3.x;
|
||||
tmpVec3.x = tmpX * preTransform[0] + tmpVec3.y * preTransform[2] * ySign;
|
||||
tmpVec3.y = tmpX * preTransform[1] + tmpVec3.y * preTransform[3] * ySign;
|
||||
|
||||
geometry::Ray out;
|
||||
if (isProj) {
|
||||
tmpVec3.transformMat4(tmpVec3, _matViewProjInv);
|
||||
} else {
|
||||
out.o.transformMat4(tmpVec3, _matViewProjInv);
|
||||
}
|
||||
|
||||
if (isProj) {
|
||||
// camera origin
|
||||
geometry::Ray::fromPoints(&out, _node->getWorldPosition(), tmpVec3);
|
||||
} else {
|
||||
out.d.set(0, 0, -1.F);
|
||||
out.d.transformQuat(_node->getWorldRotation());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec3 Camera::screenToWorld(const Vec3 &screenPos) {
|
||||
const float cx = _orientedViewport.x * static_cast<float>(_width);
|
||||
const float cy = _orientedViewport.y * static_cast<float>(_height);
|
||||
const float cw = _orientedViewport.z * static_cast<float>(_width);
|
||||
const float ch = _orientedViewport.w * static_cast<float>(_height);
|
||||
const float ySign = _device->getCapabilities().clipSpaceSignY;
|
||||
const ccstd::array<float, 4> &preTransform = PRE_TRANSFORMS[static_cast<int>(_curTransform)];
|
||||
Vec3 out;
|
||||
|
||||
if (_proj == CameraProjection::PERSPECTIVE) {
|
||||
// calculate screen pos in far clip plane
|
||||
out.set(
|
||||
(screenPos.x - cx) / cw * 2 - 1,
|
||||
(screenPos.y - cy) / ch * 2 - 1,
|
||||
1.0F);
|
||||
|
||||
// transform to world
|
||||
float tmpX = out.x;
|
||||
out.x = tmpX * preTransform[0] + out.y * preTransform[2] * ySign;
|
||||
out.y = tmpX * preTransform[1] + out.y * preTransform[3] * ySign;
|
||||
out.transformMat4(out, _matViewProjInv);
|
||||
// lerp to depth z
|
||||
Vec3 tmpVec3;
|
||||
if (_node) {
|
||||
tmpVec3.set(_node->getWorldPosition());
|
||||
}
|
||||
|
||||
out = tmpVec3.lerp(out, MathUtil::lerp(_nearClip / _farClip, 1, screenPos.z));
|
||||
} else {
|
||||
out.set(
|
||||
(screenPos.x - cx) / cw * 2 - 1,
|
||||
(screenPos.y - cy) / ch * 2 - 1,
|
||||
screenPos.z * 2 - 1);
|
||||
|
||||
// transform to world
|
||||
float tmpX = out.x;
|
||||
out.x = tmpX * preTransform[0] + out.y * preTransform[2] * ySign;
|
||||
out.y = tmpX * preTransform[1] + out.y * preTransform[3] * ySign;
|
||||
out.transformMat4(out, _matViewProjInv);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Vec3 Camera::worldToScreen(const Vec3 &worldPos) {
|
||||
const float ySign = _device->getCapabilities().clipSpaceSignY;
|
||||
const ccstd::array<float, 4> &preTransform = PRE_TRANSFORMS[static_cast<int>(_curTransform)];
|
||||
Vec3 out;
|
||||
Vec3::transformMat4(worldPos, _matViewProj, &out);
|
||||
|
||||
float tmpX = out.x;
|
||||
out.x = tmpX * preTransform[0] + out.y * preTransform[2] * ySign;
|
||||
out.y = tmpX * preTransform[1] + out.y * preTransform[3] * ySign;
|
||||
|
||||
const float cx = _orientedViewport.x * static_cast<float>(_width);
|
||||
const float cy = _orientedViewport.y * static_cast<float>(_height);
|
||||
const float cw = _orientedViewport.z * static_cast<float>(_width);
|
||||
const float ch = _orientedViewport.w * static_cast<float>(_height);
|
||||
|
||||
out.x = cx + (out.x + 1) * 0.5F * cw;
|
||||
out.y = cy + (out.y + 1) * 0.5F * ch;
|
||||
out.z = out.z * 0.5F + 0.5F;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Mat4 Camera::worldMatrixToScreen(const Mat4 &worldMatrix, uint32_t width, uint32_t height) {
|
||||
Mat4 out;
|
||||
Mat4::multiply(_matViewProj, worldMatrix, &out);
|
||||
Mat4::multiply(correctionMatrices[static_cast<int>(_curTransform)], out, &out);
|
||||
|
||||
const float halfWidth = static_cast<float>(width) / 2;
|
||||
const float halfHeight = static_cast<float>(height) / 2;
|
||||
Mat4 tmpMat4(Mat4::IDENTITY);
|
||||
tmpMat4.translate(halfWidth, halfHeight, 0);
|
||||
tmpMat4.scale(halfWidth, halfHeight, 1);
|
||||
|
||||
out.multiply(tmpMat4);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Calculate and set oblique view frustum projection matrix.
|
||||
* @zh 计算并设置斜视锥体投影矩阵
|
||||
* @param clipPlane clip plane in camera space
|
||||
*/
|
||||
void Camera::calculateObliqueMat(const Vec4 &viewSpacePlane) {
|
||||
float clipSpaceMinZ = _device->getCapabilities().clipSpaceMinZ;
|
||||
Vec4 far{math::sgn(viewSpacePlane.x), math::sgn(viewSpacePlane.y), 1.F, 0.F};
|
||||
|
||||
_matProjInv.transformVector(&far);
|
||||
|
||||
const Vec4 m4 = {_matProj.m[3], _matProj.m[7], clipSpaceMinZ, _matProj.m[15]};
|
||||
const float scale = 2.F / Vec4::dot(viewSpacePlane, far);
|
||||
const Vec4 newViewSpaceNearPlane = viewSpacePlane * scale;
|
||||
|
||||
const Vec4 m3 = newViewSpaceNearPlane - m4;
|
||||
|
||||
_matProj.m[2] = m3.x;
|
||||
_matProj.m[6] = m3.y;
|
||||
_matProj.m[10] = m3.z;
|
||||
_matProj.m[14] = m3.w;
|
||||
}
|
||||
|
||||
float Camera::getClipSpaceMinz() const {
|
||||
return _device->getCapabilities().clipSpaceMinZ;
|
||||
}
|
||||
|
||||
void Camera::setNode(Node *val) { _node = val; }
|
||||
|
||||
void Camera::setExposure(float ev100) {
|
||||
_exposure = 0.833333F / std::pow(2.0F, ev100);
|
||||
}
|
||||
|
||||
void Camera::updateExposure() {
|
||||
const float ev100 = std::log2((_apertureValue * _apertureValue) / _shutterValue * 100.F / _isoValue);
|
||||
setExposure(ev100);
|
||||
}
|
||||
|
||||
void Camera::updateAspect(bool oriented) {
|
||||
_aspect = (static_cast<float>(getWindow()->getWidth()) * _viewport.z) / (static_cast<float>(getWindow()->getHeight()) * _viewport.w);
|
||||
// window size/viewport is pre-rotated, but aspect should be oriented to acquire the correct projection
|
||||
if (oriented) {
|
||||
auto *swapchain = getWindow()->getSwapchain();
|
||||
const auto orientation = swapchain ? swapchain->getSurfaceTransform() : gfx::SurfaceTransform::IDENTITY;
|
||||
if (static_cast<int32_t>(orientation) % 2) _aspect = 1 / _aspect;
|
||||
}
|
||||
_isProjDirty = true;
|
||||
}
|
||||
|
||||
void Camera::setViewport(const Rect &val) {
|
||||
debug::warnID(8302);
|
||||
setViewportInOrientedSpace(val);
|
||||
}
|
||||
|
||||
void Camera::setViewportInOrientedSpace(const Rect &val) {
|
||||
const auto x = val.x;
|
||||
const auto width = val.width;
|
||||
const auto height = val.height;
|
||||
|
||||
const auto y = _device->getCapabilities().screenSpaceSignY < 0 ? 1.F - val.y - height : val.y;
|
||||
|
||||
auto *swapchain = getWindow()->getSwapchain();
|
||||
const auto orientation = swapchain ? swapchain->getSurfaceTransform() : gfx::SurfaceTransform::IDENTITY;
|
||||
switch (orientation) {
|
||||
case gfx::SurfaceTransform::ROTATE_90:
|
||||
_viewport.x = 1 - y - height;
|
||||
_viewport.y = x;
|
||||
_viewport.z = height;
|
||||
_viewport.w = width;
|
||||
break;
|
||||
case gfx::SurfaceTransform::ROTATE_180:
|
||||
_viewport.x = 1 - x - width;
|
||||
_viewport.y = 1 - y - height;
|
||||
_viewport.z = width;
|
||||
_viewport.w = height;
|
||||
break;
|
||||
case gfx::SurfaceTransform::ROTATE_270:
|
||||
_viewport.x = y;
|
||||
_viewport.y = 1 - x - width;
|
||||
_viewport.z = height;
|
||||
_viewport.w = width;
|
||||
break;
|
||||
case gfx::SurfaceTransform::IDENTITY:
|
||||
_viewport.x = x;
|
||||
_viewport.y = y;
|
||||
_viewport.z = width;
|
||||
_viewport.w = height;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_orientedViewport.x = x;
|
||||
_orientedViewport.y = y;
|
||||
_orientedViewport.z = width;
|
||||
_orientedViewport.w = height;
|
||||
|
||||
resize(_width, _height);
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
442
cocos/scene/Camera.h
Normal file
442
cocos/scene/Camera.h
Normal file
@@ -0,0 +1,442 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "base/Macros.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/optional.h"
|
||||
#include "cocos/math/Geometry.h"
|
||||
#include "cocos/math/Utils.h"
|
||||
#include "core/geometry/Frustum.h"
|
||||
#include "core/geometry/Ray.h"
|
||||
#include "math/Mat4.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "math/Vec4.h"
|
||||
#include "platform/interfaces/modules/IXRInterface.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
|
||||
namespace cc {
|
||||
class IXRInterface;
|
||||
class Node;
|
||||
|
||||
namespace pipeline {
|
||||
class GeometryRenderer;
|
||||
}
|
||||
|
||||
namespace scene {
|
||||
|
||||
// As RenderScene includes Camera.h, so use forward declaration here.
|
||||
class RenderScene;
|
||||
// As RenderWindow includes Camera.h, so use forward declaration here.
|
||||
class RenderWindow;
|
||||
|
||||
enum class CameraProjection {
|
||||
ORTHO,
|
||||
PERSPECTIVE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
enum class CameraFOVAxis {
|
||||
VERTICAL,
|
||||
HORIZONTAL,
|
||||
};
|
||||
|
||||
enum class CameraAperture {
|
||||
F1_8,
|
||||
F2_0,
|
||||
F2_2,
|
||||
F2_5,
|
||||
F2_8,
|
||||
F3_2,
|
||||
F3_5,
|
||||
F4_0,
|
||||
F4_5,
|
||||
F5_0,
|
||||
F5_6,
|
||||
F6_3,
|
||||
F7_1,
|
||||
F8_0,
|
||||
F9_0,
|
||||
F10_0,
|
||||
F11_0,
|
||||
F13_0,
|
||||
F14_0,
|
||||
F16_0,
|
||||
F18_0,
|
||||
F20_0,
|
||||
F22_0,
|
||||
};
|
||||
|
||||
enum class CameraISO {
|
||||
ISO100,
|
||||
ISO200,
|
||||
ISO400,
|
||||
ISO800,
|
||||
};
|
||||
|
||||
enum class CameraShutter {
|
||||
D1,
|
||||
D2,
|
||||
D4,
|
||||
D8,
|
||||
D15,
|
||||
D30,
|
||||
D60,
|
||||
D125,
|
||||
D250,
|
||||
D500,
|
||||
D1000,
|
||||
D2000,
|
||||
D4000,
|
||||
};
|
||||
|
||||
enum class CameraType {
|
||||
DEFAULT = -1,
|
||||
LEFT_EYE = 0,
|
||||
RIGHT_EYE = 1,
|
||||
MAIN = 2,
|
||||
};
|
||||
|
||||
enum class TrackingType {
|
||||
NO_TRACKING = 0,
|
||||
POSITION_AND_ROTATION = 1,
|
||||
POSITION = 2,
|
||||
ROTATION = 3,
|
||||
};
|
||||
|
||||
enum class CameraUsage {
|
||||
EDITOR,
|
||||
GAME_VIEW,
|
||||
SCENE_VIEW,
|
||||
PREVIEW,
|
||||
GAME = 100,
|
||||
};
|
||||
|
||||
struct ICameraInfo {
|
||||
ccstd::string name;
|
||||
Node *node{nullptr};
|
||||
CameraProjection projection;
|
||||
ccstd::optional<uint32_t> targetDisplay;
|
||||
RenderWindow *window{nullptr};
|
||||
uint32_t priority{0};
|
||||
ccstd::optional<ccstd::string> pipeline;
|
||||
CameraType cameraType{CameraType::DEFAULT};
|
||||
TrackingType trackingType{TrackingType::NO_TRACKING};
|
||||
CameraUsage usage{CameraUsage::GAME};
|
||||
};
|
||||
|
||||
class Camera : public RefCounted {
|
||||
public:
|
||||
static constexpr int32_t SKYBOX_FLAG{static_cast<int32_t>(gfx::ClearFlagBit::STENCIL) << 1};
|
||||
|
||||
explicit Camera(gfx::Device *device);
|
||||
~Camera() override;
|
||||
|
||||
/**
|
||||
* this exposure value corresponding to default standard camera exposure parameters
|
||||
*/
|
||||
static constexpr float getStandardExposureValue() {
|
||||
return 1.F / 38400.F;
|
||||
}
|
||||
|
||||
/**
|
||||
* luminance unit scale used by area lights
|
||||
*/
|
||||
static constexpr float getStandardLightMeterScale() {
|
||||
return 10000.F;
|
||||
}
|
||||
|
||||
bool initialize(const ICameraInfo &info);
|
||||
void destroy();
|
||||
void attachToScene(RenderScene *scene);
|
||||
void detachFromScene();
|
||||
void resize(uint32_t width, uint32_t height);
|
||||
void setFixedSize(uint32_t width, uint32_t height);
|
||||
void syncCameraEditor(const Camera *camera);
|
||||
void update(bool forceUpdate = false); // for lazy eval situations like the in-editor preview
|
||||
void changeTargetWindow(RenderWindow *window);
|
||||
|
||||
/**
|
||||
* transform a screen position (in oriented space) to a world space ray
|
||||
*/
|
||||
geometry::Ray screenPointToRay(float x, float y);
|
||||
|
||||
/**
|
||||
* transform a screen position (in oriented space) to world space
|
||||
*/
|
||||
Vec3 screenToWorld(const Vec3 &screenPos);
|
||||
|
||||
/**
|
||||
* transform a world space position to screen space
|
||||
*/
|
||||
Vec3 worldToScreen(const Vec3 &worldPos);
|
||||
|
||||
/**
|
||||
* transform a world space matrix to screen space
|
||||
* @param {Mat4} out the resulting vector
|
||||
* @param {Mat4} worldMatrix the world space matrix to be transformed
|
||||
* @param {number} width framebuffer width
|
||||
* @param {number} height framebuffer height
|
||||
* @returns {Mat4} the resulting vector
|
||||
*/
|
||||
Mat4 worldMatrixToScreen(const Mat4 &worldMatrix, uint32_t width, uint32_t height);
|
||||
|
||||
void setNode(Node *val);
|
||||
inline Node *getNode() const { return _node.get(); }
|
||||
|
||||
inline void setEnabled(bool val) { _enabled = val; }
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
|
||||
inline void setOrthoHeight(float val) {
|
||||
_orthoHeight = val;
|
||||
_isProjDirty = true;
|
||||
}
|
||||
inline float getOrthoHeight() const { return _orthoHeight; }
|
||||
|
||||
inline void setProjectionType(CameraProjection val) {
|
||||
_proj = val;
|
||||
_isProjDirty = true;
|
||||
}
|
||||
inline CameraProjection getProjectionType() const { return _proj; }
|
||||
|
||||
inline void setFovAxis(CameraFOVAxis axis) {
|
||||
_fovAxis = axis;
|
||||
_isProjDirty = true;
|
||||
}
|
||||
inline CameraFOVAxis getFovAxis() const { return _fovAxis; }
|
||||
|
||||
inline void setFov(float fov) {
|
||||
_fov = fov;
|
||||
_isProjDirty = true;
|
||||
}
|
||||
inline float getFov() const { return _fov; }
|
||||
|
||||
inline void setNearClip(float nearClip) {
|
||||
_nearClip = nearClip;
|
||||
_isProjDirty = true;
|
||||
}
|
||||
inline float getNearClip() const { return _nearClip; }
|
||||
|
||||
inline void setFarClip(float farClip) {
|
||||
_farClip = farClip;
|
||||
_isProjDirty = true;
|
||||
}
|
||||
inline float getFarClip() const { return _farClip; }
|
||||
|
||||
inline void setClearColor(const gfx::Color &val) { _clearColor = val; }
|
||||
inline const gfx::Color &getClearColor() const { return _clearColor; }
|
||||
|
||||
/**
|
||||
* Pre-rotated (i.e. always in identity/portrait mode) if possible.
|
||||
*/
|
||||
inline const Vec4 &getViewport() const { return _viewport; }
|
||||
void setViewport(const Rect &val);
|
||||
void setViewportInOrientedSpace(const Rect &val);
|
||||
|
||||
inline RenderScene *getScene() const { return _scene; }
|
||||
inline const ccstd::string &getName() const { return _name; }
|
||||
inline uint32_t getWidth() const { return _width; }
|
||||
inline uint32_t getHeight() const { return _height; }
|
||||
inline float getAspect() const { return _aspect; }
|
||||
inline const Mat4 &getMatView() const { return _matView; }
|
||||
inline const Mat4 &getMatProj() const { return _matProj; }
|
||||
inline const Mat4 &getMatProjInv() const { return _matProjInv; }
|
||||
inline const Mat4 &getMatViewProj() const { return _matViewProj; }
|
||||
inline const Mat4 &getMatViewProjInv() const { return _matViewProjInv; }
|
||||
|
||||
inline void setFrustum(const geometry::Frustum &val) {
|
||||
*_frustum = val;
|
||||
}
|
||||
inline const geometry::Frustum &getFrustum() const { return *_frustum; }
|
||||
|
||||
inline void setWindow(RenderWindow *val) { _window = val; }
|
||||
inline RenderWindow *getWindow() const { return _window; }
|
||||
|
||||
inline void setForward(const Vec3 &val) { _forward = val; }
|
||||
inline const Vec3 &getForward() const { return _forward; }
|
||||
|
||||
inline void setPosition(const Vec3 &val) { _position = val; }
|
||||
inline const Vec3 &getPosition() const { return _position; }
|
||||
|
||||
inline void setVisibility(uint32_t vis) { _visibility = vis; }
|
||||
inline uint32_t getVisibility() const { return _visibility; }
|
||||
|
||||
inline uint32_t getPriority() const { return _priority; }
|
||||
inline void setPriority(uint32_t val) { _priority = val; }
|
||||
|
||||
inline void setAperture(CameraAperture val) {
|
||||
_aperture = val;
|
||||
_apertureValue = Camera::FSTOPS[static_cast<int>(_aperture)];
|
||||
updateExposure();
|
||||
}
|
||||
inline CameraAperture getAperture() const { return _aperture; }
|
||||
|
||||
inline float getApertureValue() const { return _apertureValue; }
|
||||
|
||||
inline void setShutter(CameraShutter val) {
|
||||
_shutter = val;
|
||||
_shutterValue = Camera::SHUTTERS[static_cast<int>(_shutter)];
|
||||
updateExposure();
|
||||
}
|
||||
inline CameraShutter getShutter() const { return _shutter; }
|
||||
|
||||
inline float getShutterValue() const { return _shutterValue; }
|
||||
|
||||
inline void setIso(CameraISO val) {
|
||||
_iso = val;
|
||||
_isoValue = Camera::ISOS[static_cast<int>(_iso)];
|
||||
updateExposure();
|
||||
}
|
||||
inline CameraISO getIso() const { return _iso; }
|
||||
|
||||
inline float getIsoValue() const { return _isoValue; }
|
||||
|
||||
inline void setEc(float val) { _ec = val; }
|
||||
inline float getEc() const { return _ec; }
|
||||
|
||||
inline float getExposure() const { return _exposure; }
|
||||
|
||||
inline gfx::ClearFlagBit getClearFlag() const { return _clearFlag; }
|
||||
inline void setClearFlag(gfx::ClearFlagBit flag) { _clearFlag = flag; }
|
||||
|
||||
inline float getClearDepth() const { return _clearDepth; }
|
||||
inline void setClearDepth(float depth) { _clearDepth = depth; }
|
||||
|
||||
inline uint32_t getClearStencil() const { return _clearStencil; }
|
||||
inline void setClearStencil(uint32_t stencil) { _clearStencil = stencil; }
|
||||
|
||||
inline bool isWindowSize() const { return _isWindowSize; }
|
||||
inline void setWindowSize(bool val) { _isWindowSize = val; }
|
||||
|
||||
inline float getScreenScale() const { return _screenScale; }
|
||||
inline void setScreenScale(float val) { _screenScale = val; }
|
||||
|
||||
inline gfx::SurfaceTransform getSurfaceTransform() const { return _curTransform; }
|
||||
|
||||
void initGeometryRenderer();
|
||||
inline pipeline::GeometryRenderer *getGeometryRenderer() const {
|
||||
#if CC_USE_GEOMETRY_RENDERER
|
||||
return _geometryRenderer.get();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void detachCamera();
|
||||
|
||||
uint32_t getSystemWindowId() const { return _systemWindowId; }
|
||||
|
||||
inline CameraType getCameraType() const { return _cameraType; }
|
||||
inline void setCameraType(CameraType type) { _cameraType = type; }
|
||||
|
||||
inline TrackingType getTrackingType() const { return _trackingType; }
|
||||
inline void setTrackingType(TrackingType type) { _trackingType = type; }
|
||||
|
||||
inline CameraUsage getCameraUsage() const { return _usage; }
|
||||
inline void setCameraUsage(CameraUsage usage) { _usage = usage; }
|
||||
|
||||
inline bool isCullingEnabled() const { return _isCullingEnabled; }
|
||||
inline void setCullingEnable(bool val) { _isCullingEnabled = val; }
|
||||
|
||||
void calculateObliqueMat(const Vec4 &viewSpacePlane);
|
||||
|
||||
float getClipSpaceMinz() const;
|
||||
|
||||
protected:
|
||||
void setExposure(float ev100);
|
||||
|
||||
private:
|
||||
void updateExposure();
|
||||
void updateAspect(bool oriented = true);
|
||||
|
||||
bool _isWindowSize{true};
|
||||
float _screenScale{0.F};
|
||||
gfx::Device *_device{nullptr};
|
||||
RenderScene *_scene{nullptr};
|
||||
IntrusivePtr<Node> _node;
|
||||
ccstd::string _name;
|
||||
bool _enabled{false};
|
||||
bool _isCullingEnabled{true};
|
||||
CameraProjection _proj{CameraProjection::UNKNOWN};
|
||||
float _aspect{0.F};
|
||||
float _orthoHeight{10.0F};
|
||||
CameraFOVAxis _fovAxis{CameraFOVAxis::VERTICAL};
|
||||
float _fov{static_cast<float>(mathutils::toRadian(45.F))};
|
||||
float _nearClip{1.0F};
|
||||
float _farClip{1000.0F};
|
||||
gfx::Color _clearColor{0.2, 0.2, 0.2, 1};
|
||||
Vec4 _viewport{0, 0, 1, 1};
|
||||
Vec4 _orientedViewport{0, 0, 1, 1};
|
||||
gfx::SurfaceTransform _curTransform{gfx::SurfaceTransform::IDENTITY};
|
||||
bool _isProjDirty{true};
|
||||
Mat4 _matView;
|
||||
Mat4 _matProj;
|
||||
Mat4 _matProjInv;
|
||||
Mat4 _matViewProj;
|
||||
Mat4 _matViewProjInv;
|
||||
geometry::Frustum *_frustum{nullptr};
|
||||
Vec3 _forward;
|
||||
Vec3 _position;
|
||||
uint32_t _priority{0};
|
||||
CameraAperture _aperture{CameraAperture::F16_0};
|
||||
float _apertureValue{0.F};
|
||||
CameraShutter _shutter{CameraShutter::D125};
|
||||
float _shutterValue{0.F};
|
||||
CameraISO _iso{CameraISO::ISO100};
|
||||
float _isoValue{0.F};
|
||||
float _ec = {0.F};
|
||||
RenderWindow *_window{nullptr};
|
||||
uint32_t _width{0};
|
||||
uint32_t _height{0};
|
||||
gfx::ClearFlagBit _clearFlag{gfx::ClearFlagBit::NONE};
|
||||
float _clearDepth{1.0F};
|
||||
CameraType _cameraType{CameraType::DEFAULT};
|
||||
TrackingType _trackingType{TrackingType::NO_TRACKING};
|
||||
CameraUsage _usage{CameraUsage::GAME};
|
||||
|
||||
#if CC_USE_GEOMETRY_RENDERER
|
||||
IntrusivePtr<pipeline::GeometryRenderer> _geometryRenderer;
|
||||
#endif
|
||||
|
||||
static const ccstd::vector<float> FSTOPS;
|
||||
static const ccstd::vector<float> SHUTTERS;
|
||||
static const ccstd::vector<float> ISOS;
|
||||
|
||||
uint32_t _visibility = pipeline::CAMERA_DEFAULT_MASK;
|
||||
float _exposure{0.F};
|
||||
uint32_t _clearStencil{0};
|
||||
IXRInterface *_xr{nullptr};
|
||||
|
||||
uint32_t _systemWindowId{0};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Camera);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
60
cocos/scene/Define.h
Normal file
60
cocos/scene/Define.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/std/container/string.h"
|
||||
#include "renderer/core/PassUtils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
struct IMacroPatch {
|
||||
ccstd::string name;
|
||||
MacroValue value;
|
||||
|
||||
IMacroPatch() = default;
|
||||
IMacroPatch(const ccstd::string& n, const MacroValue& v) {
|
||||
name = n;
|
||||
value = v;
|
||||
}
|
||||
|
||||
IMacroPatch(const std::pair<const std::string, cc::MacroValue>& pair) {
|
||||
name = pair.first;
|
||||
value = pair.second;
|
||||
}
|
||||
|
||||
bool operator==(const IMacroPatch& rhs) const {
|
||||
return rhs.name == name && rhs.value == value;
|
||||
}
|
||||
|
||||
static bool compare(const IMacroPatch& lhs, const IMacroPatch& rhs) {
|
||||
return lhs.name < rhs.name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
91
cocos/scene/DirectionalLight.cpp
Normal file
91
cocos/scene/DirectionalLight.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/DirectionalLight.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/RenderPipeline.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
DirectionalLight::DirectionalLight() { _type = LightType::DIRECTIONAL; }
|
||||
|
||||
DirectionalLight::~DirectionalLight() = default;
|
||||
|
||||
void DirectionalLight::initialize() {
|
||||
Light::initialize();
|
||||
|
||||
setIlluminance(Ambient::SUN_ILLUM);
|
||||
_dir.set(1.0F, -1.0F, -1.0F);
|
||||
}
|
||||
|
||||
void DirectionalLight::update() {
|
||||
if (_node && _node->getChangedFlags()) {
|
||||
_dir = _forward;
|
||||
_node->updateWorldTransform();
|
||||
_dir.transformQuat(_node->getWorldRotation());
|
||||
}
|
||||
}
|
||||
|
||||
float DirectionalLight::getIlluminance() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
return _illuminanceHDR;
|
||||
}
|
||||
return _illuminanceLDR;
|
||||
}
|
||||
|
||||
void DirectionalLight::setIlluminance(float value) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_illuminanceHDR = value;
|
||||
} else {
|
||||
_illuminanceLDR = value;
|
||||
}
|
||||
}
|
||||
|
||||
void DirectionalLight::activate() const {
|
||||
auto *pipeline = Root::getInstance()->getPipeline();
|
||||
if (pipeline) {
|
||||
if (_shadowEnabled) {
|
||||
if (_shadowFixedArea || !pipeline->getPipelineSceneData()->getCSMSupported()) {
|
||||
pipeline->setValue("CC_DIR_LIGHT_SHADOW_TYPE", 1);
|
||||
} else if (_csmLevel > CSMLevel::LEVEL_1 && pipeline->getPipelineSceneData()->getCSMSupported()) {
|
||||
pipeline->setValue("CC_DIR_LIGHT_SHADOW_TYPE", 2);
|
||||
pipeline->setValue("CC_CASCADED_LAYERS_TRANSITION", _csmLayersTransition);
|
||||
} else {
|
||||
pipeline->setValue("CC_DIR_LIGHT_SHADOW_TYPE", 1);
|
||||
}
|
||||
pipeline->setValue("CC_DIR_SHADOW_PCF_TYPE", static_cast<int32_t>(_shadowPcf));
|
||||
} else {
|
||||
pipeline->setValue("CC_DIR_LIGHT_SHADOW_TYPE", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
134
cocos/scene/DirectionalLight.h
Normal file
134
cocos/scene/DirectionalLight.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "math/Vec3.h"
|
||||
#include "scene/Ambient.h"
|
||||
#include "scene/Light.h"
|
||||
#include "scene/Shadow.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class DirectionalLight final : public Light {
|
||||
public:
|
||||
DirectionalLight();
|
||||
~DirectionalLight() override;
|
||||
|
||||
void initialize() override;
|
||||
void update() override;
|
||||
|
||||
inline void setShadowEnabled(bool enabled) {
|
||||
_shadowEnabled = enabled;
|
||||
activate();
|
||||
}
|
||||
inline void setShadowPcf(PCFType pcf) {
|
||||
_shadowPcf = pcf;
|
||||
activate();
|
||||
}
|
||||
inline void setShadowBias(float bias) { _shadowBias = bias; }
|
||||
inline void setShadowNormalBias(float normalBias) { _shadowNormalBias = normalBias; }
|
||||
inline void setShadowSaturation(float saturation) { _shadowSaturation = saturation; }
|
||||
inline void setShadowDistance(float distance) { _shadowDistance = distance; }
|
||||
inline void setShadowInvisibleOcclusionRange(float invisibleOcclusionRange) { _shadowInvisibleOcclusionRange = invisibleOcclusionRange; }
|
||||
inline void setCSMLevel(CSMLevel csmLevel) {
|
||||
_csmLevel = csmLevel;
|
||||
activate();
|
||||
}
|
||||
inline void setCSMLayerLambda(float lambda) { _csmLayerLambda = lambda; }
|
||||
inline void setCSMNeedUpdate(bool isCSMNeedUpdate) { _isCSMNeedUpdate = isCSMNeedUpdate; }
|
||||
inline void setCSMOptimizationMode(CSMOptimizationMode csmOptimizationMode) { _csmOptimizationMode = csmOptimizationMode; }
|
||||
inline void setShadowFixedArea(bool fixedArea) {
|
||||
_shadowFixedArea = fixedArea;
|
||||
activate();
|
||||
}
|
||||
inline void setShadowNear(float nearValue) { _shadowNear = nearValue; }
|
||||
inline void setShadowFar(float farValue) { _shadowFar = farValue; }
|
||||
inline void setShadowOrthoSize(float orthoSize) { _shadowOrthoSize = orthoSize; }
|
||||
inline void setCSMLayersTransition(bool csmLayersTransition) {
|
||||
_csmLayersTransition = csmLayersTransition;
|
||||
activate();
|
||||
}
|
||||
inline void setCSMTransitionRange(bool csmTransitionRange) { _csmTransitionRange = csmTransitionRange; }
|
||||
|
||||
inline bool isShadowEnabled() const { return _shadowEnabled; }
|
||||
inline PCFType getShadowPcf() const { return _shadowPcf; }
|
||||
inline float getShadowBias() const { return _shadowBias; }
|
||||
inline float getShadowNormalBias() const { return _shadowNormalBias; }
|
||||
inline float getShadowSaturation() const { return _shadowSaturation; }
|
||||
inline float getShadowDistance() const { return _shadowDistance; }
|
||||
inline float getShadowInvisibleOcclusionRange() const { return _shadowInvisibleOcclusionRange; }
|
||||
inline CSMLevel getCSMLevel() const { return _csmLevel; }
|
||||
inline float getCSMLayerLambda() const { return _csmLayerLambda; }
|
||||
inline bool isCSMNeedUpdate() const { return _isCSMNeedUpdate; }
|
||||
inline CSMOptimizationMode getCSMOptimizationMode() const { return _csmOptimizationMode; }
|
||||
inline bool isShadowFixedArea() const { return _shadowFixedArea; }
|
||||
inline float getShadowNear() const { return _shadowNear; }
|
||||
inline float getShadowFar() const { return _shadowFar; }
|
||||
inline float getShadowOrthoSize() const { return _shadowOrthoSize; }
|
||||
|
||||
inline const Vec3 &getDirection() const { return _dir; }
|
||||
inline void setDirection(const Vec3 &dir) { _dir = dir; }
|
||||
inline void setIlluminanceHDR(float value) { _illuminanceHDR = value; }
|
||||
inline void setIlluminanceLDR(float value) { _illuminanceLDR = value; }
|
||||
inline float getIlluminanceHDR() const { return _illuminanceHDR; }
|
||||
inline float getIlluminanceLDR() const { return _illuminanceLDR; }
|
||||
inline float getCSMLayersTransition() const { return _csmLayersTransition; }
|
||||
inline float getCSMTransitionRange() const { return _csmTransitionRange; }
|
||||
float getIlluminance() const;
|
||||
void setIlluminance(float value);
|
||||
void activate() const;
|
||||
|
||||
private:
|
||||
// shadow info
|
||||
bool _shadowEnabled{false};
|
||||
bool _isCSMNeedUpdate{false};
|
||||
bool _shadowFixedArea{false};
|
||||
bool _csmLayersTransition{false};
|
||||
|
||||
PCFType _shadowPcf{PCFType::HARD};
|
||||
CSMLevel _csmLevel{CSMLevel::LEVEL_3};
|
||||
CSMOptimizationMode _csmOptimizationMode{CSMOptimizationMode::REMOVE_DUPLICATES};
|
||||
|
||||
float _illuminanceHDR{Ambient::SUN_ILLUM};
|
||||
float _illuminanceLDR{1.F};
|
||||
float _shadowBias{0.0F};
|
||||
float _shadowNormalBias{0.0F};
|
||||
float _shadowSaturation{0.75F};
|
||||
float _shadowDistance{50.0F};
|
||||
float _shadowInvisibleOcclusionRange{200.0F};
|
||||
float _csmLayerLambda{0.75F};
|
||||
float _shadowNear{0.1F};
|
||||
float _shadowFar{10.0F};
|
||||
float _shadowOrthoSize{1.0F};
|
||||
float _csmTransitionRange{0.05F};
|
||||
|
||||
Vec3 _dir{1.0F, -1.0F, -1.0F};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(DirectionalLight);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
67
cocos/scene/DrawBatch2D.cpp
Normal file
67
cocos/scene/DrawBatch2D.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "DrawBatch2D.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/assets/Material.h"
|
||||
#include "scene/Pass.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
void DrawBatch2D::clear() {
|
||||
_inputAssembler = nullptr;
|
||||
_descriptorSet = nullptr;
|
||||
_model = nullptr;
|
||||
_visFlags = 1 << 23;
|
||||
}
|
||||
|
||||
void DrawBatch2D::fillPass(Material *mat, const gfx::DepthStencilState *depthStencilState, ccstd::hash_t dsHash, const ccstd::vector<IMacroPatch> *patches) {
|
||||
const auto &passes = mat->getPasses();
|
||||
if (passes->empty()) return;
|
||||
_shaders.clear();
|
||||
if (_passes.size() < passes->size()) {
|
||||
auto num = static_cast<uint32_t>(passes->size() - _passes.size());
|
||||
for (uint32_t i = 0; i < num; ++i) {
|
||||
_passes.emplace_back(ccnew scene::Pass(Root::getInstance()));
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < passes->size(); ++i) {
|
||||
auto &pass = passes->at(i);
|
||||
auto &passInUse = _passes[i];
|
||||
pass->update();
|
||||
if (!depthStencilState) depthStencilState = pass->getDepthStencilState();
|
||||
passInUse->initPassFromTarget(pass, *depthStencilState, dsHash);
|
||||
_shaders.push_back(patches ? passInUse->getShaderVariant(*patches) : passInUse->getShaderVariant());
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBatch2D::setInputAssembler(gfx::InputAssembler *ia) {
|
||||
_inputAssembler = ia;
|
||||
_drawInfo = _inputAssembler->getDrawInfo();
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
80
cocos/scene/DrawBatch2D.h
Normal file
80
cocos/scene/DrawBatch2D.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/RefCounted.h"
|
||||
//#include "core/scene-graph/Layers.h"
|
||||
#include "base/Macros.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "scene/Define.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Material;
|
||||
|
||||
namespace scene {
|
||||
|
||||
class Pass;
|
||||
class Model;
|
||||
|
||||
class DrawBatch2D final : public RefCounted {
|
||||
public:
|
||||
DrawBatch2D() = default;
|
||||
~DrawBatch2D() override = default;
|
||||
|
||||
void clear();
|
||||
void fillPass(Material *mat, const gfx::DepthStencilState *depthStencilState, ccstd::hash_t dsHash, const ccstd::vector<IMacroPatch> *patches = nullptr);
|
||||
void setInputAssembler(gfx::InputAssembler *ia);
|
||||
inline void setFirstIndex(uint32_t index) { _drawInfo.firstIndex = index; }
|
||||
inline void setIndexCount(uint32_t count) { _drawInfo.indexCount = count; }
|
||||
|
||||
inline void setDescriptorSet(gfx::DescriptorSet *descriptorSet) { _descriptorSet = descriptorSet; }
|
||||
inline void setVisFlags(uint32_t flags) { _visFlags = flags; }
|
||||
inline void setModel(Model *model) { _model = model; }
|
||||
|
||||
inline const gfx::DrawInfo &getDrawInfo() const { return _drawInfo; }
|
||||
inline gfx::InputAssembler *getInputAssembler() const { return _inputAssembler; }
|
||||
inline gfx::DescriptorSet *getDescriptorSet() const { return _descriptorSet; }
|
||||
inline uint32_t getVisFlags() const { return _visFlags; }
|
||||
inline const ccstd::vector<gfx::Shader *> &getShaders() const { return _shaders; }
|
||||
inline const ccstd::vector<IntrusivePtr<Pass>> &getPasses() const { return _passes; }
|
||||
inline Model *getModel() const { return _model; }
|
||||
|
||||
protected:
|
||||
gfx::InputAssembler *_inputAssembler{nullptr}; // IntrusivePtr ?
|
||||
gfx::DescriptorSet *_descriptorSet{nullptr};
|
||||
uint32_t _visFlags{0};
|
||||
ccstd::vector<IntrusivePtr<scene::Pass>> _passes;
|
||||
ccstd::vector<gfx::Shader *> _shaders;
|
||||
|
||||
Model *_model{nullptr};
|
||||
gfx::DrawInfo _drawInfo;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(DrawBatch2D);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
152
cocos/scene/Fog.cpp
Normal file
152
cocos/scene/Fog.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Fog.h"
|
||||
#include "core/Root.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
#include "renderer/pipeline/helper/Utils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
void FogInfo::setEnabled(bool val) const {
|
||||
if (_isEnabled == val) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_resource != nullptr) {
|
||||
_resource->setEnabled(val);
|
||||
if (val) {
|
||||
_resource->setType(_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogColor(const Color &val) {
|
||||
_fogColor.set(val);
|
||||
if (_resource != nullptr) {
|
||||
_resource->setFogColor(_fogColor);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setType(FogType val) {
|
||||
_type = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setType(_type);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogDensity(float val) {
|
||||
_fogDensity = val;
|
||||
if (_resource) {
|
||||
_resource->setFogDensity(_fogDensity);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogStart(float val) {
|
||||
_fogStart = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setFogStart(_fogStart);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogEnd(float val) {
|
||||
_fogEnd = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setFogEnd(_fogEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogAtten(float val) {
|
||||
_fogAtten = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setFogAtten(_fogAtten);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogTop(float val) {
|
||||
_fogTop = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setFogTop(_fogTop);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::setFogRange(float val) {
|
||||
_fogRange = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setFogRange(_fogRange);
|
||||
}
|
||||
}
|
||||
|
||||
void FogInfo::activate(Fog *resource) {
|
||||
_resource = resource;
|
||||
_resource->initialize(*this);
|
||||
_resource->activate();
|
||||
}
|
||||
|
||||
//
|
||||
void Fog::initialize(const FogInfo &fogInfo) {
|
||||
_activated = false;
|
||||
setFogColor(fogInfo.getFogColor());
|
||||
_enabled = fogInfo.isEnabled();
|
||||
_accurate = fogInfo.isAccurate();
|
||||
_type = _enabled ? fogInfo.getType() : FogType::NONE;
|
||||
_fogDensity = fogInfo.getFogDensity();
|
||||
_fogStart = fogInfo.getFogStart();
|
||||
_fogEnd = fogInfo.getFogEnd();
|
||||
_fogAtten = fogInfo.getFogAtten();
|
||||
_fogTop = fogInfo.getFogTop();
|
||||
_fogRange = fogInfo.getFogRange();
|
||||
}
|
||||
|
||||
void Fog::updatePipeline() {
|
||||
auto *root = Root::getInstance();
|
||||
const FogType value = _enabled ? _type : FogType::NONE;
|
||||
const int32_t accurateValue = isAccurate() ? 1 : 0;
|
||||
auto *pipeline = root->getPipeline();
|
||||
auto iterMacroFog = pipeline->getMacros().find("CC_USE_FOG");
|
||||
auto iterMacroAccurateFog = pipeline->getMacros().find("CC_USE_ACCURATE_FOG");
|
||||
if (iterMacroFog != pipeline->getMacros().end() && iterMacroAccurateFog != pipeline->getMacros().end()) {
|
||||
const MacroValue ¯oFog = iterMacroFog->second;
|
||||
const MacroValue ¯oAccurateFog = iterMacroAccurateFog->second;
|
||||
const int32_t *macroFogPtr = ccstd::get_if<int32_t>(¯oFog);
|
||||
const int32_t *macroAccurateFogPtr = ccstd::get_if<int32_t>(¯oAccurateFog);
|
||||
if (macroFogPtr != nullptr && *macroFogPtr == static_cast<int32_t>(value) && macroAccurateFogPtr != nullptr && *macroAccurateFogPtr == accurateValue) return;
|
||||
}
|
||||
|
||||
pipeline->setValue("CC_USE_FOG", static_cast<int32_t>(value));
|
||||
pipeline->setValue("CC_USE_ACCURATE_FOG", accurateValue);
|
||||
if (_activated) {
|
||||
root->onGlobalPipelineStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Fog::setFogColor(const Color &val) {
|
||||
_fogColor.set(val);
|
||||
Vec4 v4(static_cast<float>(val.r) / 255.F, static_cast<float>(val.g) / 255.F, static_cast<float>(val.b) / 255.F, static_cast<float>(val.a) / 255.F);
|
||||
pipeline::srgbToLinear(&_colorArray, v4);
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
354
cocos/scene/Fog.h
Normal file
354
cocos/scene/Fog.h
Normal file
@@ -0,0 +1,354 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/array.h"
|
||||
#include "math/Color.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
enum class FogType {
|
||||
/**
|
||||
* @zh
|
||||
* 线性雾。
|
||||
* @en
|
||||
* Linear fog
|
||||
* @readonly
|
||||
*/
|
||||
LINEAR = 0,
|
||||
/**
|
||||
* @zh
|
||||
* 指数雾。
|
||||
* @en
|
||||
* Exponential fog
|
||||
* @readonly
|
||||
*/
|
||||
EXP = 1,
|
||||
/**
|
||||
* @zh
|
||||
* 指数平方雾。
|
||||
* @en
|
||||
* Exponential square fog
|
||||
* @readonly
|
||||
*/
|
||||
EXP_SQUARED = 2,
|
||||
/**
|
||||
* @zh
|
||||
* 层叠雾。
|
||||
* @en
|
||||
* Layered fog
|
||||
* @readonly
|
||||
*/
|
||||
LAYERED = 3,
|
||||
NONE = 4
|
||||
};
|
||||
|
||||
class FogInfo;
|
||||
|
||||
class Fog final {
|
||||
public:
|
||||
Fog() = default;
|
||||
~Fog() = default;
|
||||
|
||||
void initialize(const FogInfo &fogInfo);
|
||||
|
||||
inline void activate() {
|
||||
updatePipeline();
|
||||
_activated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 是否启用全局雾效
|
||||
* @en Enable global fog
|
||||
*/
|
||||
inline void setEnabled(bool val) {
|
||||
_enabled = val;
|
||||
if (!val) {
|
||||
_type = FogType::NONE;
|
||||
updatePipeline();
|
||||
} else {
|
||||
activate();
|
||||
}
|
||||
}
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
|
||||
/**
|
||||
* @zh 是否启用精确雾效(像素雾)计算
|
||||
* @en Enable accurate fog (pixel fog)
|
||||
*/
|
||||
inline void setAccurate(bool val) {
|
||||
_accurate = val;
|
||||
updatePipeline();
|
||||
}
|
||||
inline bool isAccurate() const { return _accurate; }
|
||||
|
||||
/**
|
||||
* @zh 全局雾颜色
|
||||
* @en Global fog color
|
||||
*/
|
||||
void setFogColor(const Color &val);
|
||||
inline const Color &getFogColor() const { return _fogColor; }
|
||||
|
||||
/**
|
||||
* @zh 当前雾化类型。
|
||||
* @en The current global fog type.
|
||||
* @returns {FogType}
|
||||
* Returns the current global fog type
|
||||
* - -1:Disable global Fog
|
||||
* - 0:Linear fog
|
||||
* - 1:Exponential fog
|
||||
* - 2:Exponential square fog
|
||||
* - 3:Layered fog
|
||||
*/
|
||||
inline FogType getType() const { return _type; }
|
||||
inline void setType(FogType val) {
|
||||
_type = _enabled ? val : FogType::NONE;
|
||||
if (_enabled) {
|
||||
updatePipeline();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 全局雾浓度
|
||||
* @en Global fog density
|
||||
*/
|
||||
inline float getFogDensity() const { return _fogDensity; }
|
||||
inline void setFogDensity(float val) { _fogDensity = val; }
|
||||
|
||||
/**
|
||||
* @zh 雾效起始位置,只适用于线性雾
|
||||
* @en Global fog start position, only for linear fog
|
||||
*/
|
||||
inline float getFogStart() const { return _fogStart; }
|
||||
inline void setFogStart(float val) { _fogStart = val; }
|
||||
|
||||
/**
|
||||
* @zh 雾效结束位置,只适用于线性雾
|
||||
* @en Global fog end position, only for linear fog
|
||||
*/
|
||||
float getFogEnd() const { return _fogEnd; }
|
||||
void setFogEnd(float val) { _fogEnd = val; }
|
||||
|
||||
/**
|
||||
* @zh 雾效衰减
|
||||
* @en Global fog attenuation
|
||||
*/
|
||||
inline float getFogAtten() const { return _fogAtten; }
|
||||
inline void setFogAtten(float val) { _fogAtten = val; }
|
||||
|
||||
/**
|
||||
* @zh 雾效顶部范围,只适用于层级雾
|
||||
* @en Global fog top range, only for layered fog
|
||||
*/
|
||||
inline float getFogTop() const { return _fogTop; }
|
||||
|
||||
inline void setFogTop(float val) { _fogTop = val; }
|
||||
|
||||
/**
|
||||
* @zh 雾效范围,只适用于层级雾
|
||||
* @en Global fog range, only for layered fog
|
||||
*/
|
||||
inline float getFogRange() const { return _fogRange; }
|
||||
inline void setFogRange(float val) { _fogRange = val; }
|
||||
|
||||
const Vec4 &getColorArray() const { return _colorArray; }
|
||||
|
||||
private:
|
||||
void updatePipeline();
|
||||
|
||||
Color _fogColor{200, 200, 200, 255};
|
||||
Vec4 _colorArray{0.2F, 0.2F, 0.2F, 1.0F};
|
||||
bool _enabled{false};
|
||||
bool _accurate{false};
|
||||
FogType _type{FogType::LINEAR};
|
||||
float _fogDensity{0.3F};
|
||||
float _fogStart{0.5F};
|
||||
float _fogEnd{300.F};
|
||||
float _fogAtten{5.F};
|
||||
float _fogTop{1.5F};
|
||||
float _fogRange{1.2F};
|
||||
bool _activated{false};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Fog);
|
||||
};
|
||||
|
||||
class FogInfo : public RefCounted {
|
||||
public:
|
||||
FogInfo() = default;
|
||||
~FogInfo() override = default;
|
||||
/**
|
||||
* @zh 是否启用全局雾效
|
||||
* @en Enable global fog
|
||||
*/
|
||||
void setEnabled(bool val) const;
|
||||
inline bool isEnabled() const { return _isEnabled; }
|
||||
|
||||
/**
|
||||
* @zh 是否启用精确雾效(像素雾)计算
|
||||
* @en Enable accurate fog (pixel fog)
|
||||
*/
|
||||
// @editable
|
||||
// @tooltip('i18n:fog.accurate')
|
||||
inline void setAccurate(bool val) {
|
||||
if (_accurate == val) return;
|
||||
_accurate = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setAccurate(val);
|
||||
if (val) {
|
||||
_resource->setType(_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline bool isAccurate() const { return _accurate; }
|
||||
|
||||
/**
|
||||
* @zh 全局雾颜色
|
||||
* @en Global fog color
|
||||
*/
|
||||
// @editable
|
||||
// @tooltip('i18n:fog.fogColor')
|
||||
void setFogColor(const Color &val);
|
||||
inline const Color &getFogColor() const { return _fogColor; }
|
||||
|
||||
/**
|
||||
* @zh 全局雾类型
|
||||
* @en Global fog type
|
||||
*/
|
||||
// @editable
|
||||
// @type(FogType)
|
||||
// @tooltip('i18n:fog.type')
|
||||
void setType(FogType val);
|
||||
inline FogType getType() const { return _type; }
|
||||
|
||||
/**
|
||||
* @zh 全局雾浓度
|
||||
* @en Global fog density
|
||||
*/
|
||||
// @visible(function (this: FogInfo) {
|
||||
// return this._type !== FogType.LAYERED && this._type !== FogType.LINEAR;
|
||||
// })
|
||||
// @type(CCFloat)
|
||||
// @range([0, 1])
|
||||
// @rangeStep(0.01)
|
||||
// @slide
|
||||
// @displayOrder(3)
|
||||
// @tooltip('i18n:fog.fogDensity')
|
||||
void setFogDensity(float val);
|
||||
inline float getFogDensity() const { return _fogDensity; }
|
||||
|
||||
// /**
|
||||
// * @zh 雾效起始位置
|
||||
// * @en Global fog start position
|
||||
// */
|
||||
// @visible(function (this: FogInfo) { return this._type !== FogType.LAYERED; })
|
||||
// @type(CCFloat)
|
||||
// @rangeStep(0.01)
|
||||
// @displayOrder(4)
|
||||
// @tooltip('i18n:fog.fogStart')
|
||||
void setFogStart(float val);
|
||||
inline float getFogStart() const { return _fogStart; }
|
||||
|
||||
// /**
|
||||
// * @zh 雾效结束位置,只适用于线性雾
|
||||
// * @en Global fog end position, only for linear fog
|
||||
// */
|
||||
// @visible(function (this: FogInfo) { return this._type === FogType.LINEAR; })
|
||||
// @type(CCFloat)
|
||||
// @rangeStep(0.01)
|
||||
// @displayOrder(5)
|
||||
// @tooltip('i18n:fog.fogEnd')
|
||||
void setFogEnd(float val);
|
||||
inline float getFogEnd() const { return _fogEnd; }
|
||||
|
||||
/**
|
||||
* @zh 雾效衰减
|
||||
* @en Global fog attenuation
|
||||
*/
|
||||
// @visible(function (this: FogInfo) { return this._type !== FogType.LINEAR; })
|
||||
// @type(CCFloat)
|
||||
// @rangeMin(0.01)
|
||||
// @rangeStep(0.01)
|
||||
// @displayOrder(6)
|
||||
// @tooltip('i18n:fog.fogAtten')
|
||||
void setFogAtten(float val);
|
||||
inline float getFogAtten() const { return _fogAtten; }
|
||||
|
||||
/**
|
||||
* @zh 雾效顶部范围,只适用于层级雾
|
||||
* @en Global fog top range, only for layered fog
|
||||
*/
|
||||
// @visible(function (this: FogInfo) { return this._type === FogType.LAYERED; })
|
||||
// @type(CCFloat)
|
||||
// @rangeStep(0.01)
|
||||
// @displayOrder(7)
|
||||
// @tooltip('i18n:fog.fogTop')
|
||||
void setFogTop(float val);
|
||||
inline float getFogTop() const { return _fogTop; }
|
||||
|
||||
/**
|
||||
* @zh 雾效范围,只适用于层级雾
|
||||
* @en Global fog range, only for layered fog
|
||||
*/
|
||||
// @visible(function (this: FogInfo) { return this._type === FogType.LAYERED; })
|
||||
// @type(CCFloat)
|
||||
// @rangeStep(0.01)
|
||||
// @displayOrder(8)
|
||||
// @tooltip('i18n:fog.fogRange')
|
||||
void setFogRange(float val);
|
||||
inline float getFogRange() const { return _fogRange; }
|
||||
|
||||
void activate(Fog *resource);
|
||||
|
||||
//cjh JSB need to bind the property, so need to make it public
|
||||
//private:
|
||||
// @serializable
|
||||
FogType _type{FogType::LINEAR};
|
||||
// @serializable
|
||||
Color _fogColor{200, 200, 200, 255};
|
||||
// @serializable
|
||||
bool _isEnabled{false};
|
||||
// @serializable
|
||||
float _fogDensity{0.3F};
|
||||
// @serializable
|
||||
float _fogStart{0.5F};
|
||||
// @serializable
|
||||
float _fogEnd{300.F};
|
||||
// @serializable
|
||||
float _fogAtten{5.F};
|
||||
// @serializable
|
||||
float _fogTop{1.5F};
|
||||
// @serializable
|
||||
float _fogRange{1.2F};
|
||||
// @serializable
|
||||
bool _accurate{false};
|
||||
// weak reference
|
||||
Fog *_resource{nullptr};
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
129
cocos/scene/LODGroup.cpp
Normal file
129
cocos/scene/LODGroup.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/LODGroup.h"
|
||||
#include <cmath>
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "scene/Camera.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
void LODData::eraseModel(Model *model) {
|
||||
auto iter = std::find(_vecModels.begin(), _vecModels.end(), model);
|
||||
if (iter != _vecModels.end()) {
|
||||
_vecModels.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
LODGroup::LODGroup() = default;
|
||||
|
||||
LODGroup::~LODGroup() = default;
|
||||
|
||||
int8_t LODGroup::getVisibleLODLevel(const Camera *camera) const {
|
||||
float screenUsagePercentage = getScreenUsagePercentage(camera);
|
||||
|
||||
int8_t lodIndex = -1;
|
||||
for (auto i = 0; i < _vecLODData.size(); ++i) {
|
||||
const auto &lod = _vecLODData[i];
|
||||
if (screenUsagePercentage >= lod->getScreenUsagePercentage()) {
|
||||
lodIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lodIndex;
|
||||
}
|
||||
|
||||
float LODGroup::getScreenUsagePercentage(const Camera *camera) const {
|
||||
if (!_node.get()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto distance = 0;
|
||||
if (camera->getProjectionType() == CameraProjection::PERSPECTIVE) {
|
||||
Vec3 tmp{_localBoundaryCenter};
|
||||
tmp.transformMat4(_node->getWorldMatrix());
|
||||
tmp.subtract(camera->getNode()->getWorldPosition());
|
||||
distance = tmp.length();
|
||||
}
|
||||
|
||||
return distanceToScreenUsagePercentage(camera, distance, getWorldSpaceSize());
|
||||
}
|
||||
|
||||
float LODGroup::distanceToScreenUsagePercentage(const Camera *camera, float distance, float size) {
|
||||
if (camera->getProjectionType() == CameraProjection::PERSPECTIVE) {
|
||||
return static_cast<float>((size * fabs(camera->getMatProj().m[5])) / (distance * 2.0)); // note: matProj.m11 is 1 / tan(fov / 2.0)
|
||||
}
|
||||
return static_cast<float>(size * fabs(camera->getMatProj().m[5]) * 0.5);
|
||||
}
|
||||
|
||||
float LODGroup::getWorldSpaceSize() const {
|
||||
auto scale = _node->getScale();
|
||||
auto maxScale = fmaxf(fabs(scale.x), fabs(scale.y));
|
||||
maxScale = fmaxf(maxScale, fabs(scale.z));
|
||||
return maxScale * _objectSize;
|
||||
}
|
||||
|
||||
void LODGroup::lockLODLevels(ccstd::vector<int> &levels) {
|
||||
if (levels.size() != _vecLockedLevels.size()) {
|
||||
_isLockLevelChanged = true;
|
||||
} else {
|
||||
auto size = levels.size();
|
||||
for (int index = 0; index < size; index++) {
|
||||
if (levels[index] != _vecLockedLevels[index]) {
|
||||
_isLockLevelChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_vecLockedLevels.clear();
|
||||
_vecLockedLevels.insert(_vecLockedLevels.begin(), levels.begin(), levels.end());
|
||||
}
|
||||
|
||||
void LODGroup::insertLOD(uint8_t index, LODData *data) {
|
||||
if (index >= _vecLODData.size()) {
|
||||
_vecLODData.emplace_back(data);
|
||||
} else {
|
||||
_vecLODData.insert(_vecLODData.begin() + index, data);
|
||||
}
|
||||
}
|
||||
|
||||
void LODGroup::updateLOD(uint8_t index, LODData *data) {
|
||||
if (index >= _vecLODData.size()) {
|
||||
CC_LOG_WARNING("LODGroup updateLOD error, index out of range.");
|
||||
return;
|
||||
}
|
||||
_vecLODData[index] = data;
|
||||
}
|
||||
|
||||
void LODGroup::eraseLOD(uint8_t index) {
|
||||
if (index >= _vecLODData.size()) {
|
||||
CC_LOG_WARNING("LODGroup eraseLOD error, index out of range.");
|
||||
return;
|
||||
}
|
||||
_vecLODData.erase(_vecLODData.begin() + index);
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
114
cocos/scene/LODGroup.h
Normal file
114
cocos/scene/LODGroup.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Model.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/TypeDef.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "math/Vec3.h"
|
||||
|
||||
namespace cc {
|
||||
class Node;
|
||||
|
||||
namespace scene {
|
||||
|
||||
class RenderScene;
|
||||
class Camera;
|
||||
class Model;
|
||||
|
||||
class LODData final : public RefCounted {
|
||||
public:
|
||||
inline float getScreenUsagePercentage() const { return _screenUsagePercentage; }
|
||||
inline void setScreenUsagePercentage(float val) { _screenUsagePercentage = val; }
|
||||
|
||||
inline const ccstd::vector<IntrusivePtr<Model>> &getModels() const { return _vecModels; }
|
||||
|
||||
inline void addModel(Model *model) { _vecModels.emplace_back(model); }
|
||||
inline void clearModels() { _vecModels.clear(); }
|
||||
void eraseModel(Model *model);
|
||||
|
||||
private:
|
||||
float _screenUsagePercentage{1.F};
|
||||
ccstd::vector<IntrusivePtr<Model>> _vecModels;
|
||||
};
|
||||
|
||||
class LODGroup final : public RefCounted {
|
||||
public:
|
||||
LODGroup();
|
||||
~LODGroup() override;
|
||||
|
||||
inline void attachToScene(RenderScene *scene) { _scene = scene; }
|
||||
inline void detachFromScene() { _scene = nullptr; }
|
||||
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
inline void setEnabled(bool val) { _enabled = val; }
|
||||
|
||||
inline float getObjectSize() const { return _objectSize; }
|
||||
inline void setObjectSize(float val) { _objectSize = val; }
|
||||
|
||||
inline Node *getNode() const { return _node.get(); }
|
||||
void setNode(Node *node) { _node = node; }
|
||||
|
||||
inline RenderScene *getScene() const { return _scene; }
|
||||
|
||||
inline const Vec3 &getLocalBoundaryCenter() const { return _localBoundaryCenter; }
|
||||
inline void setLocalBoundaryCenter(const Vec3 &value) { _localBoundaryCenter = value; }
|
||||
|
||||
inline const ccstd::vector<IntrusivePtr<LODData>> &getLodDataArray() const { return _vecLODData; }
|
||||
|
||||
int8_t getVisibleLODLevel(const Camera *camera) const;
|
||||
|
||||
inline const ccstd::vector<uint8_t> &getLockedLODLevels() const { return _vecLockedLevels; }
|
||||
void lockLODLevels(ccstd::vector<int> &levels);
|
||||
inline bool isLockLevelChanged() const { return _isLockLevelChanged; }
|
||||
inline void resetLockChangeFlag() { _isLockLevelChanged = false; }
|
||||
|
||||
inline uint8_t getLodCount() const { return _vecLODData.size(); }
|
||||
inline void clearLODs() { _vecLODData.clear(); }
|
||||
void insertLOD(uint8_t index, LODData *data);
|
||||
void updateLOD(uint8_t index, LODData *data);
|
||||
void eraseLOD(uint8_t index);
|
||||
|
||||
private:
|
||||
float getScreenUsagePercentage(const Camera *camera) const;
|
||||
static float distanceToScreenUsagePercentage(const Camera *camera, float distance, float size);
|
||||
float getWorldSpaceSize() const;
|
||||
|
||||
ccstd::vector<IntrusivePtr<LODData>> _vecLODData;
|
||||
ccstd::vector<uint8_t> _vecLockedLevels;
|
||||
IntrusivePtr<Node> _node;
|
||||
RenderScene *_scene{nullptr};
|
||||
Vec3 _localBoundaryCenter;
|
||||
float _objectSize{1.F};
|
||||
bool _enabled{true};
|
||||
bool _isLockLevelChanged{false};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(LODGroup);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
76
cocos/scene/Light.cpp
Normal file
76
cocos/scene/Light.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Light.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "math/Math.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
Light::Light() = default;
|
||||
|
||||
Light::~Light() = default;
|
||||
|
||||
void Light::destroy() {
|
||||
_name.clear();
|
||||
_node = nullptr;
|
||||
}
|
||||
|
||||
void Light::setNode(Node *node) { _node = node; }
|
||||
|
||||
float Light::nt2lm(float size) {
|
||||
return 4 * math::PI * math::PI * size * size;
|
||||
}
|
||||
|
||||
Vec3 Light::colorTemperatureToRGB(float kelvin) {
|
||||
if (kelvin < 1000.0) {
|
||||
kelvin = 1000.0;
|
||||
} else if (kelvin > 15000.0) {
|
||||
kelvin = 15000.0;
|
||||
}
|
||||
|
||||
// Approximate Planckian locus in CIE 1960 UCS
|
||||
const float kSqr = kelvin * kelvin;
|
||||
const float u = (0.860117757 + 1.54118254e-4 * kelvin + 1.28641212e-7 * kSqr) / (1.0 + 8.42420235e-4 * kelvin + 7.08145163e-7 * kSqr);
|
||||
const float v = (0.317398726 + 4.22806245e-5 * kelvin + 4.20481691e-8 * kSqr) / (1.0 - 2.89741816e-5 * kelvin + 1.61456053e-7 * kSqr);
|
||||
|
||||
const float d = (2.0 * u - 8.0 * v + 4.0);
|
||||
const float x = (3.0 * u) / d;
|
||||
const float y = (2.0 * v) / d;
|
||||
const float z = (1.0 - x) - y;
|
||||
|
||||
const float X = (1.0 / y) * x;
|
||||
const float Z = (1.0 / y) * z;
|
||||
|
||||
// XYZ to RGB with BT.709 primaries
|
||||
Vec3 colorWithTemperature;
|
||||
colorWithTemperature.x = 3.2404542 * X + -1.5371385 + -0.4985314 * Z;
|
||||
colorWithTemperature.y = -0.9692660 * X + 1.8760108 + 0.0415560 * Z;
|
||||
colorWithTemperature.z = 0.0556434 * X + -0.2040259 + 1.0572252 * Z;
|
||||
return colorWithTemperature;
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
124
cocos/scene/Light.h
Normal file
124
cocos/scene/Light.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "pipeline/Define.h"
|
||||
|
||||
namespace cc {
|
||||
class Node;
|
||||
namespace scene {
|
||||
|
||||
class RenderScene;
|
||||
|
||||
enum class LightType {
|
||||
DIRECTIONAL,
|
||||
SPHERE,
|
||||
SPOT,
|
||||
POINT,
|
||||
RANGED_DIRECTIONAL,
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
class Light : public RefCounted {
|
||||
public:
|
||||
Light();
|
||||
~Light() override;
|
||||
|
||||
inline void attachToScene(RenderScene *scene) { _scene = scene; }
|
||||
inline void detachFromScene() { _scene = nullptr; }
|
||||
|
||||
void destroy();
|
||||
|
||||
virtual void initialize() {
|
||||
_color = Vec3(1, 1, 1);
|
||||
_colorTemp = 6550.F;
|
||||
}
|
||||
|
||||
virtual void update(){};
|
||||
|
||||
inline bool isBaked() const { return _baked; }
|
||||
inline void setBaked(bool val) { _baked = val; }
|
||||
|
||||
inline const Vec3 &getColor() const { return _color; }
|
||||
inline void setColor(const Vec3 &color) { _color = color; }
|
||||
|
||||
inline bool isUseColorTemperature() const { return _useColorTemperature; }
|
||||
inline void setUseColorTemperature(bool value) { _useColorTemperature = value; }
|
||||
|
||||
inline float getColorTemperature() const { return _colorTemp; }
|
||||
inline void setColorTemperature(float val) {
|
||||
_colorTemp = val;
|
||||
setColorTemperatureRGB(colorTemperatureToRGB(val));
|
||||
}
|
||||
|
||||
inline uint32_t getVisibility() const { return _visibility; }
|
||||
inline void setVisibility(uint32_t visibility) { _visibility = visibility; }
|
||||
|
||||
inline Node *getNode() const { return _node.get(); }
|
||||
void setNode(Node *node);
|
||||
|
||||
inline LightType getType() const { return _type; }
|
||||
inline void setType(LightType type) { _type = type; }
|
||||
|
||||
inline const ccstd::string &getName() const { return _name; }
|
||||
inline void setName(const ccstd::string &name) { _name = name; }
|
||||
|
||||
inline RenderScene *getScene() const { return _scene; }
|
||||
|
||||
inline const Vec3 &getColorTemperatureRGB() const { return _colorTemperatureRGB; }
|
||||
inline void setColorTemperatureRGB(const Vec3 &value) { _colorTemperatureRGB = value; }
|
||||
|
||||
static float nt2lm(float size);
|
||||
static Vec3 colorTemperatureToRGB(float kelvin);
|
||||
|
||||
protected:
|
||||
bool _useColorTemperature{false};
|
||||
bool _baked{false};
|
||||
|
||||
LightType _type{LightType::UNKNOWN};
|
||||
|
||||
uint32_t _visibility = pipeline::CAMERA_DEFAULT_MASK;
|
||||
|
||||
IntrusivePtr<Node> _node;
|
||||
RenderScene *_scene{nullptr};
|
||||
|
||||
float _colorTemp{6550.F};
|
||||
|
||||
Vec3 _color{1, 1, 1};
|
||||
Vec3 _colorTemperatureRGB;
|
||||
Vec3 _forward{0, 0, -1};
|
||||
|
||||
ccstd::string _name;
|
||||
|
||||
private:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Light);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
724
cocos/scene/Model.cpp
Normal file
724
cocos/scene/Model.cpp
Normal file
@@ -0,0 +1,724 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#include "base/std/container/array.h"
|
||||
|
||||
// #include "core/Director.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/TypedArray.h"
|
||||
#include "core/assets/Material.h"
|
||||
#include "core/scene-graph/Scene.h"
|
||||
#include "core/scene-graph/SceneGlobals.h"
|
||||
#include "gfx-base/GFXTexture.h"
|
||||
#include "gi/light-probe/LightProbe.h"
|
||||
#include "gi/light-probe/SH.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
#include "renderer/pipeline/InstancedBuffer.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
#include "scene/Model.h"
|
||||
#include "scene/Pass.h"
|
||||
#include "scene/ReflectionProbe.h"
|
||||
#include "scene/ReflectionProbeManager.h"
|
||||
#include "scene/RenderScene.h"
|
||||
#include "scene/SubModel.h"
|
||||
|
||||
namespace {
|
||||
const cc::gfx::SamplerInfo LIGHTMAP_SAMPLER_HASH{
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Filter::NONE,
|
||||
cc::gfx::Address::CLAMP,
|
||||
cc::gfx::Address::CLAMP,
|
||||
cc::gfx::Address::CLAMP,
|
||||
};
|
||||
|
||||
const cc::gfx::SamplerInfo LIGHTMAP_SAMPLER_WITH_MIP_HASH{
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Address::CLAMP,
|
||||
cc::gfx::Address::CLAMP,
|
||||
cc::gfx::Address::CLAMP,
|
||||
};
|
||||
|
||||
const ccstd::vector<cc::scene::IMacroPatch> SHADOW_MAP_PATCHES{{"CC_RECEIVE_SHADOW", true}};
|
||||
const ccstd::vector<cc::scene::IMacroPatch> LIGHT_PROBE_PATCHES{{"CC_USE_LIGHT_PROBE", true}};
|
||||
const ccstd::string CC_USE_REFLECTION_PROBE = "CC_USE_REFLECTION_PROBE";
|
||||
const ccstd::string CC_DISABLE_DIRECTIONAL_LIGHT = "CC_DISABLE_DIRECTIONAL_LIGHT";
|
||||
const ccstd::vector<cc::scene::IMacroPatch> STATIC_LIGHTMAP_PATHES{{"CC_USE_LIGHTMAP", 1}};
|
||||
const ccstd::vector<cc::scene::IMacroPatch> STATIONARY_LIGHTMAP_PATHES{{"CC_USE_LIGHTMAP", 2}};
|
||||
const ccstd::vector<cc::scene::IMacroPatch> HIGHP_LIGHTMAP_PATHES{{"CC_LIGHT_MAP_VERSION", 2}};
|
||||
} // namespace
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
Model::Model() {
|
||||
_device = Root::getInstance()->getDevice();
|
||||
}
|
||||
|
||||
Model::~Model() = default;
|
||||
|
||||
void Model::initialize() {
|
||||
if (_inited) return;
|
||||
_receiveShadow = true;
|
||||
_castShadow = false;
|
||||
_enabled = true;
|
||||
_visFlags = Layers::Enum::NONE;
|
||||
_inited = true;
|
||||
_bakeToReflectionProbe = true;
|
||||
_reflectionProbeType = scene::UseReflectionProbeType::NONE;
|
||||
}
|
||||
|
||||
void Model::destroy() {
|
||||
for (SubModel *subModel : _subModels) {
|
||||
CC_SAFE_DESTROY(subModel);
|
||||
}
|
||||
_subModels.clear();
|
||||
|
||||
CC_SAFE_DESTROY_NULL(_localBuffer);
|
||||
CC_SAFE_DESTROY_NULL(_localSHBuffer);
|
||||
CC_SAFE_DESTROY_NULL(_worldBoundBuffer);
|
||||
|
||||
_worldBounds = nullptr;
|
||||
_modelBounds = nullptr;
|
||||
_inited = false;
|
||||
_localDataUpdated = true;
|
||||
_transform = nullptr;
|
||||
_node = nullptr;
|
||||
_isDynamicBatching = false;
|
||||
}
|
||||
|
||||
void Model::updateTransform(uint32_t stamp) {
|
||||
CC_PROFILE(ModelUpdateTransform);
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
emit<UpdateTransform>(stamp);
|
||||
_isCalledFromJS = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Node *node = _transform;
|
||||
if (node->getChangedFlags() || node->isTransformDirty()) {
|
||||
node->updateWorldTransform();
|
||||
_localDataUpdated = true;
|
||||
if (_modelBounds != nullptr && _modelBounds->isValid() && _worldBounds != nullptr) {
|
||||
_modelBounds->transform(node->getWorldMatrix(), _worldBounds);
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateWorldBound() {
|
||||
Node *node = _transform;
|
||||
if (node) {
|
||||
node->updateWorldTransform();
|
||||
_localDataUpdated = true;
|
||||
if (_modelBounds != nullptr && _modelBounds->isValid() && _worldBounds != nullptr) {
|
||||
_modelBounds->transform(node->getWorldMatrix(), _worldBounds);
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateWorldBoundsForJSSkinningModel(const Vec3 &min, const Vec3 &max) {
|
||||
Node *node = _transform;
|
||||
if (node) {
|
||||
if (_modelBounds != nullptr && _modelBounds->isValid() && _worldBounds != nullptr) {
|
||||
geometry::AABB::fromPoints(min, max, _modelBounds);
|
||||
_modelBounds->transform(node->getWorldMatrix(), _worldBounds);
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateWorldBoundsForJSBakedSkinningModel(geometry::AABB *aabb) {
|
||||
_worldBounds->center = aabb->center;
|
||||
_worldBounds->halfExtents = aabb->halfExtents;
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
|
||||
void Model::updateUBOs(uint32_t stamp) {
|
||||
CC_PROFILE(ModelUpdateUBOs);
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
emit<UpdateUBO>(stamp);
|
||||
_isCalledFromJS = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (SubModel *subModel : _subModels) {
|
||||
subModel->update();
|
||||
}
|
||||
_updateStamp = stamp;
|
||||
|
||||
updateSHUBOs();
|
||||
|
||||
const auto *pipeline = Root::getInstance()->getPipeline();
|
||||
const auto *shadowInfo = pipeline->getPipelineSceneData()->getShadows();
|
||||
const auto forceUpdateUBO = shadowInfo->isEnabled() && shadowInfo->getType() == ShadowType::PLANAR;
|
||||
|
||||
if (!_localDataUpdated) {
|
||||
return;
|
||||
}
|
||||
_localDataUpdated = false;
|
||||
getTransform()->updateWorldTransform();
|
||||
const auto &worldMatrix = getTransform()->getWorldMatrix();
|
||||
bool hasNonInstancingPass = false;
|
||||
for (const auto &subModel : _subModels) {
|
||||
const auto idx = subModel->getInstancedWorldMatrixIndex();
|
||||
if (idx >= 0) {
|
||||
ccstd::vector<TypedArray> &attrs = subModel->getInstancedAttributeBlock().views;
|
||||
subModel->updateInstancedWorldMatrix(worldMatrix, idx);
|
||||
} else {
|
||||
hasNonInstancingPass = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((hasNonInstancingPass || forceUpdateUBO) && _localBuffer) {
|
||||
Mat4 mat4;
|
||||
Mat4::inverseTranspose(worldMatrix, &mat4);
|
||||
|
||||
_localBuffer->write(worldMatrix, sizeof(float) * pipeline::UBOLocal::MAT_WORLD_OFFSET);
|
||||
_localBuffer->write(mat4, sizeof(float) * pipeline::UBOLocal::MAT_WORLD_IT_OFFSET);
|
||||
_localBuffer->write(_lightmapUVParam, sizeof(float) * pipeline::UBOLocal::LIGHTINGMAP_UVPARAM);
|
||||
_localBuffer->write(_shadowBias, sizeof(float) * (pipeline::UBOLocal::LOCAL_SHADOW_BIAS));
|
||||
|
||||
auto *probe = scene::ReflectionProbeManager::getInstance()->getReflectionProbeById(_reflectionProbeId);
|
||||
auto *blendProbe = scene::ReflectionProbeManager::getInstance()->getReflectionProbeById(_reflectionProbeBlendId);
|
||||
if (probe) {
|
||||
if (probe->getProbeType() == scene::ReflectionProbe::ProbeType::PLANAR) {
|
||||
const Vec4 plane = {probe->getNode()->getUp().x, probe->getNode()->getUp().y, probe->getNode()->getUp().z, 1.F};
|
||||
_localBuffer->write(plane, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_DATA1));
|
||||
const Vec4 depthScale = {1.F, 0.F, 0.F, 1.F};
|
||||
_localBuffer->write(depthScale, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_DATA2));
|
||||
} else {
|
||||
uint16_t mipAndUseRGBE = probe->isRGBE() ? 1000 : 0;
|
||||
const Vec4 pos = {probe->getNode()->getWorldPosition().x, probe->getNode()->getWorldPosition().y, probe->getNode()->getWorldPosition().z, 0.F};
|
||||
_localBuffer->write(pos, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_DATA1));
|
||||
const Vec4 boxSize = {probe->getBoudingSize().x, probe->getBoudingSize().y, probe->getBoudingSize().z, static_cast<float>(probe->getCubeMap() ? probe->getCubeMap()->mipmapLevel() + mipAndUseRGBE : 1 + mipAndUseRGBE)};
|
||||
_localBuffer->write(boxSize, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_DATA2));
|
||||
}
|
||||
if (_reflectionProbeType == scene::UseReflectionProbeType::BLEND_PROBES ||
|
||||
_reflectionProbeType == scene::UseReflectionProbeType::BLEND_PROBES_AND_SKYBOX) {
|
||||
if (blendProbe) {
|
||||
uint16_t mipAndUseRGBE = blendProbe->isRGBE() ? 1000 : 0;
|
||||
const Vec3 worldPos = blendProbe->getNode()->getWorldPosition();
|
||||
Vec3 boudingBox = blendProbe->getBoudingSize();
|
||||
const Vec4 pos = {worldPos.x, worldPos.y, worldPos.z, _reflectionProbeBlendWeight};
|
||||
_localBuffer->write(pos, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_BLEND_DATA1));
|
||||
const Vec4 boxSize = {boudingBox.x, boudingBox.y, boudingBox.z, static_cast<float>(blendProbe->getCubeMap() ? blendProbe->getCubeMap()->mipmapLevel() + mipAndUseRGBE : 1 + mipAndUseRGBE)};
|
||||
_localBuffer->write(boxSize, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_BLEND_DATA2));
|
||||
} else if (_reflectionProbeType == scene::UseReflectionProbeType::BLEND_PROBES_AND_SKYBOX) {
|
||||
// blend with skybox
|
||||
const Vec4 pos = {0.F, 0.F, 0.F, _reflectionProbeBlendWeight};
|
||||
_localBuffer->write(pos, sizeof(float) * (pipeline::UBOLocal::REFLECTION_PROBE_BLEND_DATA1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_localBuffer->update();
|
||||
const bool enableOcclusionQuery = Root::getInstance()->getPipeline()->isOcclusionQueryEnabled();
|
||||
if (enableOcclusionQuery) {
|
||||
updateWorldBoundUBOs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateOctree() {
|
||||
if (_scene && _worldBoundsDirty) {
|
||||
_worldBoundsDirty = false;
|
||||
_scene->updateOctree(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateWorldBoundUBOs() {
|
||||
if (_worldBoundBuffer) {
|
||||
const Vec3 ¢er = _worldBounds ? _worldBounds->getCenter() : Vec3{0.0F, 0.0F, 0.0F};
|
||||
const Vec3 &halfExtents = _worldBounds ? _worldBounds->getHalfExtents() : Vec3{1.0F, 1.0F, 1.0F};
|
||||
const Vec4 worldBoundCenter{center.x, center.y, center.z, 0.0F};
|
||||
const Vec4 worldBoundHalfExtents{halfExtents.x, halfExtents.y, halfExtents.z, 1.0F};
|
||||
_worldBoundBuffer->write(worldBoundCenter, sizeof(float) * pipeline::UBOWorldBound::WORLD_BOUND_CENTER);
|
||||
_worldBoundBuffer->write(worldBoundHalfExtents, sizeof(float) * pipeline::UBOWorldBound::WORLD_BOUND_HALF_EXTENTS);
|
||||
_worldBoundBuffer->update();
|
||||
}
|
||||
}
|
||||
|
||||
void Model::createBoundingShape(const ccstd::optional<Vec3> &minPos, const ccstd::optional<Vec3> &maxPos) {
|
||||
if (!minPos.has_value() || !maxPos.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_modelBounds) {
|
||||
_modelBounds = ccnew geometry::AABB();
|
||||
}
|
||||
geometry::AABB::fromPoints(minPos.value(), maxPos.value(), _modelBounds);
|
||||
|
||||
if (!_worldBounds) {
|
||||
_worldBounds = ccnew geometry::AABB();
|
||||
}
|
||||
geometry::AABB::fromPoints(minPos.value(), maxPos.value(), _worldBounds);
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
|
||||
SubModel *Model::createSubModel() {
|
||||
return ccnew SubModel();
|
||||
}
|
||||
|
||||
void Model::initSubModel(index_t idx, cc::RenderingSubMesh *subMeshData, Material *mat) {
|
||||
initialize();
|
||||
if (idx >= static_cast<index_t>(_subModels.size())) {
|
||||
_subModels.resize(1 + idx, nullptr);
|
||||
}
|
||||
|
||||
if (_subModels[idx] == nullptr) {
|
||||
_subModels[idx] = createSubModel();
|
||||
} else {
|
||||
CC_SAFE_DESTROY(_subModels[idx]);
|
||||
}
|
||||
_subModels[idx]->initialize(subMeshData, mat->getPasses(), getMacroPatches(idx));
|
||||
_subModels[idx]->setOwner(this);
|
||||
updateAttributesAndBinding(idx);
|
||||
}
|
||||
|
||||
void Model::setSubModelMesh(index_t idx, cc::RenderingSubMesh *subMesh) const {
|
||||
if (idx < _subModels.size()) {
|
||||
_subModels[idx]->setSubMesh(subMesh);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::setSubModelMaterial(index_t idx, Material *mat) {
|
||||
if (idx < _subModels.size()) {
|
||||
_subModels[idx]->setPasses(mat->getPasses());
|
||||
updateAttributesAndBinding(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::onGlobalPipelineStateChanged() const {
|
||||
for (SubModel *subModel : _subModels) {
|
||||
subModel->onPipelineStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Model::onMacroPatchesStateChanged() {
|
||||
for (index_t i = 0; i < _subModels.size(); ++i) {
|
||||
_subModels[i]->onMacroPatchesStateChanged(getMacroPatches(i));
|
||||
}
|
||||
}
|
||||
|
||||
void Model::onGeometryChanged() {
|
||||
for (SubModel *subModel : _subModels) {
|
||||
subModel->onGeometryChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Model::initLightingmap(Texture2D *texture, const Vec4 &uvParam) {
|
||||
_lightmap = texture;
|
||||
_lightmapUVParam = uvParam;
|
||||
}
|
||||
|
||||
void Model::updateLightingmap(Texture2D *texture, const Vec4 &uvParam) {
|
||||
_localDataUpdated = true;
|
||||
_lightmap = texture;
|
||||
_lightmapUVParam = uvParam;
|
||||
|
||||
if (texture == nullptr) {
|
||||
texture = BuiltinResMgr::getInstance()->get<Texture2D>(ccstd::string("empty-texture"));
|
||||
}
|
||||
gfx::Texture *gfxTexture = texture->getGFXTexture();
|
||||
if (gfxTexture) {
|
||||
auto *sampler = _device->getSampler(texture->getMipmaps().size() > 1 ? LIGHTMAP_SAMPLER_WITH_MIP_HASH : LIGHTMAP_SAMPLER_HASH);
|
||||
for (SubModel *subModel : _subModels) {
|
||||
gfx::DescriptorSet *descriptorSet = subModel->getDescriptorSet();
|
||||
// // TODO(Yun Hsiao Wu): should manage lightmap macro switches automatically
|
||||
// // USE_LIGHTMAP -> CC_USE_LIGHTMAP
|
||||
descriptorSet->bindTexture(pipeline::LIGHTMAPTEXTURE::BINDING, gfxTexture);
|
||||
descriptorSet->bindSampler(pipeline::LIGHTMAPTEXTURE::BINDING, sampler);
|
||||
descriptorSet->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::isLightProbeAvailable() const {
|
||||
if (!_useLightProbe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto *pipeline = Root::getInstance()->getPipeline();
|
||||
const auto *lightProbes = pipeline->getPipelineSceneData()->getLightProbes();
|
||||
if (!lightProbes || lightProbes->empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_worldBounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Model::updateSHBuffer() {
|
||||
if (_localSHData.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasNonInstancingPass = false;
|
||||
for (const auto &subModel : _subModels) {
|
||||
const auto idx = subModel->getInstancedSHIndex();
|
||||
if (idx >= 0) {
|
||||
subModel->updateInstancedSH(_localSHData, idx);
|
||||
} else {
|
||||
hasNonInstancingPass = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNonInstancingPass && _localSHBuffer) {
|
||||
_localSHBuffer->update(_localSHData.buffer()->getData());
|
||||
}
|
||||
}
|
||||
|
||||
void Model::clearSHUBOs() {
|
||||
if (_localSHData.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < pipeline::UBOSH::COUNT; i++) {
|
||||
_localSHData[i] = 0.0;
|
||||
}
|
||||
|
||||
updateSHBuffer();
|
||||
}
|
||||
|
||||
void Model::updateSHUBOs() {
|
||||
if (!isLightProbeAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto center = _worldBounds->getCenter();
|
||||
#if !CC_EDITOR
|
||||
if (center.approxEquals(_lastWorldBoundCenter, math::EPSILON)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ccstd::vector<Vec3> coefficients;
|
||||
Vec4 weights(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
const auto *pipeline = Root::getInstance()->getPipeline();
|
||||
const auto *lightProbes = pipeline->getPipelineSceneData()->getLightProbes();
|
||||
|
||||
_lastWorldBoundCenter.set(center);
|
||||
_tetrahedronIndex = lightProbes->getData()->getInterpolationWeights(center, _tetrahedronIndex, weights);
|
||||
bool result = lightProbes->getData()->getInterpolationSHCoefficients(_tetrahedronIndex, weights, coefficients);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_localSHData.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gi::SH::reduceRinging(coefficients, lightProbes->getReduceRinging());
|
||||
gi::SH::updateUBOData(_localSHData, pipeline::UBOSH::SH_LINEAR_CONST_R_OFFSET, coefficients);
|
||||
updateSHBuffer();
|
||||
}
|
||||
|
||||
ccstd::vector<IMacroPatch> Model::getMacroPatches(index_t subModelIndex) {
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
ccstd::vector<IMacroPatch> macroPatches;
|
||||
emit<GetMacroPatches>(subModelIndex, ¯oPatches);
|
||||
_isCalledFromJS = false;
|
||||
return macroPatches;
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::vector<IMacroPatch> patches;
|
||||
if (_receiveShadow) {
|
||||
for (const auto &patch : SHADOW_MAP_PATCHES) {
|
||||
patches.push_back(patch);
|
||||
}
|
||||
}
|
||||
|
||||
if (_useLightProbe) {
|
||||
for (const auto &patch : LIGHT_PROBE_PATCHES) {
|
||||
patches.push_back(patch);
|
||||
}
|
||||
}
|
||||
|
||||
patches.push_back({CC_USE_REFLECTION_PROBE, static_cast<int32_t>(_reflectionProbeType)});
|
||||
|
||||
if (_lightmap != nullptr) {
|
||||
bool stationary = false;
|
||||
if (getNode() != nullptr && getNode()->getScene() != nullptr) {
|
||||
stationary = getNode()->getScene()->getSceneGlobals()->getBakedWithStationaryMainLight();
|
||||
}
|
||||
|
||||
if (stationary) {
|
||||
for (const auto &patch : STATIONARY_LIGHTMAP_PATHES) {
|
||||
patches.push_back(patch);
|
||||
}
|
||||
} else {
|
||||
for (const auto &patch : STATIC_LIGHTMAP_PATHES) {
|
||||
patches.push_back(patch);
|
||||
}
|
||||
}
|
||||
|
||||
// use highp lightmap
|
||||
if (getNode() != nullptr && getNode()->getScene() != nullptr) {
|
||||
if (getNode()->getScene()->getSceneGlobals()->getBakedWithHighpLightmap()) {
|
||||
for (const auto &patch : HIGHP_LIGHTMAP_PATHES) {
|
||||
patches.push_back(patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
patches.push_back({CC_DISABLE_DIRECTIONAL_LIGHT, !_receiveDirLight});
|
||||
|
||||
return patches;
|
||||
}
|
||||
|
||||
void Model::updateAttributesAndBinding(index_t subModelIndex) {
|
||||
if (subModelIndex >= _subModels.size()) return;
|
||||
SubModel *subModel = _subModels[subModelIndex];
|
||||
initLocalDescriptors(subModelIndex);
|
||||
updateLocalDescriptors(subModelIndex, subModel->getDescriptorSet());
|
||||
|
||||
initLocalSHDescriptors(subModelIndex);
|
||||
updateLocalSHDescriptors(subModelIndex, subModel->getDescriptorSet());
|
||||
|
||||
initWorldBoundDescriptors(subModelIndex);
|
||||
if (subModel->getWorldBoundDescriptorSet()) {
|
||||
updateWorldBoundDescriptors(subModelIndex, subModel->getWorldBoundDescriptorSet());
|
||||
}
|
||||
|
||||
ccstd::vector<gfx::Attribute> attributes;
|
||||
ccstd::unordered_map<ccstd::string, gfx::Attribute> attributeMap;
|
||||
for (const auto &pass : *(subModel->getPasses())) {
|
||||
gfx::Shader *shader = pass->getShaderVariant(subModel->getPatches());
|
||||
for (const auto &attr : shader->getAttributes()) {
|
||||
if (attributeMap.find(attr.name) == attributeMap.end()) {
|
||||
attributes.push_back(attr);
|
||||
attributeMap.insert({attr.name, attr});
|
||||
}
|
||||
}
|
||||
}
|
||||
updateInstancedAttributes(attributes, subModel);
|
||||
}
|
||||
|
||||
void Model::updateInstancedAttributes(const ccstd::vector<gfx::Attribute> &attributes, SubModel *subModel) {
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
emit<UpdateInstancedAttributes>(attributes, subModel); // FIXME
|
||||
_isCalledFromJS = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
subModel->updateInstancedAttributes(attributes);
|
||||
_localDataUpdated = true;
|
||||
}
|
||||
|
||||
void Model::initLocalDescriptors(index_t /*subModelIndex*/) {
|
||||
if (!_localBuffer) {
|
||||
_localBuffer = _device->createBuffer({gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
pipeline::UBOLocal::SIZE,
|
||||
pipeline::UBOLocal::SIZE,
|
||||
gfx::BufferFlagBit::ENABLE_STAGING_WRITE});
|
||||
}
|
||||
}
|
||||
|
||||
void Model::initLocalSHDescriptors(index_t /*subModelIndex*/) {
|
||||
#if !CC_EDITOR
|
||||
if (!_useLightProbe) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_localSHData.empty()) {
|
||||
_localSHData.reset(pipeline::UBOSH::COUNT);
|
||||
}
|
||||
|
||||
if (!_localSHBuffer) {
|
||||
_localSHBuffer = _device->createBuffer({
|
||||
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
pipeline::UBOSH::SIZE,
|
||||
pipeline::UBOSH::SIZE,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Model::initWorldBoundDescriptors(index_t /*subModelIndex*/) {
|
||||
if (!_worldBoundBuffer) {
|
||||
_worldBoundBuffer = _device->createBuffer({gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
pipeline::UBOWorldBound::SIZE,
|
||||
pipeline::UBOWorldBound::SIZE,
|
||||
gfx::BufferFlagBit::ENABLE_STAGING_WRITE});
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateLocalDescriptors(index_t subModelIndex, gfx::DescriptorSet *descriptorSet) {
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
emit<UpdateLocalDescriptors>(subModelIndex, descriptorSet);
|
||||
_isCalledFromJS = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_localBuffer) {
|
||||
descriptorSet->bindBuffer(pipeline::UBOLocal::BINDING, _localBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateLocalSHDescriptors(index_t subModelIndex, gfx::DescriptorSet *descriptorSet) {
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
emit<UpdateLocalSHDescriptor>(subModelIndex, descriptorSet);
|
||||
_isCalledFromJS = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_localSHBuffer) {
|
||||
descriptorSet->bindBuffer(pipeline::UBOSH::BINDING, _localSHBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateWorldBoundDescriptors(index_t subModelIndex, gfx::DescriptorSet *descriptorSet) {
|
||||
if (isModelImplementedInJS()) {
|
||||
if (!_isCalledFromJS) {
|
||||
emit<UpdateWorldBound>(subModelIndex, descriptorSet);
|
||||
_isCalledFromJS = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_worldBoundBuffer) {
|
||||
descriptorSet->bindBuffer(pipeline::UBOLocal::BINDING, _worldBoundBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateLocalShadowBias() {
|
||||
_localDataUpdated = true;
|
||||
}
|
||||
|
||||
void Model::updateReflectionProbeCubemap(TextureCube *texture) {
|
||||
_localDataUpdated = true;
|
||||
if (texture == nullptr) {
|
||||
texture = BuiltinResMgr::getInstance()->get<TextureCube>(ccstd::string("default-cube-texture"));
|
||||
}
|
||||
gfx::Texture *gfxTexture = texture->getGFXTexture();
|
||||
if (gfxTexture) {
|
||||
auto *sampler = _device->getSampler(texture->getSamplerInfo());
|
||||
for (SubModel *subModel : _subModels) {
|
||||
gfx::DescriptorSet *descriptorSet = subModel->getDescriptorSet();
|
||||
descriptorSet->bindTexture(pipeline::REFLECTIONPROBECUBEMAP::BINDING, gfxTexture);
|
||||
descriptorSet->bindSampler(pipeline::REFLECTIONPROBECUBEMAP::BINDING, sampler);
|
||||
descriptorSet->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
void Model::updateReflectionProbePlanarMap(gfx::Texture *texture) {
|
||||
_localDataUpdated = true;
|
||||
|
||||
gfx::Texture *bindingTexture = texture;
|
||||
if (!bindingTexture) {
|
||||
bindingTexture = BuiltinResMgr::getInstance()->get<Texture2D>(ccstd::string("empty-texture"))->getGFXTexture();
|
||||
}
|
||||
if (bindingTexture) {
|
||||
gfx::SamplerInfo info{
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Filter::LINEAR,
|
||||
cc::gfx::Filter::NONE,
|
||||
cc::gfx::Address::CLAMP,
|
||||
cc::gfx::Address::CLAMP,
|
||||
cc::gfx::Address::CLAMP,
|
||||
};
|
||||
auto *sampler = _device->getSampler(info);
|
||||
for (SubModel *subModel : _subModels) {
|
||||
gfx::DescriptorSet *descriptorSet = subModel->getDescriptorSet();
|
||||
descriptorSet->bindTexture(pipeline::REFLECTIONPROBEPLANARMAP::BINDING, bindingTexture);
|
||||
descriptorSet->bindSampler(pipeline::REFLECTIONPROBEPLANARMAP::BINDING, sampler);
|
||||
descriptorSet->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateReflectionProbeDataMap(Texture2D *texture) {
|
||||
_localDataUpdated = true;
|
||||
|
||||
if (!texture) {
|
||||
texture = BuiltinResMgr::getInstance()->get<Texture2D>(ccstd::string("empty-texture"));
|
||||
}
|
||||
gfx::Texture *gfxTexture = texture->getGFXTexture();
|
||||
if (gfxTexture) {
|
||||
for (SubModel *subModel : _subModels) {
|
||||
gfx::DescriptorSet *descriptorSet = subModel->getDescriptorSet();
|
||||
descriptorSet->bindTexture(pipeline::REFLECTIONPROBEDATAMAP::BINDING, gfxTexture);
|
||||
descriptorSet->bindSampler(pipeline::REFLECTIONPROBEDATAMAP::BINDING, texture->getGFXSampler());
|
||||
descriptorSet->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateReflectionProbeBlendCubemap(TextureCube *texture) {
|
||||
_localDataUpdated = true;
|
||||
if (texture == nullptr) {
|
||||
texture = BuiltinResMgr::getInstance()->get<TextureCube>(ccstd::string("default-cube-texture"));
|
||||
}
|
||||
gfx::Texture *gfxTexture = texture->getGFXTexture();
|
||||
if (gfxTexture) {
|
||||
auto *sampler = _device->getSampler(texture->getSamplerInfo());
|
||||
for (SubModel *subModel : _subModels) {
|
||||
gfx::DescriptorSet *descriptorSet = subModel->getDescriptorSet();
|
||||
descriptorSet->bindTexture(pipeline::REFLECTIONPROBEBLENDCUBEMAP::BINDING, gfxTexture);
|
||||
descriptorSet->bindSampler(pipeline::REFLECTIONPROBEBLENDCUBEMAP::BINDING, sampler);
|
||||
descriptorSet->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::updateReflectionProbeId() {
|
||||
_localDataUpdated = true;
|
||||
}
|
||||
|
||||
void Model::setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteLength) {
|
||||
for (const auto &subModel : _subModels) {
|
||||
subModel->setInstancedAttribute(name, value, byteLength);
|
||||
}
|
||||
}
|
||||
void Model::setReflectionProbeType(UseReflectionProbeType val) {
|
||||
_reflectionProbeType = val;
|
||||
for (const auto &subModel : _subModels) {
|
||||
subModel->setReflectionProbeType(static_cast<int32_t>(val));
|
||||
}
|
||||
onMacroPatchesStateChanged();
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
316
cocos/scene/Model.h
Normal file
316
cocos/scene/Model.h
Normal file
@@ -0,0 +1,316 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "core/TypedArray.h"
|
||||
#include "core/assets/RenderingSubMesh.h"
|
||||
#include "core/assets/Texture2D.h"
|
||||
#include "core/assets/TextureCube.h"
|
||||
#include "core/builtin/BuiltinResMgr.h"
|
||||
#include "core/event/EventTarget.h"
|
||||
#include "core/geometry/AABB.h"
|
||||
#include "core/scene-graph/Layers.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "renderer/gfx-base/GFXBuffer.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "renderer/gfx-base/GFXTexture.h"
|
||||
#include "scene/SubModel.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Material;
|
||||
|
||||
namespace scene {
|
||||
|
||||
/**
|
||||
* @en Use Reflection probe
|
||||
* @zh 使用反射探针。
|
||||
*/
|
||||
enum class UseReflectionProbeType {
|
||||
/**
|
||||
* @en Use the default skybox.
|
||||
* @zh 使用默认天空盒。
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* @en Cubemap generate by probe.
|
||||
* @zh Probe烘焙的cubemap。
|
||||
*/
|
||||
BAKED_CUBEMAP,
|
||||
/**
|
||||
* @en Realtime planar reflection.
|
||||
* @zh 实时平面反射。
|
||||
*/
|
||||
PLANAR_REFLECTION,
|
||||
/**
|
||||
* @en Mixing between reflection probe.
|
||||
* @zh 反射探针之间进行混合。
|
||||
*/
|
||||
BLEND_PROBES,
|
||||
/**
|
||||
* @en Mixing between reflection probe and skybox.
|
||||
* @zh 反射探针之间混合或反射探针和天空盒之间混合。
|
||||
*/
|
||||
BLEND_PROBES_AND_SKYBOX,
|
||||
};
|
||||
|
||||
// SubModel.h -> Define.h -> Model.h, so do not include SubModel.h here.
|
||||
class SubModel;
|
||||
// RenderScene.h <-> Model.h, so do not include RenderScene.h here.
|
||||
class RenderScene;
|
||||
class OctreeNode;
|
||||
class Octree;
|
||||
class Pass;
|
||||
struct IMacroPatch;
|
||||
|
||||
class Model : public RefCounted {
|
||||
IMPL_EVENT_TARGET(Model)
|
||||
|
||||
DECLARE_TARGET_EVENT_BEGIN(Model)
|
||||
TARGET_EVENT_ARG1(UpdateTransform, uint32_t)
|
||||
TARGET_EVENT_ARG1(UpdateUBO, uint32_t)
|
||||
TARGET_EVENT_ARG2(UpdateLocalSHDescriptor, index_t, gfx::DescriptorSet *)
|
||||
TARGET_EVENT_ARG2(UpdateLocalDescriptors, index_t, gfx::DescriptorSet *)
|
||||
TARGET_EVENT_ARG2(UpdateWorldBound, index_t, gfx::DescriptorSet *)
|
||||
TARGET_EVENT_ARG2(UpdateInstancedAttributes, const std::vector<gfx::Attribute> &, SubModel *)
|
||||
TARGET_EVENT_ARG2(GetMacroPatches, index_t, std::vector<IMacroPatch> *)
|
||||
DECLARE_TARGET_EVENT_END()
|
||||
public:
|
||||
enum class Type {
|
||||
DEFAULT,
|
||||
SKINNING,
|
||||
BAKED_SKINNING,
|
||||
BATCH_2D,
|
||||
PARTICLE_BATCH,
|
||||
LINE,
|
||||
};
|
||||
|
||||
Model();
|
||||
~Model() override;
|
||||
|
||||
virtual void destroy();
|
||||
virtual void initSubModel(index_t idx, RenderingSubMesh *subMeshData, Material *mat);
|
||||
virtual ccstd::vector<IMacroPatch> getMacroPatches(index_t subModelIndex);
|
||||
virtual void setSubModelMaterial(index_t idx, Material *mat);
|
||||
virtual void updateInstancedAttributes(const ccstd::vector<gfx::Attribute> &attributes, SubModel *subModel);
|
||||
virtual void updateTransform(uint32_t stamp);
|
||||
virtual void updateUBOs(uint32_t stamp);
|
||||
virtual void updateLocalDescriptors(index_t subModelIndex, gfx::DescriptorSet *descriptorSet);
|
||||
virtual void updateLocalSHDescriptors(index_t subModelIndex, gfx::DescriptorSet *descriptorSet);
|
||||
virtual void updateWorldBoundDescriptors(index_t subModelIndex, gfx::DescriptorSet *descriptorSet);
|
||||
|
||||
void createBoundingShape(const ccstd::optional<Vec3> &minPos, const ccstd::optional<Vec3> &maxPos);
|
||||
void initialize();
|
||||
void initLightingmap(Texture2D *texture, const Vec4 &uvParam);
|
||||
void initLocalDescriptors(index_t subModelIndex);
|
||||
void initLocalSHDescriptors(index_t subModelIndex);
|
||||
void initWorldBoundDescriptors(index_t subModelIndex);
|
||||
void onGlobalPipelineStateChanged() const;
|
||||
void onMacroPatchesStateChanged();
|
||||
void onGeometryChanged();
|
||||
void setSubModelMesh(index_t idx, RenderingSubMesh *subMesh) const;
|
||||
void setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteLength);
|
||||
void updateWorldBound();
|
||||
void updateWorldBoundsForJSSkinningModel(const Vec3 &min, const Vec3 &max);
|
||||
void updateWorldBoundsForJSBakedSkinningModel(geometry::AABB *aabb);
|
||||
void updateLightingmap(Texture2D *texture, const Vec4 &uvParam);
|
||||
void clearSHUBOs();
|
||||
void updateSHUBOs();
|
||||
void updateOctree();
|
||||
void updateWorldBoundUBOs();
|
||||
void updateLocalShadowBias();
|
||||
void updateReflectionProbeCubemap(TextureCube *texture);
|
||||
void updateReflectionProbePlanarMap(gfx::Texture *texture);
|
||||
void updateReflectionProbeId();
|
||||
void updateReflectionProbeDataMap(Texture2D *texture);
|
||||
void updateReflectionProbeBlendCubemap(TextureCube *texture);
|
||||
|
||||
inline void attachToScene(RenderScene *scene) {
|
||||
_scene = scene;
|
||||
_localDataUpdated = true;
|
||||
}
|
||||
inline void detachFromScene() { _scene = nullptr; };
|
||||
inline void setCastShadow(bool value) { _castShadow = value; }
|
||||
inline void setEnabled(bool value) { _enabled = value; }
|
||||
inline void setLocalBuffer(gfx::Buffer *buffer) { _localBuffer = buffer; }
|
||||
inline void setLocalSHBuffer(gfx::Buffer *buffer) { _localSHBuffer = buffer; }
|
||||
inline void setWorldBoundBuffer(gfx::Buffer *buffer) { _worldBoundBuffer = buffer; }
|
||||
|
||||
inline void setNode(Node *node) { _node = node; }
|
||||
inline void setReceiveShadow(bool value) {
|
||||
_receiveShadow = value;
|
||||
onMacroPatchesStateChanged();
|
||||
}
|
||||
inline void setShadowBias(float bias) { _shadowBias.x = bias; }
|
||||
inline void setShadowNormalBias(float normalBias) { _shadowBias.y = normalBias; }
|
||||
inline void setTransform(Node *node) { _transform = node; }
|
||||
inline void setVisFlags(Layers::Enum flags) { _visFlags = flags; }
|
||||
inline void setBounds(geometry::AABB *world) {
|
||||
_worldBounds = world;
|
||||
_modelBounds->set(_worldBounds->getCenter(), _worldBounds->getHalfExtents());
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
inline void setOctreeNode(OctreeNode *node) { _octreeNode = node; }
|
||||
inline void setScene(RenderScene *scene) {
|
||||
_scene = scene;
|
||||
if (scene) _localDataUpdated = true;
|
||||
}
|
||||
|
||||
inline bool isInited() const { return _inited; }
|
||||
inline bool isCastShadow() const { return _castShadow; }
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
inline bool getUseLightProbe() const { return _useLightProbe; }
|
||||
inline void setUseLightProbe(bool val) {
|
||||
_useLightProbe = val;
|
||||
onMacroPatchesStateChanged();
|
||||
}
|
||||
inline bool getBakeToReflectionProbe() const { return _bakeToReflectionProbe; }
|
||||
inline void setBakeToReflectionProbe(bool val) {
|
||||
_bakeToReflectionProbe = val;
|
||||
}
|
||||
inline UseReflectionProbeType getReflectionProbeType() const { return _reflectionProbeType; }
|
||||
void setReflectionProbeType(UseReflectionProbeType val);
|
||||
inline int32_t getReflectionProbeId() const { return _reflectionProbeId; }
|
||||
inline void setReflectionProbeId(int32_t reflectionProbeId) {
|
||||
_reflectionProbeId = reflectionProbeId;
|
||||
_shadowBias.z = reflectionProbeId;
|
||||
}
|
||||
inline int32_t getReflectionProbeBlendId() const { return _reflectionProbeBlendId; }
|
||||
inline void setReflectionProbeBlendId(int32_t reflectionProbeId) {
|
||||
_reflectionProbeBlendId = reflectionProbeId;
|
||||
_shadowBias.w = reflectionProbeId;
|
||||
}
|
||||
inline float getReflectionProbeBlendWeight() const { return _reflectionProbeBlendWeight; }
|
||||
inline void setReflectionProbeBlendWeight(float weight) { _reflectionProbeBlendWeight = weight; }
|
||||
inline int32_t getTetrahedronIndex() const { return _tetrahedronIndex; }
|
||||
inline void setTetrahedronIndex(int32_t index) { _tetrahedronIndex = index; }
|
||||
inline bool showTetrahedron() const { return isLightProbeAvailable(); }
|
||||
inline gfx::Buffer *getLocalBuffer() const { return _localBuffer.get(); }
|
||||
inline gfx::Buffer *getLocalSHBuffer() const { return _localSHBuffer.get(); }
|
||||
inline gfx::Buffer *getWorldBoundBuffer() const { return _worldBoundBuffer.get(); }
|
||||
inline Float32Array getLocalSHData() const { return _localSHData; }
|
||||
inline geometry::AABB *getModelBounds() const { return _modelBounds; }
|
||||
inline Node *getNode() const { return _node.get(); }
|
||||
inline bool isReceiveShadow() const { return _receiveShadow; }
|
||||
inline const ccstd::vector<IntrusivePtr<SubModel>> &getSubModels() const { return _subModels; }
|
||||
inline Node *getTransform() const { return _transform.get(); }
|
||||
inline bool isLocalDataUpdated() const { return _localDataUpdated; }
|
||||
inline uint32_t getUpdateStamp() const { return _updateStamp; }
|
||||
inline Layers::Enum getVisFlags() const { return _visFlags; }
|
||||
inline geometry::AABB *getWorldBounds() const { return _worldBounds; }
|
||||
inline Type getType() const { return _type; };
|
||||
inline void setType(Type type) { _type = type; }
|
||||
inline OctreeNode *getOctreeNode() const { return _octreeNode; }
|
||||
inline RenderScene *getScene() const { return _scene; }
|
||||
inline void setDynamicBatching(bool val) { _isDynamicBatching = val; }
|
||||
inline bool isDynamicBatching() const { return _isDynamicBatching; }
|
||||
inline float getShadowBias() const { return _shadowBias.x; }
|
||||
inline float getShadowNormalBias() const { return _shadowBias.y; }
|
||||
inline uint32_t getPriority() const { return _priority; }
|
||||
inline void setPriority(uint32_t value) { _priority = value; }
|
||||
inline bool isReceiveDirLight() const { return _receiveDirLight; }
|
||||
inline void setReceiveDirLight(bool value) {
|
||||
_receiveDirLight = value;
|
||||
onMacroPatchesStateChanged();
|
||||
}
|
||||
inline void invalidateLocalData() { _localDataUpdated = true; }
|
||||
|
||||
// For JS
|
||||
inline void setCalledFromJS(bool v) { _isCalledFromJS = v; }
|
||||
inline void setLocalDataUpdated(bool v) { _localDataUpdated = v; }
|
||||
inline void setWorldBounds(geometry::AABB *bounds) {
|
||||
_worldBounds = bounds;
|
||||
_worldBoundsDirty = true;
|
||||
}
|
||||
inline void setModelBounds(geometry::AABB *bounds) { _modelBounds = bounds; }
|
||||
inline bool isModelImplementedInJS() const { return (_type != Type::DEFAULT && _type != Type::SKINNING && _type != Type::BAKED_SKINNING); };
|
||||
|
||||
protected:
|
||||
static SubModel *createSubModel();
|
||||
|
||||
void updateAttributesAndBinding(index_t subModelIndex);
|
||||
bool isLightProbeAvailable() const;
|
||||
void updateSHBuffer();
|
||||
|
||||
// Please declare variables in descending order of memory size occupied by variables.
|
||||
Type _type{Type::DEFAULT};
|
||||
Layers::Enum _visFlags{Layers::Enum::NONE};
|
||||
|
||||
UseReflectionProbeType _reflectionProbeType{ UseReflectionProbeType::NONE };
|
||||
int32_t _tetrahedronIndex{-1};
|
||||
uint32_t _descriptorSetCount{1};
|
||||
uint32_t _priority{0};
|
||||
uint32_t _updateStamp{0};
|
||||
int32_t _reflectionProbeId{-1};
|
||||
int32_t _reflectionProbeBlendId{ -1 };
|
||||
float _reflectionProbeBlendWeight{0.F};
|
||||
|
||||
OctreeNode *_octreeNode{nullptr};
|
||||
RenderScene *_scene{nullptr};
|
||||
gfx::Device *_device{nullptr};
|
||||
|
||||
IntrusivePtr<Node> _transform;
|
||||
IntrusivePtr<Node> _node;
|
||||
IntrusivePtr<gfx::Buffer> _localBuffer;
|
||||
IntrusivePtr<gfx::Buffer> _localSHBuffer;
|
||||
IntrusivePtr<gfx::Buffer> _worldBoundBuffer;
|
||||
IntrusivePtr<geometry::AABB> _worldBounds;
|
||||
IntrusivePtr<geometry::AABB> _modelBounds;
|
||||
IntrusivePtr<Texture2D> _lightmap;
|
||||
|
||||
bool _enabled{false};
|
||||
bool _castShadow{false};
|
||||
bool _receiveShadow{false};
|
||||
bool _isDynamicBatching{false};
|
||||
bool _inited{false};
|
||||
bool _localDataUpdated{false};
|
||||
bool _worldBoundsDirty{true};
|
||||
bool _useLightProbe = false;
|
||||
bool _bakeToReflectionProbe{true};
|
||||
bool _receiveDirLight{true};
|
||||
// For JS
|
||||
bool _isCalledFromJS{false};
|
||||
|
||||
Vec3 _lastWorldBoundCenter{INFINITY, INFINITY, INFINITY};
|
||||
|
||||
Vec4 _shadowBias{0.F, 0.F, -1.F, -1.F};
|
||||
Vec4 _lightmapUVParam;
|
||||
|
||||
// For JS
|
||||
// CallbacksInvoker _eventProcessor;
|
||||
ccstd::vector<IntrusivePtr<SubModel>> _subModels;
|
||||
|
||||
Float32Array _localSHData;
|
||||
|
||||
private:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Model);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
419
cocos/scene/Octree.cpp
Normal file
419
cocos/scene/Octree.cpp
Normal file
@@ -0,0 +1,419 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Octree.h"
|
||||
#include <future>
|
||||
#include <utility>
|
||||
#include "scene/Camera.h"
|
||||
#include "scene/Model.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
void OctreeInfo::setEnabled(bool val) {
|
||||
if (_enabled == val) {
|
||||
return;
|
||||
}
|
||||
_enabled = val;
|
||||
if (_resource) {
|
||||
_resource->setEnabled(val);
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeInfo::setMinPos(const Vec3 &val) {
|
||||
_minPos = val;
|
||||
if (_resource) {
|
||||
_resource->setMinPos(val);
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeInfo::setMaxPos(const Vec3 &val) {
|
||||
_maxPos = val;
|
||||
if (_resource) {
|
||||
_resource->setMaxPos(val);
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeInfo::setDepth(uint32_t val) {
|
||||
_depth = val;
|
||||
if (_resource) {
|
||||
_resource->setMaxDepth(val);
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeInfo::activate(Octree *resource) {
|
||||
_resource = resource;
|
||||
_resource->initialize(*this);
|
||||
}
|
||||
|
||||
/* children layout
|
||||
y
|
||||
|
|
||||
|_ _ _x
|
||||
/
|
||||
z/
|
||||
|
||||
--------
|
||||
/ 2 3 /
|
||||
/ 6 7 /
|
||||
---------
|
||||
/ 0 1 /
|
||||
/ 4 5 /
|
||||
--------
|
||||
**/
|
||||
|
||||
/**
|
||||
* OctreeNode class
|
||||
*/
|
||||
OctreeNode::OctreeNode(Octree *owner, OctreeNode *parent)
|
||||
: _owner(owner), _parent(parent) {
|
||||
}
|
||||
|
||||
OctreeNode::~OctreeNode() {
|
||||
for (auto i = 0; i < OCTREE_CHILDREN_NUM; i++) {
|
||||
deleteChild(i);
|
||||
}
|
||||
}
|
||||
|
||||
BBox OctreeNode::getChildBox(uint32_t index) const {
|
||||
cc::Vec3 min = _aabb.min;
|
||||
cc::Vec3 max = _aabb.max;
|
||||
const cc::Vec3 center = _aabb.getCenter();
|
||||
|
||||
if (index & 0x1) {
|
||||
min.x = center.x;
|
||||
} else {
|
||||
max.x = center.x;
|
||||
}
|
||||
|
||||
if (index & 0x2) {
|
||||
min.y = center.y;
|
||||
} else {
|
||||
max.y = center.y;
|
||||
}
|
||||
|
||||
if (index & 0x4) {
|
||||
min.z = center.z;
|
||||
} else {
|
||||
max.z = center.z;
|
||||
}
|
||||
|
||||
return {min, max};
|
||||
}
|
||||
|
||||
OctreeNode *OctreeNode::getOrCreateChild(uint32_t index) {
|
||||
if (!_children[index]) {
|
||||
BBox childBox = getChildBox(index);
|
||||
auto *child = _children[index] = ccnew OctreeNode(_owner, this);
|
||||
child->setBox(childBox);
|
||||
child->setDepth(_depth + 1);
|
||||
child->setIndex(index);
|
||||
}
|
||||
|
||||
return _children[index];
|
||||
}
|
||||
|
||||
void OctreeNode::deleteChild(uint32_t index) {
|
||||
if (_children[index]) {
|
||||
delete _children[index];
|
||||
_children[index] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeNode::insert(Model *model) { // NOLINT(misc-no-recursion)
|
||||
bool split = false;
|
||||
if (_depth < _owner->getMaxDepth() - 1) {
|
||||
BBox modelBox(*model->getWorldBounds());
|
||||
const cc::Vec3 &modelCenter = modelBox.getCenter();
|
||||
const cc::Vec3 &nodeCenter = _aabb.getCenter();
|
||||
|
||||
uint32_t index = modelCenter.x < nodeCenter.x ? 0 : 1;
|
||||
index += modelCenter.y < nodeCenter.y ? 0 : 2;
|
||||
index += modelCenter.z < nodeCenter.z ? 0 : 4;
|
||||
|
||||
BBox childBox = getChildBox(index);
|
||||
if (childBox.contain(modelBox)) {
|
||||
split = true;
|
||||
|
||||
// insert to child node recursively
|
||||
OctreeNode *child = getOrCreateChild(index);
|
||||
child->insert(model);
|
||||
}
|
||||
}
|
||||
|
||||
if (!split) {
|
||||
// insert to this node
|
||||
OctreeNode *lastNode = model->getOctreeNode();
|
||||
if (lastNode != this) {
|
||||
add(model);
|
||||
|
||||
if (lastNode) {
|
||||
lastNode->remove(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeNode::add(Model *model) {
|
||||
_models.push_back(model);
|
||||
model->setOctreeNode(this);
|
||||
}
|
||||
|
||||
void OctreeNode::remove(Model *model) {
|
||||
auto iter = std::find(_models.begin(), _models.end(), model);
|
||||
if (iter != _models.end()) {
|
||||
_models.erase(iter);
|
||||
}
|
||||
|
||||
onRemoved();
|
||||
}
|
||||
|
||||
void OctreeNode::onRemoved() { // NOLINT(misc-no-recursion)
|
||||
// delete empty node
|
||||
if (!_models.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto *child : _children) {
|
||||
if (child) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// delete recursively
|
||||
OctreeNode *parent = _parent;
|
||||
if (parent) {
|
||||
parent->deleteChild(_index);
|
||||
parent->onRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeNode::gatherModels(ccstd::vector<Model *> &results) const { // NOLINT(misc-no-recursion)
|
||||
for (auto *model : _models) {
|
||||
results.push_back(model);
|
||||
}
|
||||
|
||||
for (auto *child : _children) {
|
||||
if (child) {
|
||||
child->gatherModels(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeNode::doQueryVisibility(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const {
|
||||
const auto visibility = camera->getVisibility();
|
||||
for (auto *model : _models) {
|
||||
if (!model->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Node *node = model->getNode();
|
||||
if ((node && ((visibility & node->getLayer()) == node->getLayer())) ||
|
||||
(visibility & static_cast<uint32_t>(model->getVisFlags()))) {
|
||||
const geometry::AABB *modelWorldBounds = model->getWorldBounds();
|
||||
if (!modelWorldBounds) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isShadow) {
|
||||
if (model->isCastShadow() && modelWorldBounds->aabbFrustum(frustum)) {
|
||||
results.push_back(model);
|
||||
}
|
||||
} else {
|
||||
if (modelWorldBounds->aabbFrustum(frustum)) {
|
||||
results.push_back(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeNode::queryVisibilityParallelly(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const {
|
||||
geometry::AABB box;
|
||||
geometry::AABB::fromPoints(_aabb.min, _aabb.max, &box);
|
||||
if (!box.aabbFrustum(frustum)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccstd::array<std::future<ccstd::vector<const Model *>>, OCTREE_CHILDREN_NUM> futures{};
|
||||
for (auto i = 0; i < OCTREE_CHILDREN_NUM; i++) {
|
||||
if (_children[i]) {
|
||||
futures[i] = std::async(std::launch::async, [=, &frustum] {
|
||||
ccstd::vector<const Model *> models;
|
||||
_children[i]->queryVisibilitySequentially(camera, frustum, isShadow, models);
|
||||
return models;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
doQueryVisibility(camera, frustum, isShadow, results);
|
||||
|
||||
for (auto i = 0; i < OCTREE_CHILDREN_NUM; i++) {
|
||||
if (_children[i]) {
|
||||
auto models = futures[i].get();
|
||||
results.insert(results.end(), models.begin(), models.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeNode::queryVisibilitySequentially(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const { // NOLINT(misc-no-recursion)
|
||||
geometry::AABB box;
|
||||
geometry::AABB::fromPoints(_aabb.min, _aabb.max, &box);
|
||||
if (!box.aabbFrustum(frustum)) {
|
||||
return;
|
||||
}
|
||||
|
||||
doQueryVisibility(camera, frustum, isShadow, results);
|
||||
|
||||
// query recursively.
|
||||
for (auto *child : _children) {
|
||||
if (child) {
|
||||
child->queryVisibilitySequentially(camera, frustum, isShadow, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Octree class
|
||||
*/
|
||||
Octree::Octree() {
|
||||
_root = ccnew OctreeNode(this, nullptr);
|
||||
}
|
||||
|
||||
Octree::~Octree() {
|
||||
delete _root;
|
||||
}
|
||||
|
||||
void Octree::initialize(const OctreeInfo &info) {
|
||||
const Vec3 expand{OCTREE_BOX_EXPAND_SIZE, OCTREE_BOX_EXPAND_SIZE, OCTREE_BOX_EXPAND_SIZE};
|
||||
_minPos = info.getMinPos();
|
||||
_maxPos = info.getMaxPos();
|
||||
_maxDepth = std::max(info.getDepth(), 1U);
|
||||
setEnabled(info.isEnabled());
|
||||
_root->setBox(BBox{_minPos - expand, _maxPos});
|
||||
_root->setDepth(0);
|
||||
_root->setIndex(0);
|
||||
}
|
||||
|
||||
void Octree::setEnabled(bool val) {
|
||||
if (_enabled == val) {
|
||||
return;
|
||||
}
|
||||
_enabled = val;
|
||||
}
|
||||
|
||||
void Octree::setMinPos(const Vec3 &val) {
|
||||
_minPos = val;
|
||||
}
|
||||
|
||||
void Octree::setMaxPos(const Vec3 &val) {
|
||||
_maxPos = val;
|
||||
}
|
||||
|
||||
void Octree::setMaxDepth(uint32_t val) {
|
||||
_maxDepth = val;
|
||||
}
|
||||
|
||||
void Octree::resize(const Vec3 &minPos, const Vec3 &maxPos, uint32_t maxDepth) {
|
||||
const Vec3 expand{OCTREE_BOX_EXPAND_SIZE, OCTREE_BOX_EXPAND_SIZE, OCTREE_BOX_EXPAND_SIZE};
|
||||
BBox rootBox = _root->getBox();
|
||||
if ((minPos - expand) == rootBox.min && maxPos == rootBox.max && maxDepth == _maxDepth) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccstd::vector<Model *> models;
|
||||
_root->gatherModels(models);
|
||||
|
||||
delete _root;
|
||||
_root = ccnew OctreeNode(this, nullptr);
|
||||
_root->setBox(BBox{minPos - expand, maxPos});
|
||||
_root->setDepth(0);
|
||||
_root->setIndex(0);
|
||||
|
||||
_maxDepth = std::max(maxDepth, 1U);
|
||||
|
||||
for (auto *model : models) {
|
||||
model->setOctreeNode(nullptr);
|
||||
insert(model);
|
||||
}
|
||||
}
|
||||
|
||||
void Octree::insert(Model *model) {
|
||||
CC_ASSERT(model);
|
||||
|
||||
if (!model->getWorldBounds()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOutside(model)) {
|
||||
CC_LOG_WARNING("Octree insert: model is outside of the scene bounding box, please modify DEFAULT_WORLD_MIN_POS and DEFAULT_WORLD_MAX_POS.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!model->getOctreeNode()) {
|
||||
_totalCount++;
|
||||
}
|
||||
|
||||
_root->insert(model);
|
||||
}
|
||||
|
||||
void Octree::remove(Model *model) {
|
||||
CC_ASSERT(model);
|
||||
|
||||
OctreeNode *node = model->getOctreeNode();
|
||||
if (node) {
|
||||
node->remove(model);
|
||||
model->setOctreeNode(nullptr);
|
||||
_totalCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void Octree::update(Model *model) {
|
||||
insert(model);
|
||||
}
|
||||
|
||||
void Octree::queryVisibility(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const {
|
||||
if (_totalCount > USE_MULTI_THRESHOLD) {
|
||||
_root->queryVisibilityParallelly(camera, frustum, isShadow, results);
|
||||
} else {
|
||||
_root->queryVisibilitySequentially(camera, frustum, isShadow, results);
|
||||
}
|
||||
}
|
||||
|
||||
bool Octree::isInside(Model *model) const {
|
||||
const BBox &rootBox = _root->getBox();
|
||||
BBox modelBox = BBox(*model->getWorldBounds());
|
||||
|
||||
return rootBox.contain(modelBox);
|
||||
}
|
||||
|
||||
bool Octree::isOutside(Model *model) const {
|
||||
const BBox &rootBox = _root->getBox();
|
||||
BBox modelBox = BBox(*model->getWorldBounds());
|
||||
|
||||
return !rootBox.intersect(modelBox);
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
237
cocos/scene/Octree.h
Normal file
237
cocos/scene/Octree.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/array.h"
|
||||
#include "core/geometry/AABB.h"
|
||||
#include "math/Vec3.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class Camera;
|
||||
class Model;
|
||||
class Octree;
|
||||
|
||||
constexpr int OCTREE_CHILDREN_NUM = 8;
|
||||
constexpr int DEFAULT_OCTREE_DEPTH = 8;
|
||||
const Vec3 DEFAULT_WORLD_MIN_POS = {-1024.0F, -1024.0F, -1024.0F};
|
||||
const Vec3 DEFAULT_WORLD_MAX_POS = {1024.0F, 1024.0F, 1024.0F};
|
||||
const float OCTREE_BOX_EXPAND_SIZE = 10.0F;
|
||||
constexpr int USE_MULTI_THRESHOLD = 1024; // use parallel culling if greater than this value
|
||||
|
||||
class CC_DLL OctreeInfo final : public RefCounted {
|
||||
public:
|
||||
OctreeInfo() = default;
|
||||
~OctreeInfo() override = default;
|
||||
/**
|
||||
* @en Whether activate octree
|
||||
* @zh 是否启用八叉树加速剔除?
|
||||
*/
|
||||
void setEnabled(bool val);
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
|
||||
/**
|
||||
* @en min pos of scene bounding box
|
||||
* @zh 场景包围盒最小值
|
||||
*/
|
||||
void setMinPos(const Vec3 &val);
|
||||
inline const Vec3 &getMinPos() const { return _minPos; }
|
||||
|
||||
/**
|
||||
* @en max pos of scene bounding box
|
||||
* @zh 场景包围盒最大值
|
||||
*/
|
||||
void setMaxPos(const Vec3 &val);
|
||||
inline const Vec3 &getMaxPos() const { return _maxPos; }
|
||||
|
||||
/**
|
||||
* @en depth of octree
|
||||
* @zh 八叉树深度
|
||||
*/
|
||||
void setDepth(uint32_t val);
|
||||
inline uint32_t getDepth() const { return _depth; }
|
||||
|
||||
void activate(Octree *resource);
|
||||
|
||||
// JS deserialization require the properties to be public
|
||||
// private:
|
||||
bool _enabled{false};
|
||||
Vec3 _minPos{DEFAULT_WORLD_MIN_POS};
|
||||
Vec3 _maxPos{DEFAULT_WORLD_MAX_POS};
|
||||
uint32_t _depth{DEFAULT_OCTREE_DEPTH};
|
||||
|
||||
private:
|
||||
Octree *_resource{nullptr};
|
||||
};
|
||||
|
||||
// Axis aligned bounding box
|
||||
struct CC_DLL BBox final {
|
||||
cc::Vec3 min;
|
||||
cc::Vec3 max;
|
||||
|
||||
BBox() = default;
|
||||
|
||||
explicit BBox(const geometry::AABB &aabb)
|
||||
: min(aabb.getCenter() - aabb.getHalfExtents()), max(aabb.getCenter() + aabb.getHalfExtents()) {
|
||||
}
|
||||
|
||||
BBox(const cc::Vec3 &minPos, const cc::Vec3 &maxPos)
|
||||
: min(minPos), max(maxPos) {
|
||||
}
|
||||
|
||||
inline cc::Vec3 getCenter() const {
|
||||
return (min + max) * 0.5F;
|
||||
}
|
||||
|
||||
inline bool operator==(const BBox &box) const {
|
||||
return min == box.min && max == box.max;
|
||||
}
|
||||
|
||||
inline bool contain(const cc::Vec3 &point) const {
|
||||
return !(point.x > max.x || point.x < min.x ||
|
||||
point.y > max.y || point.y < min.y ||
|
||||
point.z > max.z || point.z < min.z);
|
||||
}
|
||||
|
||||
inline bool contain(const BBox &box) const {
|
||||
return contain(box.min) && contain(box.max);
|
||||
}
|
||||
|
||||
inline bool intersect(const BBox &box) const {
|
||||
return !(min.x > box.max.x || max.x < box.min.x ||
|
||||
min.y > box.max.y || max.y < box.min.y ||
|
||||
min.z > box.max.z || max.z < box.min.z);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* OctreeNode class
|
||||
*/
|
||||
class CC_DLL OctreeNode final {
|
||||
private:
|
||||
OctreeNode(Octree *owner, OctreeNode *parent);
|
||||
~OctreeNode();
|
||||
|
||||
inline void setBox(const BBox &aabb) { _aabb = aabb; }
|
||||
inline void setDepth(uint32_t depth) { _depth = depth; }
|
||||
inline void setIndex(uint32_t index) { _index = index; }
|
||||
|
||||
inline Octree *getOwner() const { return _owner; }
|
||||
inline const BBox &getBox() const { return _aabb; }
|
||||
BBox getChildBox(uint32_t index) const;
|
||||
OctreeNode *getOrCreateChild(uint32_t index);
|
||||
void deleteChild(uint32_t index);
|
||||
void insert(Model *model);
|
||||
void add(Model *model);
|
||||
void remove(Model *model);
|
||||
void onRemoved();
|
||||
void gatherModels(ccstd::vector<Model *> &results) const;
|
||||
void doQueryVisibility(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const;
|
||||
void queryVisibilityParallelly(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const;
|
||||
void queryVisibilitySequentially(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const;
|
||||
|
||||
Octree *_owner{nullptr};
|
||||
OctreeNode *_parent{nullptr};
|
||||
ccstd::array<OctreeNode *, OCTREE_CHILDREN_NUM> _children{};
|
||||
ccstd::vector<Model *> _models;
|
||||
BBox _aabb{};
|
||||
uint32_t _depth{0};
|
||||
uint32_t _index{0};
|
||||
|
||||
friend class Octree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Octree class
|
||||
*/
|
||||
class CC_DLL Octree final {
|
||||
public:
|
||||
Octree();
|
||||
~Octree();
|
||||
|
||||
void initialize(const OctreeInfo &info);
|
||||
|
||||
/**
|
||||
* @en Whether activate octree
|
||||
* @zh 是否启用八叉树加速剔除?
|
||||
*/
|
||||
void setEnabled(bool val);
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
|
||||
/**
|
||||
* @en min pos of scene bounding box
|
||||
* @zh 场景包围盒最小值
|
||||
*/
|
||||
void setMinPos(const Vec3 &val);
|
||||
inline const Vec3 &getMinPos() const { return _minPos; }
|
||||
|
||||
/**
|
||||
* @en max pos of scene bounding box
|
||||
* @zh 场景包围盒最大值
|
||||
*/
|
||||
void setMaxPos(const Vec3 &val);
|
||||
inline const Vec3 &getMaxPos() const { return _maxPos; }
|
||||
|
||||
// reinsert all models in the tree when you change the aabb or max depth in editor
|
||||
void resize(const Vec3 &minPos, const Vec3 &maxPos, uint32_t maxDepth);
|
||||
|
||||
// insert a model to tree.
|
||||
void insert(Model *model);
|
||||
|
||||
// remove a model from tree.
|
||||
void remove(Model *model);
|
||||
|
||||
// update model's location in the tree.
|
||||
void update(Model *model);
|
||||
|
||||
/**
|
||||
* @en depth of octree
|
||||
* @zh 八叉树深度
|
||||
*/
|
||||
void setMaxDepth(uint32_t val);
|
||||
// return octree depth
|
||||
inline uint32_t getMaxDepth() const { return _maxDepth; }
|
||||
|
||||
// view frustum culling
|
||||
void queryVisibility(const Camera *camera, const geometry::Frustum &frustum, bool isShadow, ccstd::vector<const Model *> &results) const;
|
||||
|
||||
private:
|
||||
bool isInside(Model *model) const;
|
||||
bool isOutside(Model *model) const;
|
||||
|
||||
OctreeNode *_root{nullptr};
|
||||
uint32_t _maxDepth{DEFAULT_OCTREE_DEPTH};
|
||||
uint32_t _totalCount{0};
|
||||
|
||||
bool _enabled{false};
|
||||
Vec3 _minPos;
|
||||
Vec3 _maxPos;
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
880
cocos/scene/Pass.cpp
Normal file
880
cocos/scene/Pass.cpp
Normal file
@@ -0,0 +1,880 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Pass.h"
|
||||
#include "base/std/hash/hash.h"
|
||||
#include "cocos/bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/renderer/pipeline/custom/RenderingModule.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/assets/EffectAsset.h"
|
||||
#include "core/assets/TextureBase.h"
|
||||
#include "core/builtin/BuiltinResMgr.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "pipeline/custom/details/GslUtils.h"
|
||||
#include "renderer/core/PassUtils.h"
|
||||
#include "renderer/core/ProgramLib.h"
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
#include "renderer/gfx-base/states/GFXSampler.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
#include "renderer/pipeline/InstancedBuffer.h"
|
||||
#include "scene/Define.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t INVALID_ID = 0xFFFFFFFF;
|
||||
|
||||
ccstd::hash_t serializeBlendState(const gfx::BlendState &bs) {
|
||||
ccstd::hash_t hashValue{2};
|
||||
ccstd::hash_combine(hashValue, bs.isA2C);
|
||||
for (const auto &t : bs.targets) {
|
||||
ccstd::hash_combine(hashValue, t.blend);
|
||||
ccstd::hash_combine(hashValue, t.blendEq);
|
||||
ccstd::hash_combine(hashValue, t.blendAlphaEq);
|
||||
ccstd::hash_combine(hashValue, t.blendColorMask);
|
||||
ccstd::hash_combine(hashValue, t.blendSrc);
|
||||
ccstd::hash_combine(hashValue, t.blendDst);
|
||||
ccstd::hash_combine(hashValue, t.blendSrcAlpha);
|
||||
ccstd::hash_combine(hashValue, t.blendDstAlpha);
|
||||
}
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
ccstd::hash_t serializeRasterizerState(const gfx::RasterizerState &rs) {
|
||||
ccstd::hash_t hashValue{2};
|
||||
ccstd::hash_combine(hashValue, rs.cullMode);
|
||||
ccstd::hash_combine(hashValue, rs.depthBias);
|
||||
ccstd::hash_combine(hashValue, rs.isFrontFaceCCW);
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
ccstd::hash_t serializeDepthStencilState(const gfx::DepthStencilState &dss) {
|
||||
ccstd::hash_t hashValue{2};
|
||||
ccstd::hash_combine(hashValue, dss.depthTest);
|
||||
ccstd::hash_combine(hashValue, dss.depthWrite);
|
||||
ccstd::hash_combine(hashValue, dss.depthFunc);
|
||||
ccstd::hash_combine(hashValue, dss.stencilTestFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilFuncFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilRefFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilReadMaskFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilFailOpFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilZFailOpFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilPassOpFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilWriteMaskFront);
|
||||
ccstd::hash_combine(hashValue, dss.stencilTestBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilFuncBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilRefBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilReadMaskBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilFailOpBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilZFailOpBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilPassOpBack);
|
||||
ccstd::hash_combine(hashValue, dss.stencilWriteMaskBack);
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*static*/
|
||||
void Pass::fillPipelineInfo(Pass *pass, const IPassInfoFull &info) {
|
||||
if (info.priority.has_value()) {
|
||||
pass->_priority = static_cast<pipeline::RenderPriority>(info.priority.value());
|
||||
}
|
||||
if (info.primitive.has_value()) {
|
||||
pass->_primitive = info.primitive.value();
|
||||
}
|
||||
if (info.stage.has_value()) {
|
||||
pass->_stage = info.stage.value();
|
||||
}
|
||||
if (info.dynamicStates.has_value()) {
|
||||
pass->_dynamicStates = info.dynamicStates.value();
|
||||
}
|
||||
if (info.phase.has_value()) {
|
||||
pass->_phaseString = info.phase.value();
|
||||
pass->_phase = pipeline::getPhaseID(pass->_phaseString);
|
||||
}
|
||||
|
||||
if (info.blendState.has_value()) {
|
||||
info.blendState.value().assignToGFXBlendState(pass->_blendState);
|
||||
}
|
||||
|
||||
if (info.rasterizerState.has_value()) {
|
||||
info.rasterizerState.value().assignToGFXRasterizerState(pass->_rs);
|
||||
}
|
||||
|
||||
if (info.depthStencilState.has_value()) {
|
||||
info.depthStencilState.value().assignToGFXDepthStencilState(pass->_depthStencilState);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
ccstd::hash_t Pass::getPassHash(Pass *pass) {
|
||||
ccstd::hash_t hashValue{666};
|
||||
ccstd::hash_combine(hashValue, pass->_primitive);
|
||||
ccstd::hash_combine(hashValue, pass->_dynamicStates);
|
||||
ccstd::hash_combine(hashValue, serializeBlendState(pass->_blendState));
|
||||
ccstd::hash_combine(hashValue, serializeDepthStencilState(pass->_depthStencilState));
|
||||
ccstd::hash_combine(hashValue, serializeRasterizerState(pass->_rs));
|
||||
|
||||
const auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
const auto &shaderKey = programLib->getKey(pass->_phaseID, pass->getProgram(), pass->getDefines());
|
||||
ccstd::hash_combine(hashValue, pass->_phaseID);
|
||||
ccstd::hash_range(hashValue, shaderKey.begin(), shaderKey.end());
|
||||
} else {
|
||||
const ccstd::string &shaderKey = ProgramLib::getInstance()->getKey(pass->getProgram(), pass->getDefines());
|
||||
ccstd::hash_range(hashValue, shaderKey.begin(), shaderKey.end());
|
||||
}
|
||||
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
Pass::Pass() : Pass(Root::getInstance()) {}
|
||||
|
||||
Pass::Pass(Root *root) {
|
||||
_device = root->getDevice();
|
||||
_root = root;
|
||||
_phaseString = "default";
|
||||
_phase = pipeline::getPhaseID(_phaseString);
|
||||
}
|
||||
|
||||
Pass::~Pass() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void Pass::initialize(const IPassInfoFull &info) {
|
||||
doInit(info);
|
||||
resetUBOs();
|
||||
resetTextures();
|
||||
tryCompile();
|
||||
}
|
||||
|
||||
uint32_t Pass::getHandle(const ccstd::string &name, uint32_t offset /* = 0 */, gfx::Type targetType /* = gfx::Type::UNKNOWN */) const {
|
||||
uint32_t handle = 0;
|
||||
auto iter = _propertyHandleMap.find(name); // handle = _propertyHandleMap[name];
|
||||
if (iter == _propertyHandleMap.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle = iter->second;
|
||||
|
||||
if (targetType != gfx::Type::UNKNOWN) {
|
||||
handle = customizeType(handle, targetType);
|
||||
} else if (offset) {
|
||||
handle = customizeType(handle, static_cast<gfx::Type>(static_cast<uint32_t>(getTypeFromHandle(handle)) - offset));
|
||||
}
|
||||
return handle + offset;
|
||||
}
|
||||
|
||||
uint32_t Pass::getBinding(const ccstd::string &name) const {
|
||||
uint32_t handle = getHandle(name);
|
||||
if (0 == handle) {
|
||||
return -1;
|
||||
}
|
||||
return Pass::getBindingFromHandle(handle);
|
||||
}
|
||||
|
||||
void Pass::setUniform(uint32_t handle, const MaterialProperty &value) {
|
||||
const uint32_t binding = Pass::getBindingFromHandle(handle);
|
||||
const gfx::Type type = Pass::getTypeFromHandle(handle);
|
||||
const uint32_t ofs = Pass::getOffsetFromHandle(handle);
|
||||
auto &block = _blocks[binding];
|
||||
#if CC_DEBUG
|
||||
auto validatorIt = type2validator.find(type);
|
||||
if (validatorIt != type2validator.end()) {
|
||||
if (!validatorIt->second(value)) {
|
||||
const ccstd::string stack = se::ScriptEngine::getInstance()->getCurrentStackTrace();
|
||||
debug::errorID(12011, binding, stack.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
auto writerIt = type2writer.find(type);
|
||||
if (writerIt != type2writer.end()) {
|
||||
writerIt->second(block.data, value, static_cast<int>(ofs));
|
||||
}
|
||||
|
||||
_rootBufferDirty = true;
|
||||
}
|
||||
|
||||
MaterialProperty Pass::getUniform(uint32_t handle) const {
|
||||
MaterialProperty out;
|
||||
const uint32_t binding = Pass::getBindingFromHandle(handle);
|
||||
const gfx::Type type = Pass::getTypeFromHandle(handle);
|
||||
const uint32_t ofs = Pass::getOffsetFromHandle(handle);
|
||||
const auto &block = _blocks[binding];
|
||||
auto iter = type2reader.find(type);
|
||||
if (iter != type2reader.end()) {
|
||||
iter->second(block.data, out, static_cast<int>(ofs));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void Pass::setUniformArray(uint32_t handle, const MaterialPropertyList &value) {
|
||||
const uint32_t binding = Pass::getBindingFromHandle(handle);
|
||||
const gfx::Type type = Pass::getTypeFromHandle(handle);
|
||||
const uint32_t stride = gfx::getTypeSize(type) >> 2;
|
||||
auto &block = _blocks[binding];
|
||||
uint32_t ofs = Pass::getOffsetFromHandle(handle);
|
||||
for (size_t i = 0; i < value.size(); i++, ofs += stride) {
|
||||
if (value[i].index() == 0) {
|
||||
continue;
|
||||
}
|
||||
auto iter = type2writer.find(type);
|
||||
if (iter != type2writer.end()) {
|
||||
iter->second(block.data, value[i], static_cast<int>(ofs));
|
||||
}
|
||||
}
|
||||
_rootBufferDirty = true;
|
||||
}
|
||||
|
||||
void Pass::bindTexture(uint32_t binding, gfx::Texture *value, uint32_t index) {
|
||||
_descriptorSet->bindTexture(binding, value, index);
|
||||
}
|
||||
|
||||
void Pass::bindSampler(uint32_t binding, gfx::Sampler *value, uint32_t index) {
|
||||
_descriptorSet->bindSampler(binding, value, index);
|
||||
}
|
||||
|
||||
void Pass::setDynamicState(gfx::DynamicStateFlagBit state, float value) {
|
||||
auto &ds = _dynamics[static_cast<uint32_t>(state)];
|
||||
if (ds.value == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
ds.value = value;
|
||||
ds.dirty = true;
|
||||
}
|
||||
|
||||
void Pass::overridePipelineStates(const IPassInfo & /*original*/, const PassOverrides & /*overrides*/) {
|
||||
CC_LOG_WARNING("base pass cannot override states, please use pass instance instead.");
|
||||
}
|
||||
|
||||
void Pass::update() {
|
||||
if (_descriptorSet == nullptr) {
|
||||
debug::errorID(12006);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_rootBufferDirty && _rootBuffer) {
|
||||
_rootBuffer->update(_rootBlock->getData(), _rootBlock->byteLength());
|
||||
_rootBufferDirty = false;
|
||||
}
|
||||
_descriptorSet->update();
|
||||
}
|
||||
|
||||
pipeline::InstancedBuffer *Pass::getInstancedBuffer(int32_t extraKey) {
|
||||
auto iter = _instancedBuffers.find(extraKey);
|
||||
if (iter != _instancedBuffers.end()) {
|
||||
return iter->second.get();
|
||||
}
|
||||
auto *instancedBuffer = ccnew pipeline::InstancedBuffer(this);
|
||||
_instancedBuffers[extraKey] = instancedBuffer;
|
||||
return instancedBuffer;
|
||||
}
|
||||
|
||||
void Pass::destroy() {
|
||||
if (!_buffers.empty()) {
|
||||
for (const auto &u : _shaderInfo->blocks) {
|
||||
_buffers[u.binding]->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
_buffers.clear();
|
||||
|
||||
if (_rootBuffer) {
|
||||
_rootBuffer->destroy();
|
||||
_rootBuffer = nullptr;
|
||||
}
|
||||
|
||||
for (auto &ib : _instancedBuffers) {
|
||||
ib.second->destroy();
|
||||
}
|
||||
_instancedBuffers.clear();
|
||||
|
||||
// NOTE: There may be many passes reference the same descriptor set,
|
||||
// so here we can't use _descriptorSet->destroy() to release it.
|
||||
// Its type is IntrusivePtr<gfx::DescriptorSet>, so just set it to nullptr,
|
||||
// and let its destructor to destroy it.
|
||||
_descriptorSet = nullptr;
|
||||
}
|
||||
|
||||
void Pass::resetUniform(const ccstd::string &name) {
|
||||
const uint32_t handle = getHandle(name);
|
||||
if (0 == handle) {
|
||||
return;
|
||||
}
|
||||
const gfx::Type type = Pass::getTypeFromHandle(handle);
|
||||
const uint32_t binding = Pass::getBindingFromHandle(handle);
|
||||
const uint32_t ofs = Pass::getOffsetFromHandle(handle);
|
||||
const uint32_t count = Pass::getCountFromHandle(handle);
|
||||
auto &block = _blocks[binding];
|
||||
ccstd::optional<IPropertyValue> givenDefaultOpt;
|
||||
auto iter = _properties.find(name);
|
||||
if (iter != _properties.end()) {
|
||||
givenDefaultOpt = iter->second.value;
|
||||
}
|
||||
|
||||
if (givenDefaultOpt.has_value()) {
|
||||
const auto &value = givenDefaultOpt.value();
|
||||
if (ccstd::holds_alternative<ccstd::vector<float>>(value)) {
|
||||
const auto &floatArr = ccstd::get<ccstd::vector<float>>(value);
|
||||
auto iter = type2writer.find(type);
|
||||
if (iter != type2writer.end()) {
|
||||
CC_ASSERT_EQ(floatArr.size(), 2);
|
||||
iter->second(block.data, toMaterialProperty(type, floatArr), static_cast<int32_t>(ofs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_rootBufferDirty = true;
|
||||
}
|
||||
|
||||
void Pass::resetTexture(const ccstd::string &name) {
|
||||
resetTexture(name, 0);
|
||||
}
|
||||
|
||||
void Pass::resetTexture(const ccstd::string &name, uint32_t index) {
|
||||
const uint32_t handle = getHandle(name);
|
||||
if (0 == handle) {
|
||||
return;
|
||||
}
|
||||
const gfx::Type type = Pass::getTypeFromHandle(handle);
|
||||
const uint32_t binding = Pass::getBindingFromHandle(handle);
|
||||
ccstd::string texName;
|
||||
const IPropertyInfo *info = nullptr;
|
||||
auto iter = _properties.find(name);
|
||||
if (iter != _properties.end()) {
|
||||
if (iter->second.value.has_value()) {
|
||||
info = &iter->second;
|
||||
const ccstd::string *pStrVal = ccstd::get_if<ccstd::string>(&iter->second.value.value());
|
||||
if (pStrVal != nullptr) {
|
||||
texName = (*pStrVal) + getStringFromType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texName.empty()) {
|
||||
texName = getDefaultStringFromType(type);
|
||||
}
|
||||
|
||||
auto *textureBase = BuiltinResMgr::getInstance()->get<TextureBase>(texName);
|
||||
gfx::Texture *texture = textureBase != nullptr ? textureBase->getGFXTexture() : nullptr;
|
||||
ccstd::optional<gfx::SamplerInfo> samplerInfo;
|
||||
if (info != nullptr && info->samplerHash.has_value()) {
|
||||
samplerInfo = gfx::Sampler::unpackFromHash(info->samplerHash.value());
|
||||
} else if (textureBase != nullptr) {
|
||||
samplerInfo = textureBase->getSamplerInfo();
|
||||
}
|
||||
|
||||
if (samplerInfo.has_value()) {
|
||||
auto *sampler = _device->getSampler(samplerInfo.value());
|
||||
_descriptorSet->bindSampler(binding, sampler, index);
|
||||
_descriptorSet->bindTexture(binding, texture, index);
|
||||
} else {
|
||||
CC_LOG_WARNING("sampler hash could not be found!");
|
||||
}
|
||||
}
|
||||
|
||||
void Pass::resetUBOs() {
|
||||
auto updateBuffer = [&](const IBlockInfo &u) {
|
||||
uint32_t ofs = 0;
|
||||
for (const auto &cur : u.members) {
|
||||
const auto &block = _blocks[u.binding];
|
||||
auto iter = _properties.find(cur.name);
|
||||
const auto &value =
|
||||
(iter != _properties.end() && iter->second.value.has_value()
|
||||
? ccstd::get<ccstd::vector<float>>(iter->second.value.value())
|
||||
: getDefaultFloatArrayFromType(cur.type));
|
||||
const uint32_t size = (gfx::getTypeSize(cur.type) >> 2) * cur.count;
|
||||
for (size_t k = 0; (k + value.size()) <= size; k += value.size()) {
|
||||
std::copy(value.begin(), value.end(), block.data + ofs + k);
|
||||
}
|
||||
ofs += size;
|
||||
}
|
||||
};
|
||||
for (const auto &u : _shaderInfo->blocks) {
|
||||
updateBuffer(u);
|
||||
}
|
||||
_rootBufferDirty = true;
|
||||
}
|
||||
|
||||
void Pass::resetTextures() {
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
const auto &set = _shaderInfo->descriptors.at(
|
||||
static_cast<size_t>(pipeline::SetIndex::MATERIAL));
|
||||
for (const auto &combined : set.samplerTextures) {
|
||||
for (int32_t j = 0; j < combined.count; j++) {
|
||||
resetTexture(combined.name, j);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &u : _shaderInfo->samplerTextures) {
|
||||
for (int32_t j = 0; j < u.count; j++) {
|
||||
resetTexture(u.name, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Pass::tryCompile() {
|
||||
if (_root->getPipeline() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
syncBatchingScheme();
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
auto *shaderProxy = programLib->getProgramVariant(_device, _phaseID, _programName, _defines);
|
||||
if (!shaderProxy) {
|
||||
CC_LOG_WARNING("create shader %s failed", _programName.c_str());
|
||||
return false;
|
||||
}
|
||||
_shader = shaderProxy->getShader();
|
||||
_pipelineLayout = programLib->getPipelineLayout(_device, _phaseID, _programName);
|
||||
} else {
|
||||
auto *shader = ProgramLib::getInstance()->getGFXShader(_device, _programName, _defines, _root->getPipeline());
|
||||
if (!shader) {
|
||||
CC_LOG_WARNING("create shader %s failed", _programName.c_str());
|
||||
return false;
|
||||
}
|
||||
_shader = shader;
|
||||
_pipelineLayout = ProgramLib::getInstance()->getTemplateInfo(_programName)->pipelineLayout;
|
||||
}
|
||||
|
||||
_hash = Pass::getPassHash(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
gfx::Shader *Pass::getShaderVariant() {
|
||||
return getShaderVariant({});
|
||||
}
|
||||
|
||||
gfx::Shader *Pass::getShaderVariant(const ccstd::vector<IMacroPatch> &patches) {
|
||||
if (!_shader && !tryCompile()) {
|
||||
CC_LOG_WARNING("pass resources incomplete");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (patches.empty()) {
|
||||
return _shader;
|
||||
}
|
||||
#if CC_EDITOR
|
||||
for (const auto &patch : patches) {
|
||||
std::size_t pos = patch.name.find_first_of("CC_");
|
||||
if (pos != 0) { // not startsWith CC_
|
||||
CC_LOG_WARNING("cannot patch non-builtin macros");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
auto *pipeline = _root->getPipeline();
|
||||
for (const auto &patch : patches) {
|
||||
_defines[patch.name] = patch.value;
|
||||
}
|
||||
|
||||
if (isBlend()) {
|
||||
_defines["CC_IS_TRANSPARENCY_PASS"] = MacroValue(true);
|
||||
}
|
||||
|
||||
gfx::Shader *shader = nullptr;
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
const auto *program = programLib->getProgramVariant(_device, _phaseID, _programName, _defines);
|
||||
if (program) {
|
||||
shader = program->getShader();
|
||||
}
|
||||
} else {
|
||||
shader = ProgramLib::getInstance()->getGFXShader(_device, _programName, _defines, pipeline);
|
||||
}
|
||||
|
||||
for (const auto &patch : patches) {
|
||||
auto iter = _defines.find(patch.name);
|
||||
if (iter != _defines.end()) {
|
||||
_defines.erase(iter);
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
bool Pass::isBlend() {
|
||||
bool isBlend = false;
|
||||
for (const auto target : _blendState.targets) {
|
||||
if (target.blend) {
|
||||
isBlend = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isBlend;
|
||||
}
|
||||
|
||||
IPassInfoFull Pass::getPassInfoFull() const {
|
||||
IPassInfoFull ret;
|
||||
ret.passIndex = _passIndex;
|
||||
ret.defines = _defines;
|
||||
|
||||
ret.program = _programName;
|
||||
ret.propertyIndex = _propertyIndex;
|
||||
ret.properties = _properties;
|
||||
ret.priority = static_cast<int32_t>(_priority);
|
||||
|
||||
ret.primitive = _primitive;
|
||||
ret.stage = _stage;
|
||||
|
||||
RasterizerStateInfo rsInfo;
|
||||
rsInfo.fromGFXRasterizerState(_rs);
|
||||
ret.rasterizerState = rsInfo;
|
||||
|
||||
DepthStencilStateInfo dsInfo;
|
||||
dsInfo.fromGFXDepthStencilState(_depthStencilState);
|
||||
ret.depthStencilState = dsInfo;
|
||||
|
||||
BlendStateInfo bsInfo;
|
||||
bsInfo.fromGFXBlendState(_blendState);
|
||||
ret.blendState = bsInfo;
|
||||
|
||||
ret.dynamicStates = _dynamicStates;
|
||||
ret.phase = _phaseString;
|
||||
|
||||
ret.passID = _passID;
|
||||
ret.subpassID = _subpassID;
|
||||
ret.phaseID = _phaseID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Pass::setState(const gfx::BlendState &bs, const gfx::DepthStencilState &dss, const gfx::RasterizerState &rs, gfx::DescriptorSet *ds) {
|
||||
// cjh how to control lifecycle?
|
||||
_blendState = bs;
|
||||
_depthStencilState = dss;
|
||||
_rs = rs;
|
||||
_descriptorSet = ds;
|
||||
}
|
||||
|
||||
void Pass::doInit(const IPassInfoFull &info, bool /*copyDefines*/ /* = false */) {
|
||||
auto *programLib = ProgramLib::getInstance();
|
||||
_priority = pipeline::RenderPriority::DEFAULT;
|
||||
_stage = pipeline::RenderPassStage::DEFAULT;
|
||||
auto *programLib2 = render::getProgramLibrary();
|
||||
if (programLib2) {
|
||||
const auto *rendering = render::getRenderingModule();
|
||||
CC_EXPECTS(rendering);
|
||||
if (info.phaseID != INVALID_ID) {
|
||||
_passID = info.passID;
|
||||
_subpassID = info.subpassID;
|
||||
_phaseID = info.phaseID;
|
||||
} else {
|
||||
if (info.pass) {
|
||||
_passID = rendering->getPassID(*info.pass);
|
||||
} else {
|
||||
_passID = rendering->getPassID("default");
|
||||
}
|
||||
CC_ENSURES(_passID != INVALID_ID);
|
||||
if (info.subpass) {
|
||||
CC_EXPECTS(!info.subpass->empty());
|
||||
_subpassID = rendering->getSubpassID(_passID, *info.subpass);
|
||||
CC_ENSURES(_subpassID != INVALID_ID);
|
||||
}
|
||||
if (info.phase) {
|
||||
_phaseID = rendering->getPhaseID(getSubpassOrPassID(), *info.phase);
|
||||
} else {
|
||||
_phaseID = rendering->getPhaseID(getSubpassOrPassID(), "default");
|
||||
}
|
||||
}
|
||||
if (_passID == INVALID_ID) {
|
||||
CC_LOG_ERROR("Invalid pass ID");
|
||||
return;
|
||||
}
|
||||
if (info.subpass && _subpassID == INVALID_ID) {
|
||||
CC_LOG_ERROR("Invalid subpass ID");
|
||||
return;
|
||||
}
|
||||
if (_phaseID == INVALID_ID) {
|
||||
CC_LOG_ERROR("Invalid phase ID");
|
||||
return;
|
||||
}
|
||||
}
|
||||
_phaseString = "default";
|
||||
_phase = pipeline::getPhaseID(_phaseString);
|
||||
_primitive = gfx::PrimitiveMode::TRIANGLE_LIST;
|
||||
|
||||
_passIndex = info.passIndex;
|
||||
_propertyIndex = info.propertyIndex.has_value() ? info.propertyIndex.value() : info.passIndex;
|
||||
_programName = info.program;
|
||||
_defines = info.defines; // cjh c++ always does copy by assignment. copyDefines ? ({ ...info.defines }) : info.defines;
|
||||
// init shader info
|
||||
if (programLib2) {
|
||||
CC_EXPECTS(_phaseID != INVALID_ID);
|
||||
_shaderInfo = &programLib2->getProgramInfo(_phaseID, _programName);
|
||||
} else {
|
||||
_shaderInfo = programLib->getTemplate(info.program);
|
||||
}
|
||||
if (info.properties.has_value()) {
|
||||
_properties = info.properties.value();
|
||||
}
|
||||
|
||||
// init gfx
|
||||
gfx::Device *device = _device;
|
||||
Pass::fillPipelineInfo(this, info);
|
||||
if (info.stateOverrides.has_value()) {
|
||||
Pass::fillPipelineInfo(this, IPassInfoFull(info.stateOverrides.value()));
|
||||
}
|
||||
|
||||
// init descriptor set
|
||||
gfx::DescriptorSetInfo dsInfo;
|
||||
if (programLib2) {
|
||||
CC_EXPECTS(_phaseID != INVALID_ID);
|
||||
dsInfo.layout = &programLib2->getMaterialDescriptorSetLayout(
|
||||
_device, _phaseID, _programName);
|
||||
} else {
|
||||
dsInfo.layout = programLib->getDescriptorSetLayout(_device, info.program);
|
||||
}
|
||||
_descriptorSet = _device->createDescriptorSet(dsInfo);
|
||||
|
||||
// calculate total size required
|
||||
const auto &blocks = _shaderInfo->blocks;
|
||||
const auto *tmplInfo =
|
||||
programLib2
|
||||
? nullptr
|
||||
: programLib->getTemplateInfo(info.program);
|
||||
const auto &blockSizes = [&]() -> const auto & {
|
||||
if (programLib2) {
|
||||
return programLib2->getBlockSizes(_phaseID, _programName);
|
||||
}
|
||||
return tmplInfo->blockSizes;
|
||||
}
|
||||
();
|
||||
const auto &handleMap = [&]() -> const auto & {
|
||||
if (programLib2) {
|
||||
CC_EXPECTS(_phaseID != INVALID_ID);
|
||||
return programLib2->getHandleMap(_phaseID, _programName);
|
||||
}
|
||||
return tmplInfo->handleMap;
|
||||
}
|
||||
();
|
||||
|
||||
// build uniform blocks
|
||||
if (programLib2) {
|
||||
const auto &shaderInfo = programLib2->getShaderInfo(_phaseID, _programName);
|
||||
buildMaterialUniformBlocks(shaderInfo.blocks, blockSizes);
|
||||
} else {
|
||||
buildUniformBlocks(blocks, blockSizes);
|
||||
}
|
||||
|
||||
// store handles
|
||||
_propertyHandleMap = handleMap;
|
||||
auto &directHandleMap = _propertyHandleMap;
|
||||
ccstd::unordered_map<ccstd::string, uint32_t> indirectHandleMap;
|
||||
for (const auto &properties : _properties) {
|
||||
if (!properties.second.handleInfo.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &propVal = properties.second.handleInfo.value();
|
||||
indirectHandleMap[properties.first] = getHandle(std::get<0>(propVal), std::get<1>(propVal), std::get<2>(propVal));
|
||||
}
|
||||
|
||||
utils::mergeToMap(directHandleMap, indirectHandleMap);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void calculateTotalSize(
|
||||
gfx::Device *device, const uint32_t lastSize,
|
||||
IntrusivePtr<gfx::Buffer> &rootBuffer,
|
||||
IntrusivePtr<ArrayBuffer> &rootBlock,
|
||||
ccstd::vector<uint32_t> &startOffsets) {
|
||||
uint32_t totalSize = !startOffsets.empty() ? (startOffsets[startOffsets.size() - 1] + lastSize) : 0;
|
||||
if (totalSize > 0) {
|
||||
gfx::BufferInfo bufferInfo;
|
||||
bufferInfo.usage = gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST;
|
||||
bufferInfo.memUsage = gfx::MemoryUsageBit::DEVICE;
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=988988
|
||||
const auto alignment = device->getCapabilities().uboOffsetAlignment;
|
||||
bufferInfo.size = static_cast<int32_t>(std::ceil(static_cast<float>(totalSize) / static_cast<float>(alignment))) * alignment;
|
||||
rootBuffer = device->createBuffer(bufferInfo);
|
||||
rootBlock = ccnew ArrayBuffer(totalSize);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Pass::buildUniformBlock(
|
||||
uint32_t binding, int32_t size,
|
||||
gfx::BufferViewInfo &bufferViewInfo,
|
||||
ccstd::vector<uint32_t> &startOffsets,
|
||||
size_t &count) {
|
||||
const auto alignment = _device->getCapabilities().uboOffsetAlignment;
|
||||
bufferViewInfo.buffer = _rootBuffer;
|
||||
bufferViewInfo.offset = startOffsets[count++];
|
||||
bufferViewInfo.range = static_cast<int32_t>(std::ceil(static_cast<float>(size) / static_cast<float>(alignment))) * alignment;
|
||||
if (binding >= _buffers.size()) {
|
||||
_buffers.resize(binding + 1);
|
||||
}
|
||||
auto *bufferView = _device->createBuffer(bufferViewInfo);
|
||||
_buffers[binding] = bufferView;
|
||||
// non-builtin UBO data pools, note that the effect compiler
|
||||
// guarantees these bindings to be consecutive, starting from 0 and non-array-typed
|
||||
if (binding >= _blocks.size()) {
|
||||
_blocks.resize(binding + 1);
|
||||
}
|
||||
_blocks[binding].data = reinterpret_cast<float *>(const_cast<uint8_t *>(_rootBlock->getData()) + bufferViewInfo.offset);
|
||||
_blocks[binding].count = size / 4;
|
||||
_blocks[binding].offset = bufferViewInfo.offset / 4;
|
||||
_descriptorSet->bindBuffer(binding, bufferView);
|
||||
}
|
||||
|
||||
void Pass::buildMaterialUniformBlocks(
|
||||
const ccstd::vector<gfx::UniformBlock> &blocks,
|
||||
const ccstd::vector<int32_t> &blockSizes) {
|
||||
gfx::Device *device = _device;
|
||||
const auto alignment = device->getCapabilities().uboOffsetAlignment;
|
||||
ccstd::vector<uint32_t> startOffsets;
|
||||
startOffsets.reserve(blocks.size());
|
||||
uint32_t lastSize = 0;
|
||||
uint32_t lastOffset = 0;
|
||||
for (size_t i = 0; i < blocks.size(); i++) {
|
||||
const auto &block = blocks[i];
|
||||
if (static_cast<pipeline::SetIndex>(block.set) != pipeline::SetIndex::MATERIAL) {
|
||||
continue;
|
||||
}
|
||||
const auto &size = blockSizes[i];
|
||||
startOffsets.emplace_back(lastOffset);
|
||||
lastOffset += static_cast<int32_t>(std::ceil(static_cast<float>(size) / static_cast<float>(alignment))) * alignment;
|
||||
lastSize = size;
|
||||
}
|
||||
|
||||
// create gfx buffer resource
|
||||
if (lastSize != 0) {
|
||||
calculateTotalSize(device, lastSize, _rootBuffer, _rootBlock, startOffsets);
|
||||
}
|
||||
|
||||
// create buffer views
|
||||
gfx::BufferViewInfo bufferViewInfo{};
|
||||
for (size_t i = 0, count = 0; i < blocks.size(); i++) {
|
||||
const auto &block = blocks[i];
|
||||
if (static_cast<pipeline::SetIndex>(block.set) != pipeline::SetIndex::MATERIAL) {
|
||||
continue;
|
||||
}
|
||||
const auto binding = block.binding;
|
||||
int32_t size = blockSizes[i];
|
||||
buildUniformBlock(binding, size, bufferViewInfo, startOffsets, count);
|
||||
}
|
||||
}
|
||||
|
||||
void Pass::buildUniformBlocks(
|
||||
const ccstd::vector<IBlockInfo> &blocks,
|
||||
const ccstd::vector<int32_t> &blockSizes) {
|
||||
gfx::Device *device = _device;
|
||||
const auto alignment = device->getCapabilities().uboOffsetAlignment;
|
||||
ccstd::vector<uint32_t> startOffsets;
|
||||
startOffsets.reserve(blocks.size());
|
||||
uint32_t lastSize = 0;
|
||||
uint32_t lastOffset = 0;
|
||||
for (size_t i = 0; i < blocks.size(); i++) {
|
||||
const auto &size = blockSizes[i];
|
||||
startOffsets.emplace_back(lastOffset);
|
||||
lastOffset += static_cast<int32_t>(std::ceil(static_cast<float>(size) / static_cast<float>(alignment))) * alignment;
|
||||
lastSize = size;
|
||||
}
|
||||
|
||||
// create gfx buffer resource
|
||||
calculateTotalSize(device, lastSize, _rootBuffer, _rootBlock, startOffsets);
|
||||
|
||||
// create buffer views
|
||||
gfx::BufferViewInfo bufferViewInfo;
|
||||
for (size_t i = 0, count = 0; i < blocks.size(); i++) {
|
||||
const auto binding = blocks[i].binding;
|
||||
int32_t size = blockSizes[i];
|
||||
buildUniformBlock(binding, size, bufferViewInfo, startOffsets, count);
|
||||
}
|
||||
}
|
||||
|
||||
void Pass::syncBatchingScheme() {
|
||||
auto iter = _defines.find("USE_INSTANCING");
|
||||
if (iter != _defines.end()) {
|
||||
if (_device->hasFeature(gfx::Feature::INSTANCED_ARRAYS) && macroRecordAsBool(iter->second)) {
|
||||
_batchingScheme = BatchingSchemes::INSTANCING;
|
||||
} else {
|
||||
iter->second = false;
|
||||
_batchingScheme = BatchingSchemes::NONE;
|
||||
}
|
||||
} else {
|
||||
_batchingScheme = BatchingSchemes::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void Pass::initPassFromTarget(Pass *target, const gfx::DepthStencilState &dss, ccstd::hash_t hashFactor) {
|
||||
_priority = target->_priority;
|
||||
_stage = target->_stage;
|
||||
_phase = target->_phase;
|
||||
_passID = target->_passID;
|
||||
_subpassID = target->_subpassID;
|
||||
_phaseID = target->_phaseID;
|
||||
_batchingScheme = target->_batchingScheme;
|
||||
_primitive = target->_primitive;
|
||||
_dynamicStates = target->_dynamicStates;
|
||||
_blendState = *target->getBlendState();
|
||||
_depthStencilState = dss;
|
||||
_descriptorSet = target->_descriptorSet;
|
||||
_rs = *target->getRasterizerState();
|
||||
_passIndex = target->_passIndex;
|
||||
_propertyIndex = target->_propertyIndex;
|
||||
_programName = target->getProgram();
|
||||
_defines = target->_defines;
|
||||
_shaderInfo = target->_shaderInfo; // cjh how to release?
|
||||
_properties = target->_properties;
|
||||
|
||||
_blocks = target->_blocks;
|
||||
_dynamics = target->_dynamics;
|
||||
|
||||
_shader = target->_shader;
|
||||
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
_pipelineLayout = programLib->getPipelineLayout(_device, _phaseID, _programName);
|
||||
} else {
|
||||
_pipelineLayout = ProgramLib::getInstance()->getTemplateInfo(_programName)->pipelineLayout;
|
||||
}
|
||||
_hash = target->_hash ^ hashFactor;
|
||||
}
|
||||
|
||||
void Pass::updatePassHash() {
|
||||
_hash = Pass::getPassHash(this);
|
||||
}
|
||||
|
||||
const gfx::DescriptorSetLayout *Pass::getLocalSetLayout() const {
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
return &programLib->getLocalDescriptorSetLayout(_device, _phaseID, _programName);
|
||||
}
|
||||
return ProgramLib::getInstance()->getDescriptorSetLayout(_device, _programName, true);
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
369
cocos/scene/Pass.h
Normal file
369
cocos/scene/Pass.h
Normal file
@@ -0,0 +1,369 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "core/ArrayBuffer.h"
|
||||
#include "core/TypedArray.h"
|
||||
#include "core/assets/EffectAsset.h"
|
||||
#include "renderer/core/PassUtils.h"
|
||||
#include "renderer/gfx-base/GFXBuffer.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "renderer/gfx-base/GFXDescriptorSet.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Root;
|
||||
struct IProgramInfo;
|
||||
namespace pipeline {
|
||||
class InstancedBuffer;
|
||||
} // namespace pipeline
|
||||
namespace scene {
|
||||
struct IMacroPatch;
|
||||
|
||||
struct PassDynamicsValue {
|
||||
bool dirty{false};
|
||||
float value{0.F};
|
||||
};
|
||||
using IPassDynamics = ccstd::unordered_map<uint32_t, PassDynamicsValue>;
|
||||
|
||||
enum class BatchingSchemes {
|
||||
NONE = 0,
|
||||
INSTANCING = 1,
|
||||
};
|
||||
|
||||
struct IBlockRef {
|
||||
float *data{nullptr};
|
||||
size_t count{0};
|
||||
size_t offset{0};
|
||||
};
|
||||
|
||||
class Pass : public RefCounted {
|
||||
public:
|
||||
/**
|
||||
* @en Get the type of member in uniform buffer object with the handle
|
||||
* @zh 根据 handle 获取 uniform 的具体类型。
|
||||
*/
|
||||
static gfx::Type getTypeFromHandle(uint32_t handle) {
|
||||
return cc::getTypeFromHandle(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get the binding with handle
|
||||
* @zh 根据 handle 获取 binding。
|
||||
*/
|
||||
static uint32_t getBindingFromHandle(uint32_t handle) {
|
||||
return cc::getBindingFromHandle(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get the array length with handle
|
||||
* @zh 根据 handle 获取数组长度。
|
||||
*/
|
||||
static uint32_t getCountFromHandle(uint32_t handle) {
|
||||
return cc::getCountFromHandle(handle);
|
||||
}
|
||||
|
||||
static uint32_t getOffsetFromHandle(uint32_t handle) {
|
||||
return cc::getOffsetFromHandle(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Fill a pass represented by the given pass handle with the given override info
|
||||
* @param pass The pass handle point to the pass
|
||||
* @param info The pass override info
|
||||
*/
|
||||
static void fillPipelineInfo(Pass *pass, const IPassInfoFull &info);
|
||||
|
||||
/**
|
||||
* @en Get pass hash value by [[Pass]] hash information.
|
||||
* @zh 根据 [[Pass]] 的哈希信息获取哈希值。
|
||||
*
|
||||
* @param pass Handle of the pass info used to compute hash value.
|
||||
*/
|
||||
static ccstd::hash_t getPassHash(Pass *pass);
|
||||
|
||||
Pass();
|
||||
explicit Pass(Root *root);
|
||||
~Pass() override;
|
||||
|
||||
/**
|
||||
* @en Initialize the pass with given pass info, shader will be compiled in the init process
|
||||
* @zh 根据指定参数初始化当前 pass,shader 会在这一阶段就尝试编译。
|
||||
*/
|
||||
void initialize(const IPassInfoFull &info);
|
||||
|
||||
/**
|
||||
* @en Get the handle of a UBO member, or specific channels of it.
|
||||
* @zh 获取指定 UBO 成员,或其更具体分量的读写句柄。默认以成员自身的类型为目标读写类型(即读写时必须传入与成员类型相同的变量)。
|
||||
* @param name Name of the target UBO member.
|
||||
* @param offset Channel offset into the member.
|
||||
* @param targetType Target type of the handle, i.e. the type of data when read/write to it.
|
||||
* @example
|
||||
* ```
|
||||
* import { Vec3, gfx } from 'cc';
|
||||
* // say 'pbrParams' is a uniform vec4
|
||||
* const hParams = pass.getHandle('pbrParams'); // get the default handle
|
||||
* pass.setUniform(hAlbedo, new Vec3(1, 0, 0)); // wrong! pbrParams.w is NaN now
|
||||
*
|
||||
* // say 'albedoScale' is a uniform vec4, and we only want to modify the w component in the form of a single float
|
||||
* const hThreshold = pass.getHandle('albedoScale', 3, gfx.Type.FLOAT);
|
||||
* pass.setUniform(hThreshold, 0.5); // now, albedoScale.w = 0.5
|
||||
* ```
|
||||
*/
|
||||
uint32_t getHandle(const ccstd::string &name, uint32_t offset = 0, gfx::Type targetType = gfx::Type::UNKNOWN) const;
|
||||
|
||||
/**
|
||||
* @en Gets the uniform binding with its name
|
||||
* @zh 获取指定 uniform 的 binding。
|
||||
* @param name The name of target uniform
|
||||
*/
|
||||
uint32_t getBinding(const ccstd::string &name) const;
|
||||
|
||||
/**
|
||||
* @en Sets a vector type uniform value, if a uniform requires frequent update, please use this method.
|
||||
* @zh 设置指定普通向量类 uniform 的值,如果需要频繁更新请尽量使用此接口。
|
||||
* @param handle The handle for the target uniform
|
||||
* @param value New value
|
||||
*/
|
||||
void setUniform(uint32_t handle, const MaterialProperty &value);
|
||||
|
||||
/**
|
||||
* @en Gets a uniform's value.
|
||||
* @zh 获取指定普通向量类 uniform 的值。
|
||||
* @param handle The handle for the target uniform
|
||||
*/
|
||||
MaterialProperty getUniform(uint32_t handle) const;
|
||||
|
||||
/**
|
||||
* @en Sets an array type uniform value, if a uniform requires frequent update, please use this method.
|
||||
* @zh 设置指定数组类 uniform 的值,如果需要频繁更新请尽量使用此接口。
|
||||
* @param handle The handle for the target uniform
|
||||
* @param value New value
|
||||
*/
|
||||
void setUniformArray(uint32_t handle, const MaterialPropertyList &value);
|
||||
|
||||
/**
|
||||
* @en Bind a GFX [[Texture]] the the given uniform binding
|
||||
* @zh 绑定实际 GFX [[Texture]] 到指定 binding。
|
||||
* @param binding The binding for target uniform of texture type
|
||||
* @param value Target texture
|
||||
*/
|
||||
void bindTexture(uint32_t binding, gfx::Texture *value, uint32_t index = 0);
|
||||
|
||||
/**
|
||||
* @en Bind a GFX [[Sampler]] the the given uniform binding
|
||||
* @zh 绑定实际 GFX [[Sampler]] 到指定 binding。
|
||||
* @param binding The binding for target uniform of sampler type
|
||||
* @param value Target sampler
|
||||
*/
|
||||
void bindSampler(uint32_t binding, gfx::Sampler *value, uint32_t index = 0);
|
||||
|
||||
/**
|
||||
* @en Sets the dynamic pipeline state property at runtime
|
||||
* @zh 设置运行时 pass 内可动态更新的管线状态属性。
|
||||
* @param state Target dynamic state
|
||||
* @param value Target value
|
||||
*/
|
||||
void setDynamicState(gfx::DynamicStateFlagBit state, float value);
|
||||
|
||||
/**
|
||||
* @en Override all pipeline states with the given pass override info.
|
||||
* @zh 重载当前所有管线状态。
|
||||
* @param original The original pass info
|
||||
* @param value The override pipeline state info
|
||||
*/
|
||||
virtual void overridePipelineStates(const IPassInfo &original, const PassOverrides &overrides);
|
||||
|
||||
void update();
|
||||
|
||||
pipeline::InstancedBuffer *getInstancedBuffer(int32_t extraKey = 0);
|
||||
|
||||
/**
|
||||
* @en Destroy the current pass.
|
||||
* @zh 销毁当前 pass。
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @en Resets the value of the given uniform by name to the default value in [[EffectAsset]].
|
||||
* This method does not support array type uniform.
|
||||
* @zh 重置指定(非数组) Uniform 为 [[EffectAsset]] 默认值。
|
||||
*/
|
||||
void resetUniform(const ccstd::string &name);
|
||||
|
||||
void resetTexture(const ccstd::string &name);
|
||||
|
||||
/**
|
||||
* @en Resets the value of the given texture by name to the default value in [[EffectAsset]].
|
||||
* @zh 重置指定贴图为 [[EffectAsset]] 默认值。
|
||||
*/
|
||||
void resetTexture(const ccstd::string &name, uint32_t index);
|
||||
|
||||
/**
|
||||
* @en Resets all uniform buffer objects to the default values in [[EffectAsset]]
|
||||
* @zh 重置所有 UBO 为默认值。
|
||||
*/
|
||||
void resetUBOs();
|
||||
|
||||
/**
|
||||
* @en Resets all textures and samplers to the default values in [[EffectAsset]]
|
||||
* @zh 重置所有 texture 和 sampler 为初始默认值。
|
||||
*/
|
||||
void resetTextures();
|
||||
|
||||
/**
|
||||
* @en Try to compile the shader and retrieve related resources references.
|
||||
* @zh 尝试编译 shader 并获取相关资源引用。
|
||||
*/
|
||||
virtual bool tryCompile();
|
||||
virtual bool tryCompile(const ccstd::optional<MacroRecord> & /*defineOverrides*/) { return Pass::tryCompile(); }
|
||||
|
||||
/**
|
||||
* @en Gets the shader variant of the current pass and given macro patches
|
||||
* @zh 结合指定的编译宏组合获取当前 Pass 的 Shader Variant
|
||||
* @param patches The macro patches
|
||||
*/
|
||||
gfx::Shader *getShaderVariant();
|
||||
gfx::Shader *getShaderVariant(const ccstd::vector<IMacroPatch> &patches);
|
||||
|
||||
IPassInfoFull getPassInfoFull() const;
|
||||
|
||||
// infos
|
||||
inline Root *getRoot() const { return _root; }
|
||||
inline gfx::Device *getDevice() const { return _device; }
|
||||
inline const IProgramInfo *getShaderInfo() const { return _shaderInfo; }
|
||||
const gfx::DescriptorSetLayout *getLocalSetLayout() const;
|
||||
inline const ccstd::string &getProgram() const { return _programName; }
|
||||
inline const PassPropertyInfoMap &getProperties() const { return _properties; }
|
||||
inline const MacroRecord &getDefines() const { return _defines; }
|
||||
inline MacroRecord &getDefines() { return _defines; }
|
||||
inline index_t getPassIndex() const { return _passIndex; }
|
||||
inline index_t getPropertyIndex() const { return _propertyIndex; }
|
||||
// data
|
||||
inline const IPassDynamics &getDynamics() const { return _dynamics; }
|
||||
inline const ccstd::vector<IBlockRef> &getBlocks() const { return _blocks; }
|
||||
inline ArrayBuffer *getRootBlock() { return _rootBlock; }
|
||||
inline bool isRootBufferDirty() const { return _rootBufferDirty; }
|
||||
inline void setRootBufferDirty(bool val) { _rootBufferDirty = val; }
|
||||
// states
|
||||
inline pipeline::RenderPriority getPriority() const { return _priority; }
|
||||
// It is added for internal use by the engine.
|
||||
inline void setPriority(pipeline::RenderPriority priority) { _priority = priority; }
|
||||
inline gfx::PrimitiveMode getPrimitive() const { return _primitive; }
|
||||
inline pipeline::RenderPassStage getStage() const { return _stage; }
|
||||
inline uint32_t getPhase() const { return _phase; }
|
||||
inline uint32_t getPassID() const { return _passID; }
|
||||
inline uint32_t getSubpassOrPassID() const { return _subpassID == 0xFFFFFFFF ? _passID : _subpassID; }
|
||||
inline uint32_t getPhaseID() const { return _phaseID; }
|
||||
inline const gfx::RasterizerState *getRasterizerState() const { return &_rs; }
|
||||
inline const gfx::DepthStencilState *getDepthStencilState() const { return &_depthStencilState; }
|
||||
inline const gfx::BlendState *getBlendState() const { return &_blendState; }
|
||||
inline gfx::DynamicStateFlagBit getDynamicStates() const { return _dynamicStates; }
|
||||
inline BatchingSchemes getBatchingScheme() const { return _batchingScheme; }
|
||||
inline gfx::DescriptorSet *getDescriptorSet() const { return _descriptorSet; }
|
||||
inline ccstd::hash_t getHash() const { return _hash; }
|
||||
inline gfx::PipelineLayout *getPipelineLayout() const { return _pipelineLayout; }
|
||||
|
||||
// Only for UI
|
||||
void initPassFromTarget(Pass *target, const gfx::DepthStencilState &dss, ccstd::hash_t hashFactor);
|
||||
void updatePassHash();
|
||||
|
||||
// internal use
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
virtual void beginChangeStatesSilently() {}
|
||||
virtual void endChangeStatesSilently() {}
|
||||
|
||||
private:
|
||||
void buildUniformBlocks(
|
||||
const ccstd::vector<IBlockInfo> &blocks,
|
||||
const ccstd::vector<int32_t> &blockSizes);
|
||||
void buildMaterialUniformBlocks(
|
||||
const ccstd::vector<gfx::UniformBlock> &blocks,
|
||||
const ccstd::vector<int32_t> &blockSizes);
|
||||
void buildUniformBlock(
|
||||
uint32_t binding, int32_t size,
|
||||
gfx::BufferViewInfo &bufferViewInfo,
|
||||
ccstd::vector<uint32_t> &startOffsets,
|
||||
size_t &count);
|
||||
bool isBlend();
|
||||
|
||||
protected:
|
||||
void setState(const gfx::BlendState &bs, const gfx::DepthStencilState &dss, const gfx::RasterizerState &rs, gfx::DescriptorSet *ds);
|
||||
void doInit(const IPassInfoFull &info, bool copyDefines = false);
|
||||
virtual void syncBatchingScheme();
|
||||
|
||||
// internal resources
|
||||
IntrusivePtr<gfx::Buffer> _rootBuffer;
|
||||
ccstd::vector<IntrusivePtr<gfx::Buffer>> _buffers;
|
||||
IntrusivePtr<gfx::DescriptorSet> _descriptorSet;
|
||||
IntrusivePtr<gfx::PipelineLayout> _pipelineLayout;
|
||||
// internal data
|
||||
index_t _passIndex{0};
|
||||
index_t _propertyIndex{0};
|
||||
ccstd::string _programName;
|
||||
IPassDynamics _dynamics;
|
||||
ccstd::unordered_map<ccstd::string, uint32_t> _propertyHandleMap;
|
||||
IntrusivePtr<ArrayBuffer> _rootBlock;
|
||||
ccstd::vector<IBlockRef> _blocks; // Point to position in _rootBlock
|
||||
|
||||
const IProgramInfo *_shaderInfo; // weakref to template of ProgramLib
|
||||
MacroRecord _defines;
|
||||
PassPropertyInfoMap _properties;
|
||||
IntrusivePtr<gfx::Shader> _shader;
|
||||
gfx::BlendState _blendState{};
|
||||
gfx::DepthStencilState _depthStencilState{};
|
||||
gfx::RasterizerState _rs{};
|
||||
pipeline::RenderPriority _priority{pipeline::RenderPriority::DEFAULT};
|
||||
pipeline::RenderPassStage _stage{pipeline::RenderPassStage::DEFAULT};
|
||||
uint32_t _phase{0};
|
||||
uint32_t _passID{0xFFFFFFFF};
|
||||
uint32_t _subpassID{0xFFFFFFFF};
|
||||
uint32_t _phaseID{0xFFFFFFFF};
|
||||
ccstd::string _phaseString;
|
||||
gfx::PrimitiveMode _primitive{gfx::PrimitiveMode::TRIANGLE_LIST};
|
||||
BatchingSchemes _batchingScheme{BatchingSchemes::NONE};
|
||||
gfx::DynamicStateFlagBit _dynamicStates{gfx::DynamicStateFlagBit::NONE};
|
||||
ccstd::unordered_map<int32_t, IntrusivePtr<pipeline::InstancedBuffer>> _instancedBuffers;
|
||||
|
||||
ccstd::hash_t _hash{0U};
|
||||
// external references
|
||||
Root *_root{nullptr};
|
||||
gfx::Device *_device{nullptr};
|
||||
|
||||
bool _rootBufferDirty{false};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Pass);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
71
cocos/scene/PointLight.cpp
Normal file
71
cocos/scene/PointLight.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/PointLight.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
PointLight::PointLight() {
|
||||
_type = LightType::POINT;
|
||||
}
|
||||
|
||||
void PointLight::initialize() {
|
||||
Light::initialize();
|
||||
|
||||
_range = 1.0F;
|
||||
setLuminance(1700 / Light::nt2lm(1.0F));
|
||||
_luminanceLDR = 1.0F;
|
||||
}
|
||||
|
||||
void PointLight::update() {
|
||||
if (_node && (_node->getChangedFlags() || _needUpdate)) {
|
||||
_node->updateWorldTransform();
|
||||
_pos = _node->getWorldPosition();
|
||||
_aabb.set(_pos, {_range, _range, _range});
|
||||
_needUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
float PointLight::getLuminance() const {
|
||||
auto *sceneData = Root::getInstance()->getPipeline()->getPipelineSceneData();
|
||||
const auto isHDR = sceneData->isHDR();
|
||||
return isHDR ? _luminanceHDR : _luminanceLDR;
|
||||
}
|
||||
|
||||
void PointLight::setLuminance(float value) {
|
||||
auto *sceneData = Root::getInstance()->getPipeline()->getPipelineSceneData();
|
||||
const auto isHDR = sceneData->isHDR();
|
||||
if (isHDR) {
|
||||
_luminanceHDR = value;
|
||||
} else {
|
||||
_luminanceLDR = value;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
77
cocos/scene/PointLight.h
Normal file
77
cocos/scene/PointLight.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/geometry/AABB.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "scene/Light.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class PointLight final : public Light {
|
||||
public:
|
||||
PointLight();
|
||||
~PointLight() override = default;
|
||||
|
||||
void initialize() override;
|
||||
void update() override;
|
||||
|
||||
inline const Vec3 &getPosition() const { return _pos; }
|
||||
inline void setPosition(const Vec3 &pos) { _pos = pos; }
|
||||
|
||||
inline float getRange() const { return _range; }
|
||||
inline void setRange(float range) {
|
||||
_range = range;
|
||||
_needUpdate = true;
|
||||
}
|
||||
|
||||
float getLuminance() const;
|
||||
void setLuminance(float);
|
||||
|
||||
inline void setLuminanceHDR(float illum) { _luminanceHDR = illum; }
|
||||
inline float getLuminanceHDR() const { return _luminanceHDR; }
|
||||
|
||||
inline void setLuminanceLDR(float illum) { _luminanceLDR = illum; }
|
||||
inline float getLuminanceLDR() const { return _luminanceLDR; }
|
||||
|
||||
inline const geometry::AABB &getAABB() const { return _aabb; }
|
||||
|
||||
private:
|
||||
bool _needUpdate{false};
|
||||
|
||||
float _luminanceHDR{0.F};
|
||||
float _luminanceLDR{0.F};
|
||||
float _range{0.F};
|
||||
|
||||
Vec3 _pos;
|
||||
|
||||
geometry::AABB _aabb;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(PointLight);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
75
cocos/scene/PostSettings.cpp
Normal file
75
cocos/scene/PostSettings.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/PostSettings.h"
|
||||
#include "core/Root.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
void PostSettingsInfo::activate(PostSettings *resource) {
|
||||
_resource = resource;
|
||||
if (_resource != nullptr) {
|
||||
_resource->initialize(*this);
|
||||
_resource->activate();
|
||||
}
|
||||
}
|
||||
void PostSettingsInfo::setToneMappingType(ToneMappingType toneMappingType) {
|
||||
_toneMappingType = toneMappingType;
|
||||
|
||||
if (_resource != nullptr) {
|
||||
_resource->setToneMappingType(toneMappingType);
|
||||
}
|
||||
}
|
||||
|
||||
void PostSettings::activate() {
|
||||
_activated = true;
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
void PostSettings::initialize(const PostSettingsInfo &postSettingsInfo) {
|
||||
_activated = false;
|
||||
_toneMappingType = postSettingsInfo.getToneMappingType();
|
||||
}
|
||||
|
||||
void PostSettings::setToneMappingType(ToneMappingType toneMappingType) {
|
||||
_toneMappingType = toneMappingType;
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
void PostSettings::updatePipeline() const {
|
||||
|
||||
Root *root = Root::getInstance();
|
||||
auto *pipeline = root->getPipeline();
|
||||
|
||||
pipeline->setValue("CC_TONE_MAPPING_TYPE", static_cast<int32_t>(_toneMappingType));
|
||||
|
||||
if (_activated)
|
||||
{
|
||||
root->onGlobalPipelineStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
67
cocos/scene/PostSettings.h
Normal file
67
cocos/scene/PostSettings.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/RefCounted.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
enum class ToneMappingType {
|
||||
DEFAULT = 0,
|
||||
LINEAR = 1,
|
||||
};
|
||||
|
||||
class PostSettings;
|
||||
class PostSettingsInfo : public RefCounted {
|
||||
public:
|
||||
PostSettingsInfo() = default;
|
||||
~PostSettingsInfo() override = default;
|
||||
|
||||
inline ToneMappingType getToneMappingType() const { return _toneMappingType; }
|
||||
void setToneMappingType(ToneMappingType toneMappingType);
|
||||
|
||||
void activate(PostSettings *resource);
|
||||
PostSettings *_resource{nullptr};
|
||||
ToneMappingType _toneMappingType{ ToneMappingType::DEFAULT };
|
||||
};
|
||||
|
||||
class PostSettings final {
|
||||
public:
|
||||
PostSettings() = default;
|
||||
~PostSettings() = default;
|
||||
void activate();
|
||||
|
||||
void initialize(const PostSettingsInfo &postSettingsInfo);
|
||||
inline ToneMappingType getToneMappingType() const { return _toneMappingType; }
|
||||
void setToneMappingType(ToneMappingType toneMappingType);
|
||||
private:
|
||||
void updatePipeline() const;
|
||||
bool _activated{ false };
|
||||
ToneMappingType _toneMappingType{ ToneMappingType::DEFAULT };
|
||||
};
|
||||
|
||||
|
||||
}// namespace scene
|
||||
} // namespace cc
|
||||
70
cocos/scene/RangedDirectionalLight.cpp
Normal file
70
cocos/scene/RangedDirectionalLight.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
http://www.cocos.com
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/RangedDirectionalLight.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
RangedDirectionalLight::RangedDirectionalLight() { _type = LightType::RANGED_DIRECTIONAL; }
|
||||
|
||||
RangedDirectionalLight::~RangedDirectionalLight() = default;
|
||||
|
||||
void RangedDirectionalLight::initialize() {
|
||||
Light::initialize();
|
||||
|
||||
setIlluminance(Ambient::SUN_ILLUM);
|
||||
}
|
||||
|
||||
void RangedDirectionalLight::update() {
|
||||
if (_node && (_node->getChangedFlags())) {
|
||||
_pos = _node->getWorldPosition();
|
||||
_dir.set(0.0F, 0.0F, -1.0F);
|
||||
_dir.transformQuat(_node->getWorldRotation());
|
||||
_right.set(1.0F, 0.0F, 0.0F);
|
||||
_right.transformQuat(_node->getWorldRotation());
|
||||
_scale = _node->getWorldScale();
|
||||
}
|
||||
}
|
||||
|
||||
float RangedDirectionalLight::getIlluminance() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
return _illuminanceHDR;
|
||||
}
|
||||
return _illuminanceLDR;
|
||||
}
|
||||
|
||||
void RangedDirectionalLight::setIlluminance(float value) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_illuminanceHDR = value;
|
||||
} else {
|
||||
_illuminanceLDR = value;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
63
cocos/scene/RangedDirectionalLight.h
Normal file
63
cocos/scene/RangedDirectionalLight.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
http://www.cocos.com
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "math/Vec3.h"
|
||||
#include "scene/Ambient.h"
|
||||
#include "scene/Light.h"
|
||||
#include "scene/Shadow.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class RangedDirectionalLight final : public Light {
|
||||
public:
|
||||
RangedDirectionalLight();
|
||||
~RangedDirectionalLight() override;
|
||||
|
||||
void initialize() override;
|
||||
void update() override;
|
||||
|
||||
inline const Vec3 &getDirection() const { return _dir; }
|
||||
inline const Vec3 &getPosition() const { return _pos; }
|
||||
inline const Vec3 &getScale() const { return _scale; }
|
||||
inline const Vec3 &getRight() const { return _right; }
|
||||
inline void setIlluminanceHDR(float value) { _illuminanceHDR = value; }
|
||||
inline void setIlluminanceLDR(float value) { _illuminanceLDR = value; }
|
||||
inline float getIlluminanceHDR() const { return _illuminanceHDR; }
|
||||
inline float getIlluminanceLDR() const { return _illuminanceLDR; }
|
||||
float getIlluminance() const;
|
||||
void setIlluminance(float value);
|
||||
|
||||
private:
|
||||
float _illuminanceHDR{Ambient::SUN_ILLUM};
|
||||
float _illuminanceLDR{1.F};
|
||||
Vec3 _dir{0.0F, 0.0F, -1.0F};
|
||||
Vec3 _pos{0.0F, 0.0F, 0.0F};
|
||||
Vec3 _scale{1.0F, 1.0F, 1.0F};
|
||||
Vec3 _right{1.0F, 0.0F, 0.0F};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(RangedDirectionalLight);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
307
cocos/scene/ReflectionProbe.cpp
Normal file
307
cocos/scene/ReflectionProbe.cpp
Normal file
@@ -0,0 +1,307 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/ReflectionProbe.h"
|
||||
#include "Define.h"
|
||||
#include "core/scene-graph/Scene.h"
|
||||
#include "math/Quaternion.h"
|
||||
#include "scene/ReflectionProbeManager.h"
|
||||
#include "core/scene-graph/SceneGlobals.h"
|
||||
#include "scene/Skybox.h"
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
// right left up down front back
|
||||
const std::array<Vec3, 6> CAMERA_DIR{
|
||||
Vec3(0, -90, 0),
|
||||
Vec3(0, 90, 0),
|
||||
Vec3(90, 0, 0),
|
||||
Vec3(-90, 0, 0),
|
||||
Vec3(0, 0, 0),
|
||||
Vec3(0, 180, 0)};
|
||||
ReflectionProbe::ReflectionProbe(int32_t id) {
|
||||
_probeId = id;
|
||||
}
|
||||
|
||||
void ReflectionProbe::setResolution(int32_t resolution) {
|
||||
if (_resolution != resolution) {
|
||||
for (const auto& rt : _bakedCubeTextures) {
|
||||
rt->resize(resolution, resolution);
|
||||
}
|
||||
_resolution = resolution;
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbe::initialize(Node* probeNode, Node* cameraNode) {
|
||||
_node = probeNode;
|
||||
_cameraNode = cameraNode;
|
||||
const Vec3 pos = probeNode->getWorldPosition();
|
||||
_boundingBox = geometry::AABB::create(pos.x, pos.y, pos.z, _size.x, _size.y, _size.z);
|
||||
|
||||
if (!_camera) {
|
||||
_camera = Root::getInstance()->createCamera();
|
||||
scene::ICameraInfo info;
|
||||
info.name = cameraNode->getName();
|
||||
info.node = cameraNode;
|
||||
info.projection = CameraProjection::PERSPECTIVE;
|
||||
info.window = Root::getInstance()->getTempWindow();
|
||||
info.priority = 0;
|
||||
info.cameraType = CameraType::DEFAULT;
|
||||
info.trackingType = TrackingType::NO_TRACKING;
|
||||
_camera->initialize(info);
|
||||
}
|
||||
_camera->setViewportInOrientedSpace(Rect(0, 0, 1, 1));
|
||||
_camera->setFovAxis(CameraFOVAxis::VERTICAL);
|
||||
_camera->setFov(static_cast<float>(mathutils::toRadian(90.0)));
|
||||
_camera->setOrthoHeight(10.0);
|
||||
|
||||
_camera->setNearClip(1.0);
|
||||
_camera->setFarClip(1000.0);
|
||||
_camera->setClearColor(_backgroundColor);
|
||||
_camera->setClearDepth(1.0);
|
||||
_camera->setClearStencil(0.0);
|
||||
_camera->setClearFlag(_clearFlag);
|
||||
_camera->setVisibility(_visibility);
|
||||
_camera->setAperture(CameraAperture::F16_0);
|
||||
_camera->setShutter(CameraShutter::D125);
|
||||
_camera->setIso(CameraISO::ISO100);
|
||||
|
||||
RenderWindow* win = Root::getInstance()->getMainWindow();
|
||||
_realtimePlanarTexture = ccnew RenderTexture();
|
||||
IRenderTextureCreateInfo info;
|
||||
info.name = "realtimePlanarTexture";
|
||||
info.height = win->getHeight();
|
||||
info.width = win->getWidth();
|
||||
_realtimePlanarTexture->initialize(info);
|
||||
}
|
||||
|
||||
void ReflectionProbe::syncCameraParams(const Camera* camera) {
|
||||
_camera->setProjectionType(camera->getProjectionType());
|
||||
_camera->setOrthoHeight(camera->getOrthoHeight());
|
||||
_camera->setNearClip(camera->getNearClip());
|
||||
_camera->setFarClip(camera->getFarClip());
|
||||
_camera->setFov(camera->getFov());
|
||||
_camera->setClearFlag(camera->getClearFlag());
|
||||
_camera->setClearColor(camera->getClearColor());
|
||||
_camera->setPriority(camera->getPriority() - 1);
|
||||
_camera->changeTargetWindow(_realtimePlanarTexture->getWindow());
|
||||
_camera->resize(camera->getWidth(), camera->getHeight());
|
||||
}
|
||||
|
||||
void ReflectionProbe::renderPlanarReflection(const Camera* sourceCamera) {
|
||||
if (!sourceCamera) return;
|
||||
syncCameraParams(sourceCamera);
|
||||
transformReflectionCamera(sourceCamera);
|
||||
packBackgroundColor();
|
||||
_needRender = true;
|
||||
}
|
||||
|
||||
void ReflectionProbe::switchProbeType(int32_t type, const Camera* sourceCamera) {
|
||||
if (type == static_cast<uint32_t>(ProbeType::CUBE)) {
|
||||
_needRender = false;
|
||||
} else if (sourceCamera != nullptr) {
|
||||
renderPlanarReflection(sourceCamera);
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbe::transformReflectionCamera(const Camera* sourceCamera) {
|
||||
float offset = Vec3::dot(_node->getWorldPosition(), _node->getUp());
|
||||
_cameraWorldPos = reflect(sourceCamera->getNode()->getWorldPosition(), _node->getUp(), offset);
|
||||
_cameraNode->setWorldPosition(_cameraWorldPos);
|
||||
|
||||
_forward = Vec3::FORWARD;
|
||||
_forward.transformQuat(sourceCamera->getNode()->getWorldRotation());
|
||||
_forward = reflect(_forward, _node->getUp(), 0);
|
||||
_forward.normalize();
|
||||
_forward *= -1;
|
||||
|
||||
_up = Vec3::UNIT_Y;
|
||||
_up.transformQuat(sourceCamera->getNode()->getWorldRotation());
|
||||
_up = reflect(_up, _node->getUp(), 0);
|
||||
_up.normalize();
|
||||
|
||||
Quaternion::fromViewUp(_forward, _up, &_cameraWorldRotation);
|
||||
_cameraNode->setWorldRotation(_cameraWorldRotation);
|
||||
_camera->update(true);
|
||||
|
||||
// Transform the plane from world space to reflection camera space use the inverse transpose matrix
|
||||
Vec4 viewSpaceProbe{ _node->getUp().x, _node->getUp().y, _node->getUp().z, -Vec3::dot(_node->getUp(), _node->getWorldPosition())};
|
||||
Mat4 matView = _camera->getMatView();
|
||||
matView.inverse();
|
||||
matView.transpose();
|
||||
matView.transformVector(&viewSpaceProbe);
|
||||
_camera->calculateObliqueMat(viewSpaceProbe);
|
||||
}
|
||||
|
||||
Vec3 ReflectionProbe::reflect(const Vec3& point, const Vec3& normal, float offset) {
|
||||
Vec3 n = normal;
|
||||
n.normalize();
|
||||
float dist = Vec3::dot(n, point) - offset;
|
||||
n = n * 2.0 * dist;
|
||||
Vec3 mirrorPos = point;
|
||||
mirrorPos.subtract(n);
|
||||
return mirrorPos;
|
||||
}
|
||||
|
||||
void ReflectionProbe::updateBoundingBox() {
|
||||
if (_node) {
|
||||
auto pos = _node->getWorldPosition();
|
||||
_boundingBox = geometry::AABB::set(_boundingBox, pos.x, pos.y, pos.z, _size.x, _size.y, _size.z);
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbe::updatePlanarTexture(const scene::RenderScene* scene) {
|
||||
if (!scene) return;
|
||||
for (const auto& model : scene->getModels()) {
|
||||
// filter model by view visibility
|
||||
if (model->isEnabled() && model->getReflectionProbeType() == scene::UseReflectionProbeType::PLANAR_REFLECTION) {
|
||||
const auto visibility = _camera->getVisibility();
|
||||
const auto* const node = model->getNode();
|
||||
if ((model->getNode() && ((visibility & node->getLayer()) == node->getLayer())) ||
|
||||
(visibility & static_cast<uint32_t>(model->getVisFlags()))) {
|
||||
const auto* modelWorldBounds = model->getWorldBounds();
|
||||
if (!modelWorldBounds) {
|
||||
continue;
|
||||
}
|
||||
const auto* probeBoundingBox = getBoundingBox();
|
||||
if (modelWorldBounds->aabbAabb(*probeBoundingBox)) {
|
||||
model->updateReflectionProbePlanarMap(_realtimePlanarTexture->getGFXTexture());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbe::destroy() {
|
||||
_needRender = false;
|
||||
if (_camera) {
|
||||
_camera->destroy();
|
||||
_camera = nullptr;
|
||||
}
|
||||
if (_realtimePlanarTexture) {
|
||||
_realtimePlanarTexture->destroy();
|
||||
_realtimePlanarTexture = nullptr;
|
||||
}
|
||||
for (const auto& rt : _bakedCubeTextures) {
|
||||
rt->destroy();
|
||||
}
|
||||
_bakedCubeTextures.clear();
|
||||
}
|
||||
|
||||
void ReflectionProbe::enable() {
|
||||
scene::ReflectionProbeManager::getInstance()->registerProbe(this);
|
||||
}
|
||||
void ReflectionProbe::disable() {
|
||||
scene::ReflectionProbeManager::getInstance()->unRegisterProbe(this);
|
||||
}
|
||||
|
||||
void ReflectionProbe::initBakedTextures() {
|
||||
if (_bakedCubeTextures.empty()) {
|
||||
for (uint32_t i = 0; i < 6; i++) {
|
||||
auto* rt = ccnew RenderTexture();
|
||||
IRenderTextureCreateInfo info;
|
||||
info.name = "capture";
|
||||
info.height = _resolution;
|
||||
info.width = _resolution;
|
||||
rt->initialize(info);
|
||||
_bakedCubeTextures.emplace_back(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ReflectionProbe::resetCameraParams() {
|
||||
_camera->setProjectionType(CameraProjection::PERSPECTIVE);
|
||||
_camera->setOrthoHeight(10.F);
|
||||
_camera->setNearClip(1.F);
|
||||
_camera->setFarClip(1000.F);
|
||||
_camera->setFov(static_cast<float>(mathutils::toRadian(90.F)));
|
||||
_camera->setPriority(0);
|
||||
if (!_bakedCubeTextures.empty()) {
|
||||
_camera->changeTargetWindow(_bakedCubeTextures[0]->getWindow());
|
||||
}
|
||||
_camera->resize(_resolution, _resolution);
|
||||
_camera->setVisibility(_visibility);
|
||||
|
||||
_camera->setClearColor(_backgroundColor);
|
||||
_camera->setClearDepth(1.F);
|
||||
_camera->setClearStencil(0.F);
|
||||
_camera->setClearFlag(_clearFlag);
|
||||
|
||||
_camera->setAperture(CameraAperture::F16_0);
|
||||
_camera->setShutter(CameraShutter::D125);
|
||||
_camera->setIso(CameraISO::ISO100);
|
||||
|
||||
_cameraNode->setWorldPosition(_node->getWorldPosition());
|
||||
_cameraNode->setWorldRotation(_node->getWorldRotation());
|
||||
_camera->update(true);
|
||||
}
|
||||
void ReflectionProbe::captureCubemap() {
|
||||
initBakedTextures();
|
||||
resetCameraParams();
|
||||
packBackgroundColor();
|
||||
_needRender = true;
|
||||
}
|
||||
|
||||
void ReflectionProbe::updateCameraDir(int32_t faceIdx) {
|
||||
_cameraNode->setRotationFromEuler(CAMERA_DIR[faceIdx]);
|
||||
_camera->update(true);
|
||||
}
|
||||
|
||||
Vec2 ReflectionProbe::renderArea() const {
|
||||
if (_probeType == ProbeType::PLANAR) {
|
||||
return Vec2(_realtimePlanarTexture->getWidth(), _realtimePlanarTexture->getHeight());
|
||||
}
|
||||
return Vec2(_resolution, _resolution);
|
||||
}
|
||||
|
||||
void ReflectionProbe::packBackgroundColor() {
|
||||
Vec3 rgb{_camera->getClearColor().x, _camera->getClearColor().y, _camera->getClearColor().z};
|
||||
float maxComp = std::max(std::max(rgb.x, rgb.y), rgb.z);
|
||||
float e = 128.F;
|
||||
if (maxComp > 0.0001) {
|
||||
e = std::log(maxComp) / std::log(1.1F);
|
||||
e = std::ceil(e);
|
||||
e = std::clamp(e + 128.F, 0.F, 255.F);
|
||||
}
|
||||
float sc = 1.F / std::pow(1.1F, e - 128.F);
|
||||
Vec3 encode{std::clamp(rgb * sc, Vec3(0.F, 0.F, 0.F), Vec3(1.F, 1.F, 1.F))};
|
||||
encode *= 255.F;
|
||||
Vec3 fVec3{std::floor(encode.x), std::floor(encode.y), std::floor(encode.z)};
|
||||
Vec3 sub(encode - fVec3);
|
||||
Vec3 stepVec3 = sub < Vec3(0.5F, 0.5F, 0.5F) ? Vec3(0.5F, 0.5F, 0.5F) : sub;
|
||||
Vec3 encodeRounded(fVec3 + stepVec3);
|
||||
_camera->setClearColor(gfx::Color{encodeRounded.x / 255.F, encodeRounded.y / 255.F, encodeRounded.z / 255.F, e / 255.F});
|
||||
}
|
||||
|
||||
bool ReflectionProbe::isRGBE() const {
|
||||
if (_cubemap) {
|
||||
return _cubemap->isRGBE;
|
||||
}
|
||||
// no baking will reflect the skybox
|
||||
if (_node && _node->getScene() && _node->getScene()->getSceneGlobals()->getSkyboxInfo()->getEnvmap()) {
|
||||
return _node->getScene()->getSceneGlobals()->getSkyboxInfo()->getEnvmap()->isRGBE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
212
cocos/scene/ReflectionProbe.h
Normal file
212
cocos/scene/ReflectionProbe.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/assets/RenderTexture.h"
|
||||
#include "core/assets/TextureCube.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
#include "scene/Camera.h"
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
class ReflectionProbe final {
|
||||
public:
|
||||
explicit ReflectionProbe(int32_t id);
|
||||
~ReflectionProbe() = default;
|
||||
void initialize(Node* probeNode, Node* cameraNode);
|
||||
enum class ProbeType {
|
||||
CUBE = 0,
|
||||
PLANAR = 1,
|
||||
};
|
||||
/**
|
||||
* @en Set probe type,cube or planar.
|
||||
* @zh 设置探针类型,cube或者planar
|
||||
*/
|
||||
inline void setProbeType(ProbeType type) {
|
||||
_probeType = type;
|
||||
}
|
||||
inline ProbeType getProbeType() const { return _probeType; }
|
||||
inline int32_t getProbeId() const { return _probeId; }
|
||||
void setResolution(int32_t resolution);
|
||||
inline int32_t getResolution() const { return _resolution; }
|
||||
/**
|
||||
* @en Clearing flags of the camera, specifies which part of the framebuffer will be actually cleared every frame.
|
||||
* @zh 相机的缓冲清除标志位,指定帧缓冲的哪部分要每帧清除。
|
||||
*/
|
||||
inline void setClearFlag(gfx::ClearFlagBit value) {
|
||||
_clearFlag = value;
|
||||
_camera->setClearFlag(_clearFlag);
|
||||
}
|
||||
inline gfx::ClearFlagBit getClearFlag() const { return _clearFlag; }
|
||||
|
||||
/**
|
||||
* @en Clearing color of the camera.
|
||||
* @zh 相机的颜色缓冲默认值。
|
||||
*/
|
||||
inline void setBackgroundColor(gfx::Color& val) {
|
||||
_backgroundColor = val;
|
||||
_camera->setClearColor(val);
|
||||
}
|
||||
inline const gfx::Color& getBackgroundColor() const { return _backgroundColor; }
|
||||
|
||||
/**
|
||||
* @en Visibility mask, declaring a set of node layers that will be visible to this camera.
|
||||
* @zh 可见性掩码,声明在当前相机中可见的节点层级集合。
|
||||
*/
|
||||
inline void setVisibility(int32_t val) { _visibility = val; }
|
||||
inline int32_t getVisibility() const { return _visibility; }
|
||||
|
||||
/**
|
||||
* @en Gets or sets the size of the bouding box, in local space.
|
||||
* @zh 获取或设置包围盒的大小。
|
||||
*/
|
||||
inline void setBoudingSize(Vec3& value) {
|
||||
_size = value;
|
||||
const Vec3 pos = _node->getWorldPosition();
|
||||
geometry::AABB::set(_boundingBox, pos.x, pos.y, pos.z, _size.x, _size.y, _size.z);
|
||||
}
|
||||
inline const Vec3& getBoudingSize() const { return _size; }
|
||||
/**
|
||||
* @en The node of the probe.
|
||||
* @zh probe绑定的节点
|
||||
*/
|
||||
inline Node* getNode() { return _node; }
|
||||
inline const Camera* getCamera() const { return _camera; }
|
||||
inline bool needRender() const { return _needRender; }
|
||||
inline void setNeedRender(bool b) { _needRender = b; }
|
||||
inline const geometry::AABB* getBoundingBox() const { return _boundingBox; }
|
||||
|
||||
inline void setCameraNode(Node* val) { _cameraNode = val; }
|
||||
inline Node* getCameraNode() const { return _cameraNode; }
|
||||
|
||||
inline void setPreviewSphere(Node* val) { _previewSphere = val; }
|
||||
inline const Node* getPreviewSphere() const { return _previewSphere; }
|
||||
|
||||
inline void setPreviewPlane(Node* val) { _previewPlane = val; }
|
||||
inline const Node* getPreviewPlane() const { return _previewPlane; }
|
||||
|
||||
inline void setCubeMap(cc::TextureCube* cubeMap) { _cubemap = cubeMap; }
|
||||
inline const cc::TextureCube* getCubeMap() const { return _cubemap; }
|
||||
|
||||
inline RenderTexture* getRealtimePlanarTexture() const { return _realtimePlanarTexture; }
|
||||
void updateBoundingBox();
|
||||
void syncCameraParams(const Camera* camera);
|
||||
void transformReflectionCamera(const Camera* sourceCamera);
|
||||
void renderPlanarReflection(const Camera* camera);
|
||||
void switchProbeType(int32_t type, const Camera* sourceCamera);
|
||||
static Vec3 reflect(const Vec3& point, const Vec3& normal, float offset);
|
||||
|
||||
void updatePlanarTexture(const scene::RenderScene* scene);
|
||||
|
||||
void destroy();
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
inline bool validate() const { return _cubemap != nullptr; }
|
||||
|
||||
void initBakedTextures();
|
||||
void captureCubemap();
|
||||
|
||||
inline const ccstd::vector<IntrusivePtr<cc::RenderTexture>>& getBakedCubeTextures() const { return _bakedCubeTextures; }
|
||||
void resetCameraParams();
|
||||
void updateCameraDir(int32_t faceIdx);
|
||||
Vec2 renderArea() const;
|
||||
void packBackgroundColor();
|
||||
bool isRGBE() const;
|
||||
|
||||
private:
|
||||
ccstd::vector<IntrusivePtr<cc::RenderTexture>> _bakedCubeTextures;
|
||||
IntrusivePtr<cc::RenderTexture> _realtimePlanarTexture{nullptr};
|
||||
|
||||
int32_t _resolution = 256;
|
||||
gfx::ClearFlagBit _clearFlag = gfx::ClearFlagBit::NONE;
|
||||
gfx::Color _backgroundColor{1.0, 1.0, 1.0, 1.0};
|
||||
int32_t _visibility = 0;
|
||||
ProbeType _probeType = ProbeType::CUBE;
|
||||
IntrusivePtr<TextureCube> _cubemap{nullptr};
|
||||
Vec3 _size;
|
||||
/**
|
||||
* @en Objects inside bouding box.
|
||||
* @zh 包围盒范围内的物体
|
||||
*/
|
||||
ccstd::vector<Model*> _renderObjects;
|
||||
|
||||
/**
|
||||
* @en Render cubemap's camera
|
||||
* @zh 渲染cubemap的相机
|
||||
*/
|
||||
IntrusivePtr<scene::Camera> _camera{nullptr};
|
||||
|
||||
/**
|
||||
* @en Unique id of probe.
|
||||
* @zh probe的唯一id
|
||||
*/
|
||||
int32_t _probeId = 0;
|
||||
|
||||
bool _needRender = false;
|
||||
|
||||
IntrusivePtr<Node> _node;
|
||||
|
||||
IntrusivePtr<Node> _cameraNode;
|
||||
IntrusivePtr<Node> _previewSphere;
|
||||
IntrusivePtr<Node> _previewPlane;
|
||||
|
||||
/**
|
||||
* @en The AABB bounding box and probe only render the objects inside the bounding box.
|
||||
* @zh AABB包围盒,probe只渲染包围盒内的物体
|
||||
*/
|
||||
IntrusivePtr<geometry::AABB> _boundingBox{nullptr};
|
||||
|
||||
/**
|
||||
* @en The position of the camera in world space.
|
||||
* @zh 世界空间相机的位置
|
||||
*/
|
||||
Vec3 _cameraWorldPos;
|
||||
|
||||
/**
|
||||
* @en The rotation of the camera in world space.
|
||||
* @zh 世界空间相机的旋转
|
||||
*/
|
||||
Quaternion _cameraWorldRotation;
|
||||
|
||||
/**
|
||||
* @en The forward direction vertor of the camera in world space.
|
||||
* @zh 世界空间相机朝前的方向向量
|
||||
*/
|
||||
Vec3 _forward;
|
||||
/**
|
||||
* @en The up direction vertor of the camera in world space.
|
||||
* @zh 世界空间相机朝上的方向向量
|
||||
*/
|
||||
Vec3 _up;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(ReflectionProbe);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
76
cocos/scene/ReflectionProbeManager.cpp
Normal file
76
cocos/scene/ReflectionProbeManager.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ReflectionProbeManager.h"
|
||||
#include "scene/ReflectionProbe.h"
|
||||
namespace cc {
|
||||
|
||||
namespace scene {
|
||||
namespace {
|
||||
ReflectionProbeManager* instance = nullptr;
|
||||
}
|
||||
|
||||
ReflectionProbeManager* ReflectionProbeManager::getInstance() {
|
||||
if (instance == nullptr) {
|
||||
instance = new ReflectionProbeManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
ReflectionProbeManager::ReflectionProbeManager() = default;
|
||||
void ReflectionProbeManager::registerProbe(scene::ReflectionProbe* probe) {
|
||||
_probes.emplace_back(probe);
|
||||
}
|
||||
void ReflectionProbeManager::unRegisterProbe(scene::ReflectionProbe* probe) {
|
||||
const auto iter = std::find(_probes.begin(), _probes.end(), probe);
|
||||
if (iter != _probes.end()) {
|
||||
_probes.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
ReflectionProbe* ReflectionProbeManager::getReflectionProbeById(int32_t probeId) {
|
||||
for (const auto& probe : _probes) {
|
||||
if (probe->getProbeId() == probeId) {
|
||||
return probe;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t ReflectionProbeManager::getMaxProbeId() {
|
||||
if (_probes.empty()) {
|
||||
return -1;
|
||||
}
|
||||
if (_probes.size() == 1) {
|
||||
return _probes[0]->getProbeId();
|
||||
}
|
||||
|
||||
std::sort(_probes.begin(), _probes.end(), [](const ReflectionProbe* p1, const ReflectionProbe* p2) {
|
||||
return p1->getProbeId() < p2->getProbeId();
|
||||
});
|
||||
return _probes[_probes.size() - 1]->getProbeId();
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
49
cocos/scene/ReflectionProbeManager.h
Normal file
49
cocos/scene/ReflectionProbeManager.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "base/Macros.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
#include "scene/Camera.h"
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
class ReflectionProbe;
|
||||
// namespace scene
|
||||
class ReflectionProbeManager final {
|
||||
public:
|
||||
static ReflectionProbeManager* getInstance();
|
||||
ReflectionProbeManager();
|
||||
~ReflectionProbeManager() = default;
|
||||
void registerProbe(scene::ReflectionProbe* probe);
|
||||
void unRegisterProbe(scene::ReflectionProbe* probe);
|
||||
const ccstd::vector<scene::ReflectionProbe*>& getAllProbes() const { return _probes; }
|
||||
ReflectionProbe* getReflectionProbeById(int32_t probeId);
|
||||
int32_t getMaxProbeId();
|
||||
private:
|
||||
ccstd::vector<scene::ReflectionProbe*> _probes;
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
593
cocos/scene/RenderScene.cpp
Normal file
593
cocos/scene/RenderScene.cpp
Normal file
@@ -0,0 +1,593 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/RenderScene.h"
|
||||
#include "scene/Camera.h"
|
||||
|
||||
#include <utility>
|
||||
#include "3d/models/BakedSkinningModel.h"
|
||||
#include "3d/models/SkinningModel.h"
|
||||
#include "base/Log.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
#include "scene/Camera.h"
|
||||
#include "scene/DirectionalLight.h"
|
||||
#include "scene/DrawBatch2D.h"
|
||||
#include "scene/LODGroup.h"
|
||||
#include "scene/Model.h"
|
||||
#include "scene/Octree.h"
|
||||
#include "scene/PointLight.h"
|
||||
#include "scene/RangedDirectionalLight.h"
|
||||
#include "scene/SphereLight.h"
|
||||
#include "scene/SpotLight.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
/**
|
||||
* @zh 管理LODGroup的使用状态,包含使用层级及其上的model可见相机列表;便于判断当前model是否被LODGroup裁剪
|
||||
* @en Manage the usage status of LODGroup, including the usage level and the list of visible cameras on its models; easy to determine whether the current mod is cropped by LODGroup。
|
||||
*/
|
||||
class LodStateCache : public RefCounted {
|
||||
public:
|
||||
struct LODInfo {
|
||||
/**
|
||||
* @zh 当前使用哪一级的 LOD, -1 表示没有层级被使用
|
||||
* @en Which level of LOD is currently in use, -1 means no levels are used
|
||||
*/
|
||||
int8_t usedLevel{-1};
|
||||
int8_t lastUsedLevel{-1};
|
||||
bool transformDirty{true};
|
||||
};
|
||||
|
||||
explicit LodStateCache(RenderScene *scene) : _renderScene(scene){};
|
||||
~LodStateCache() override = default;
|
||||
|
||||
void addCamera(const Camera *camera);
|
||||
|
||||
void removeCamera(const Camera *camera);
|
||||
|
||||
void addLodGroup(const LODGroup *lodGroup);
|
||||
|
||||
void removeLodGroup(const LODGroup *lodGroup);
|
||||
|
||||
void removeModel(const Model *model);
|
||||
|
||||
void updateLodState();
|
||||
|
||||
bool isLodModelCulled(const Camera *camera, const Model *model);
|
||||
|
||||
void clearCache();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @zh LOD使用的model集合以及每个model当前能被看到的相机列表;包含每个LODGroup的每一级LOD
|
||||
* @en The set of models used by the LOD and the list of cameras that each models can currently be seen, contains each level of LOD for each LODGroup.
|
||||
*/
|
||||
ccstd::unordered_map<const Model *, ccstd::unordered_map<const Camera *, bool>> _modelsInLODGroup;
|
||||
|
||||
/**
|
||||
* @zh 指定相机下,LODGroup使用哪一级的LOD
|
||||
* @en Specify which level of LOD is used by the LODGroup under the camera.
|
||||
*/
|
||||
ccstd::unordered_map<const Camera *, ccstd::unordered_map<const LODGroup *, LODInfo>> _lodStateInCamera;
|
||||
|
||||
/**
|
||||
* @zh 上一帧添加的LODGroup
|
||||
* @en The LODGroup added in the previous frame.
|
||||
*/
|
||||
ccstd::vector<const LODGroup *> _newAddedLodGroupVec;
|
||||
|
||||
/**
|
||||
* @zh 每个LOD上的所有models,包含所有LODGroup中的所有LOD
|
||||
* @en All mods on each LOD, containing all LODs in all LODGroups.
|
||||
*/
|
||||
ccstd::unordered_map<const LODGroup *, ccstd::unordered_map<uint8_t, ccstd::vector<const Model *>>> _levelModels;
|
||||
|
||||
RenderScene *_renderScene{nullptr};
|
||||
};
|
||||
|
||||
RenderScene::RenderScene() = default;
|
||||
|
||||
RenderScene::~RenderScene() = default;
|
||||
|
||||
void RenderScene::activate() {
|
||||
const auto *sceneData = Root::getInstance()->getPipeline()->getPipelineSceneData();
|
||||
_octree = sceneData->getOctree();
|
||||
}
|
||||
|
||||
bool RenderScene::initialize(const IRenderSceneInfo &info) {
|
||||
_name = info.name;
|
||||
_lodStateCache = ccnew LodStateCache(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderScene::addLODGroup(LODGroup *group) {
|
||||
group->attachToScene(this);
|
||||
_lodGroups.emplace_back(group);
|
||||
_lodStateCache->addLodGroup(group);
|
||||
}
|
||||
|
||||
void RenderScene::removeLODGroup(LODGroup *group) {
|
||||
auto iter = std::find(_lodGroups.begin(), _lodGroups.end(), group);
|
||||
if (iter != _lodGroups.end()) {
|
||||
_lodStateCache->removeLodGroup(group);
|
||||
group->detachFromScene();
|
||||
_lodGroups.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid LODGroup.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeLODGroups() {
|
||||
for (const auto &group : _lodGroups) {
|
||||
_lodStateCache->removeLodGroup(group);
|
||||
group->detachFromScene();
|
||||
}
|
||||
_lodGroups.clear();
|
||||
}
|
||||
|
||||
bool RenderScene::isCulledByLod(const Camera *camera, const Model *model) const {
|
||||
return _lodStateCache->isLodModelCulled(camera, model);
|
||||
}
|
||||
|
||||
void RenderScene::setMainLight(DirectionalLight *dl) {
|
||||
_mainLight = dl;
|
||||
if (_mainLight) _mainLight->activate();
|
||||
}
|
||||
|
||||
void RenderScene::update(uint32_t stamp) {
|
||||
CC_PROFILE(RenderSceneUpdate);
|
||||
|
||||
if (_mainLight) {
|
||||
_mainLight->update();
|
||||
}
|
||||
for (const auto &light : _sphereLights) {
|
||||
light->update();
|
||||
}
|
||||
for (const auto &light : _spotLights) {
|
||||
light->update();
|
||||
}
|
||||
for (const auto &light : _pointLights) {
|
||||
light->update();
|
||||
}
|
||||
for (const auto &light : _rangedDirLights) {
|
||||
light->update();
|
||||
}
|
||||
for (const auto &model : _models) {
|
||||
if (model->isEnabled()) {
|
||||
model->updateTransform(stamp);
|
||||
model->updateUBOs(stamp);
|
||||
model->updateOctree();
|
||||
}
|
||||
}
|
||||
|
||||
CC_PROFILE_OBJECT_UPDATE(Models, _models.size());
|
||||
CC_PROFILE_OBJECT_UPDATE(Cameras, _cameras.size());
|
||||
CC_PROFILE_OBJECT_UPDATE(DrawBatch2D, _batches.size());
|
||||
|
||||
_lodStateCache->updateLodState();
|
||||
}
|
||||
|
||||
void RenderScene::destroy() {
|
||||
removeCameras();
|
||||
removeSphereLights();
|
||||
removeSpotLights();
|
||||
removePointLights();
|
||||
removeLODGroups();
|
||||
removeModels();
|
||||
_lodStateCache->clearCache();
|
||||
}
|
||||
|
||||
void RenderScene::addCamera(Camera *camera) {
|
||||
camera->attachToScene(this);
|
||||
_cameras.emplace_back(camera);
|
||||
_lodStateCache->addCamera(camera);
|
||||
}
|
||||
|
||||
void RenderScene::removeCamera(Camera *camera) {
|
||||
auto iter = std::find(_cameras.begin(), _cameras.end(), camera);
|
||||
if (iter != _cameras.end()) {
|
||||
_lodStateCache->removeCamera(camera);
|
||||
(*iter)->detachFromScene();
|
||||
_cameras.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeCameras() {
|
||||
for (const auto &camera : _cameras) {
|
||||
_lodStateCache->removeCamera(camera);
|
||||
camera->detachFromScene();
|
||||
camera->destroy();
|
||||
}
|
||||
_cameras.clear();
|
||||
}
|
||||
|
||||
void RenderScene::unsetMainLight(DirectionalLight *dl) {
|
||||
if (_mainLight == dl) {
|
||||
const auto &dlList = _directionalLights;
|
||||
if (!dlList.empty()) {
|
||||
setMainLight(dlList[dlList.size() - 1]);
|
||||
if (_mainLight->getNode() != nullptr) {
|
||||
uint32_t flag = _mainLight->getNode()->getChangedFlags();
|
||||
_mainLight->getNode()->setChangedFlags(flag | static_cast<uint32_t>(TransformBit::ROTATION));
|
||||
}
|
||||
return;
|
||||
}
|
||||
setMainLight(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::addDirectionalLight(DirectionalLight *dl) {
|
||||
dl->attachToScene(this);
|
||||
_directionalLights.emplace_back(dl);
|
||||
}
|
||||
|
||||
void RenderScene::removeDirectionalLight(DirectionalLight *dl) {
|
||||
auto iter = std::find(_directionalLights.begin(), _directionalLights.end(), dl);
|
||||
if (iter != _directionalLights.end()) {
|
||||
(*iter)->detachFromScene();
|
||||
_directionalLights.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::addSphereLight(SphereLight *light) {
|
||||
light->attachToScene(this);
|
||||
_sphereLights.emplace_back(light);
|
||||
}
|
||||
|
||||
void RenderScene::removeSphereLight(SphereLight *sphereLight) {
|
||||
auto iter = std::find(_sphereLights.begin(), _sphereLights.end(), sphereLight);
|
||||
if (iter != _sphereLights.end()) {
|
||||
(*iter)->detachFromScene();
|
||||
_sphereLights.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid sphere light.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::addSpotLight(SpotLight *spotLight) {
|
||||
spotLight->attachToScene(this);
|
||||
_spotLights.emplace_back(spotLight);
|
||||
}
|
||||
|
||||
void RenderScene::removeSpotLight(SpotLight *spotLight) {
|
||||
auto iter = std::find(_spotLights.begin(), _spotLights.end(), spotLight);
|
||||
if (iter != _spotLights.end()) {
|
||||
(*iter)->detachFromScene();
|
||||
_spotLights.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid spot light.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeSphereLights() {
|
||||
for (const auto &sphereLight : _sphereLights) {
|
||||
sphereLight->detachFromScene();
|
||||
}
|
||||
_sphereLights.clear();
|
||||
}
|
||||
|
||||
void RenderScene::removeSpotLights() {
|
||||
for (const auto &spotLight : _spotLights) {
|
||||
spotLight->detachFromScene();
|
||||
}
|
||||
_spotLights.clear();
|
||||
}
|
||||
|
||||
void RenderScene::addPointLight(PointLight *light) {
|
||||
_pointLights.emplace_back(light);
|
||||
}
|
||||
|
||||
void RenderScene::removePointLight(PointLight *pointLight) {
|
||||
auto iter = std::find(_pointLights.begin(), _pointLights.end(), pointLight);
|
||||
if (iter != _pointLights.end()) {
|
||||
_pointLights.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid point light.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removePointLights() {
|
||||
for (const auto &pointLight : _pointLights) {
|
||||
pointLight->detachFromScene();
|
||||
}
|
||||
_pointLights.clear();
|
||||
}
|
||||
|
||||
void RenderScene::addRangedDirLight(RangedDirectionalLight *rangedDirLight) {
|
||||
_rangedDirLights.emplace_back(rangedDirLight);
|
||||
}
|
||||
|
||||
void RenderScene::removeRangedDirLight(RangedDirectionalLight *rangedDirLight) {
|
||||
const auto iter = std::find(_rangedDirLights.begin(), _rangedDirLights.end(), rangedDirLight);
|
||||
if (iter != _rangedDirLights.end()) {
|
||||
_rangedDirLights.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid ranged directional light.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeRangedDirLights() {
|
||||
for (const auto &rangedDirLight : _rangedDirLights) {
|
||||
rangedDirLight->detachFromScene();
|
||||
}
|
||||
_rangedDirLights.clear();
|
||||
}
|
||||
|
||||
void RenderScene::addModel(Model *model) {
|
||||
model->attachToScene(this);
|
||||
_models.emplace_back(model);
|
||||
if (_octree && _octree->isEnabled()) {
|
||||
_octree->insert(model);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeModel(Model *model) {
|
||||
auto iter = std::find(_models.begin(), _models.end(), model);
|
||||
if (iter != _models.end()) {
|
||||
if (_octree && _octree->isEnabled()) {
|
||||
_octree->remove(*iter);
|
||||
}
|
||||
_lodStateCache->removeModel(model);
|
||||
model->detachFromScene();
|
||||
_models.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid model.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeModels() {
|
||||
for (const auto &model : _models) {
|
||||
if (_octree && _octree->isEnabled()) {
|
||||
_octree->remove(model);
|
||||
}
|
||||
_lodStateCache->removeModel(model);
|
||||
model->detachFromScene();
|
||||
CC_SAFE_DESTROY(model);
|
||||
}
|
||||
_models.clear();
|
||||
}
|
||||
void RenderScene::addBatch(DrawBatch2D *drawBatch2D) {
|
||||
_batches.emplace_back(drawBatch2D);
|
||||
}
|
||||
|
||||
void RenderScene::removeBatch(DrawBatch2D *drawBatch2D) {
|
||||
auto iter = std::find(_batches.begin(), _batches.end(), drawBatch2D);
|
||||
if (iter != _batches.end()) {
|
||||
_batches.erase(iter);
|
||||
} else {
|
||||
CC_LOG_WARNING("Try to remove invalid DrawBatch2D.");
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::removeBatches() {
|
||||
_batches.clear();
|
||||
}
|
||||
|
||||
void RenderScene::updateOctree(Model *model) {
|
||||
if (_octree && _octree->isEnabled()) {
|
||||
_octree->update(model);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderScene::onGlobalPipelineStateChanged() {
|
||||
for (const auto &model : _models) {
|
||||
model->onGlobalPipelineStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void LodStateCache::addCamera(const Camera *camera) {
|
||||
for (const auto &lodGroup : _renderScene->getLODGroups()) {
|
||||
auto layer = lodGroup->getNode()->getLayer();
|
||||
if ((camera->getVisibility() & layer) == layer) {
|
||||
if (_lodStateInCamera.count(camera) == 0) {
|
||||
_lodStateInCamera[camera] = {};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LodStateCache::removeCamera(const Camera *camera) {
|
||||
if (_lodStateInCamera.count(camera) != 0) {
|
||||
_lodStateInCamera.erase(camera);
|
||||
}
|
||||
}
|
||||
|
||||
void LodStateCache::addLodGroup(const LODGroup *lodGroup) {
|
||||
_newAddedLodGroupVec.push_back(lodGroup);
|
||||
|
||||
for (const auto &camera : _renderScene->getCameras()) {
|
||||
if (_lodStateInCamera.count(camera)) {
|
||||
continue;
|
||||
}
|
||||
auto layer = lodGroup->getNode()->getLayer();
|
||||
if ((camera->getVisibility() & layer) == layer) {
|
||||
_lodStateInCamera[camera] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LodStateCache::removeLodGroup(const LODGroup *lodGroup) {
|
||||
for (auto index = 0; index < lodGroup->getLodCount(); index++) {
|
||||
const auto &lod = lodGroup->getLodDataArray()[index];
|
||||
for (const auto &model : lod->getModels()) {
|
||||
_modelsInLODGroup.erase(model);
|
||||
}
|
||||
}
|
||||
for (auto &visibleCamera : _lodStateInCamera) {
|
||||
visibleCamera.second.erase(lodGroup);
|
||||
}
|
||||
_levelModels.erase(lodGroup);
|
||||
}
|
||||
|
||||
void LodStateCache::removeModel(const Model *model) {
|
||||
if (_modelsInLODGroup.count(model) != 0) {
|
||||
_modelsInLODGroup.erase(model);
|
||||
}
|
||||
}
|
||||
|
||||
// Update list of visible cameras on _modelsInLODGroup and update lod usage level under specified camera.
|
||||
void LodStateCache::updateLodState() {
|
||||
//insert _newAddedLodGroupVec's model into _modelsInLODGroup
|
||||
for (const auto &addedLodGroup : _newAddedLodGroupVec) {
|
||||
auto &lodModels = _levelModels[addedLodGroup];
|
||||
for (uint8_t index = 0; index < addedLodGroup->getLodCount(); index++) {
|
||||
auto &vecModels = lodModels[index];
|
||||
const auto &lod = addedLodGroup->getLodDataArray()[index];
|
||||
for (const auto &model : lod->getModels()) {
|
||||
auto &modelInfo = _modelsInLODGroup[model];
|
||||
vecModels.push_back(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
_newAddedLodGroupVec.clear();
|
||||
|
||||
//update current visible lod index & model's visible cameras list
|
||||
for (const auto &lodGroup : _renderScene->getLODGroups()) {
|
||||
if (lodGroup->isEnabled()) {
|
||||
const auto &lodLevels = lodGroup->getLockedLODLevels();
|
||||
// lodLevels is not empty, indicating that the user force to use certain layers of LOD
|
||||
if (!lodLevels.empty()) {
|
||||
//Update the dirty flag to make it easier to update the visible index of lod after lifting the forced use of lod.
|
||||
if (lodGroup->getNode()->getChangedFlags() > 0) {
|
||||
for (auto &visibleCamera : _lodStateInCamera) {
|
||||
auto &lodInfo = visibleCamera.second[lodGroup];
|
||||
lodInfo.transformDirty = true;
|
||||
}
|
||||
}
|
||||
//Update the visible camera list of all models on lodGroup when the visible level changes.
|
||||
if (lodGroup->isLockLevelChanged()) {
|
||||
lodGroup->resetLockChangeFlag();
|
||||
const auto &lodModels = _levelModels[lodGroup];
|
||||
for (const auto &level : lodModels) {
|
||||
const auto &vecModels = lodModels.at(level.first);
|
||||
for (const auto &model : vecModels) {
|
||||
_modelsInLODGroup[model].clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t visibleIndex : lodLevels) {
|
||||
const auto &vecModels = lodModels.at(visibleIndex);
|
||||
for (const auto &model : vecModels) {
|
||||
if (model->getNode() && model->getNode()->isActive()) {
|
||||
auto &modelInfo = _modelsInLODGroup[model];
|
||||
for (const auto &visibleCamera : _lodStateInCamera) {
|
||||
modelInfo.emplace(visibleCamera.first, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//Normal Process, no LOD is forced.
|
||||
bool hasUpdated = false;
|
||||
for (auto &visibleCamera : _lodStateInCamera) {
|
||||
auto cameraChangeFlags = visibleCamera.first->getNode()->getChangedFlags();
|
||||
auto lodGroupChangeFlags = lodGroup->getNode()->getChangedFlags();
|
||||
auto &lodInfo = visibleCamera.second[lodGroup];
|
||||
//Changes in the camera matrix or changes in the matrix of the node where lodGroup is located or the transformDirty marker is true, etc. All need to recalculate the visible level of LOD.
|
||||
if (cameraChangeFlags > 0 || lodGroupChangeFlags > 0 || lodInfo.transformDirty) {
|
||||
if (lodInfo.transformDirty) {
|
||||
lodInfo.transformDirty = false;
|
||||
}
|
||||
|
||||
int8_t index = lodGroup->getVisibleLODLevel(visibleCamera.first);
|
||||
if (index != lodInfo.usedLevel) {
|
||||
lodInfo.lastUsedLevel = lodInfo.usedLevel;
|
||||
lodInfo.usedLevel = index;
|
||||
hasUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//The LOD of the last frame is forced to be used, the list of visible cameras of modelInfo needs to be updated.
|
||||
const auto &lodModels = _levelModels[lodGroup];
|
||||
if (lodGroup->isLockLevelChanged()) {
|
||||
lodGroup->resetLockChangeFlag();
|
||||
|
||||
for (const auto &level : lodModels) {
|
||||
const auto &vecModels = lodModels.at(level.first);
|
||||
for (const auto &model : vecModels) {
|
||||
_modelsInLODGroup[model].clear();
|
||||
}
|
||||
}
|
||||
hasUpdated = true;
|
||||
} else if (hasUpdated) {
|
||||
for (auto &visibleCamera : _lodStateInCamera) {
|
||||
const auto &lodInfo = visibleCamera.second[lodGroup];
|
||||
int8_t usedLevel = lodInfo.usedLevel;
|
||||
if (lodInfo.usedLevel != lodInfo.lastUsedLevel && lodInfo.lastUsedLevel >= 0) {
|
||||
const auto &vecModels = lodModels.at(static_cast<uint8_t>(lodInfo.lastUsedLevel));
|
||||
for (const auto &model : vecModels) {
|
||||
_modelsInLODGroup[model].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Update the visible camera list of all models on lodGroup.
|
||||
if (hasUpdated) {
|
||||
for (auto &visibleCamera : _lodStateInCamera) {
|
||||
int8_t usedLevel = visibleCamera.second[lodGroup].usedLevel;
|
||||
if (usedLevel >= 0) {
|
||||
const auto &vecModels = lodModels.at(static_cast<uint8_t>(usedLevel));
|
||||
for (const auto &model : vecModels) {
|
||||
if (model->getNode() && model->getNode()->isActive()) {
|
||||
auto &modelInfo = _modelsInLODGroup[model];
|
||||
modelInfo.emplace(visibleCamera.first, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LodStateCache::isLodModelCulled(const Camera *camera, const Model *model) {
|
||||
const auto &itModel = _modelsInLODGroup.find(model);
|
||||
if (itModel == _modelsInLODGroup.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &visibleCamera = itModel->second;
|
||||
return visibleCamera.count(camera) == 0;
|
||||
}
|
||||
|
||||
void LodStateCache::clearCache() {
|
||||
_levelModels.clear();
|
||||
_modelsInLODGroup.clear();
|
||||
_lodStateInCamera.clear();
|
||||
_newAddedLodGroupVec.clear();
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
148
cocos/scene/RenderScene.h
Normal file
148
cocos/scene/RenderScene.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Node;
|
||||
class SkinningModel;
|
||||
class BakedSkinningModel;
|
||||
|
||||
namespace scene {
|
||||
|
||||
class Model;
|
||||
class Camera;
|
||||
class Octree;
|
||||
class DrawBatch2D;
|
||||
class DirectionalLight;
|
||||
class LODGroup;
|
||||
class SphereLight;
|
||||
class SpotLight;
|
||||
class PointLight;
|
||||
class RangedDirectionalLight;
|
||||
class LodStateCache;
|
||||
|
||||
struct IRaycastResult {
|
||||
Node *node{nullptr};
|
||||
float distance{0.F};
|
||||
};
|
||||
|
||||
struct IRenderSceneInfo {
|
||||
ccstd::string name;
|
||||
};
|
||||
|
||||
class RenderScene : public RefCounted {
|
||||
public:
|
||||
RenderScene();
|
||||
~RenderScene() override;
|
||||
|
||||
bool initialize(const IRenderSceneInfo &info);
|
||||
void update(uint32_t stamp);
|
||||
void destroy();
|
||||
|
||||
void activate();
|
||||
|
||||
void addCamera(Camera *camera);
|
||||
void removeCamera(Camera *camera);
|
||||
void removeCameras();
|
||||
|
||||
void addLODGroup(LODGroup *group);
|
||||
void removeLODGroup(LODGroup *group);
|
||||
void removeLODGroups();
|
||||
bool isCulledByLod(const Camera *camera, const Model *model) const;
|
||||
|
||||
void unsetMainLight(DirectionalLight *dl);
|
||||
void addDirectionalLight(DirectionalLight *dl);
|
||||
void removeDirectionalLight(DirectionalLight *dl);
|
||||
|
||||
void addSphereLight(SphereLight *);
|
||||
void removeSphereLight(SphereLight *);
|
||||
void removeSphereLights();
|
||||
|
||||
void addSpotLight(SpotLight *);
|
||||
void removeSpotLight(SpotLight *);
|
||||
void removeSpotLights();
|
||||
|
||||
void addPointLight(PointLight *);
|
||||
void removePointLight(PointLight *);
|
||||
void removePointLights();
|
||||
|
||||
void addRangedDirLight(RangedDirectionalLight *);
|
||||
void removeRangedDirLight(RangedDirectionalLight *);
|
||||
void removeRangedDirLights();
|
||||
|
||||
void addModel(Model *);
|
||||
void removeModel(Model *model);
|
||||
void removeModels();
|
||||
|
||||
void addBatch(DrawBatch2D *);
|
||||
void removeBatch(DrawBatch2D *);
|
||||
void removeBatches();
|
||||
|
||||
void onGlobalPipelineStateChanged();
|
||||
|
||||
inline DirectionalLight *getMainLight() const { return _mainLight.get(); }
|
||||
void setMainLight(DirectionalLight *dl);
|
||||
|
||||
inline uint64_t generateModelId() { return _modelId++; }
|
||||
inline const ccstd::string &getName() const { return _name; }
|
||||
inline const ccstd::vector<IntrusivePtr<Camera>> &getCameras() const { return _cameras; }
|
||||
inline const ccstd::vector<IntrusivePtr<LODGroup>> &getLODGroups() const { return _lodGroups; }
|
||||
inline const ccstd::vector<IntrusivePtr<SphereLight>> &getSphereLights() const { return _sphereLights; }
|
||||
inline const ccstd::vector<IntrusivePtr<SpotLight>> &getSpotLights() const { return _spotLights; }
|
||||
inline const ccstd::vector<IntrusivePtr<PointLight>> &getPointLights() const { return _pointLights; }
|
||||
inline const ccstd::vector<IntrusivePtr<RangedDirectionalLight>> &getRangedDirLights() const { return _rangedDirLights; }
|
||||
inline const ccstd::vector<IntrusivePtr<Model>> &getModels() const { return _models; }
|
||||
inline Octree *getOctree() const { return _octree; }
|
||||
void updateOctree(Model *model);
|
||||
inline const ccstd::vector<DrawBatch2D *> &getBatches() const { return _batches; }
|
||||
|
||||
private:
|
||||
ccstd::string _name;
|
||||
uint64_t _modelId{0};
|
||||
IntrusivePtr<DirectionalLight> _mainLight;
|
||||
IntrusivePtr<LodStateCache> _lodStateCache;
|
||||
ccstd::vector<IntrusivePtr<Model>> _models;
|
||||
ccstd::vector<IntrusivePtr<Camera>> _cameras;
|
||||
ccstd::vector<IntrusivePtr<DirectionalLight>> _directionalLights;
|
||||
ccstd::vector<IntrusivePtr<LODGroup>> _lodGroups;
|
||||
ccstd::vector<IntrusivePtr<SphereLight>> _sphereLights;
|
||||
ccstd::vector<IntrusivePtr<SpotLight>> _spotLights;
|
||||
ccstd::vector<IntrusivePtr<PointLight>> _pointLights;
|
||||
ccstd::vector<IntrusivePtr<RangedDirectionalLight>> _rangedDirLights;
|
||||
ccstd::vector<DrawBatch2D *> _batches;
|
||||
Octree *_octree{nullptr};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderScene);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
199
cocos/scene/RenderWindow.cpp
Normal file
199
cocos/scene/RenderWindow.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/RenderWindow.h"
|
||||
#include "BasePlatform.h"
|
||||
#include "interfaces/modules/ISystemWindow.h"
|
||||
#include "interfaces/modules/ISystemWindowManager.h"
|
||||
#include "platform/interfaces/modules/Device.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
#include "renderer/gfx-base/GFXFramebuffer.h"
|
||||
#include "renderer/gfx-base/GFXSwapchain.h"
|
||||
#include "renderer/gfx-base/GFXTexture.h"
|
||||
#include "scene/Camera.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
namespace {
|
||||
|
||||
const ccstd::unordered_map<IScreen::Orientation, gfx::SurfaceTransform> ORIENTATION_MAP{
|
||||
{IScreen::Orientation::PORTRAIT, gfx::SurfaceTransform::IDENTITY},
|
||||
{IScreen::Orientation::LANDSCAPE_RIGHT, gfx::SurfaceTransform::ROTATE_90},
|
||||
{IScreen::Orientation::PORTRAIT_UPSIDE_DOWN, gfx::SurfaceTransform::ROTATE_180},
|
||||
{IScreen::Orientation::LANDSCAPE_LEFT, gfx::SurfaceTransform::ROTATE_270},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RenderWindow::RenderWindow() = default;
|
||||
RenderWindow::~RenderWindow() = default;
|
||||
|
||||
bool RenderWindow::initialize(gfx::Device *device, IRenderWindowInfo &info) {
|
||||
if (info.title.has_value() && !info.title.value().empty()) {
|
||||
_title = info.title.value();
|
||||
}
|
||||
|
||||
if (info.swapchain != nullptr) {
|
||||
_swapchain = info.swapchain;
|
||||
}
|
||||
|
||||
_width = info.width;
|
||||
_height = info.height;
|
||||
|
||||
_renderPass = device->createRenderPass(info.renderPassInfo);
|
||||
|
||||
if (info.swapchain != nullptr) {
|
||||
_swapchain = info.swapchain;
|
||||
_colorTextures.pushBack(info.swapchain->getColorTexture());
|
||||
_depthStencilTexture = info.swapchain->getDepthStencilTexture();
|
||||
} else {
|
||||
for (auto &colorAttachment : info.renderPassInfo.colorAttachments) {
|
||||
gfx::TextureInfo textureInfo = {gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED | gfx::TextureUsageBit::TRANSFER_SRC,
|
||||
colorAttachment.format,
|
||||
_width,
|
||||
_height};
|
||||
if (info.externalFlag.has_value()) {
|
||||
if (hasFlag(info.externalFlag.value(), gfx::TextureFlagBit::EXTERNAL_NORMAL)) {
|
||||
textureInfo.flags |= info.externalFlag.value();
|
||||
if (info.externalResLow.has_value() && info.externalResHigh.has_value()) {
|
||||
uint64_t externalResAddr = (static_cast<uint64_t>(info.externalResHigh.value()) << 32) | info.externalResLow.value();
|
||||
textureInfo.externalRes = reinterpret_cast<void *>(externalResAddr);
|
||||
} else if (info.externalResLow.has_value()) {
|
||||
textureInfo.externalRes = reinterpret_cast<void *>(static_cast<uint64_t>(info.externalResLow.value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_colorTextures.pushBack(device->createTexture(textureInfo));
|
||||
}
|
||||
if (info.renderPassInfo.depthStencilAttachment.format != gfx::Format::UNKNOWN) {
|
||||
_depthStencilTexture = device->createTexture({gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::DEPTH_STENCIL_ATTACHMENT | gfx::TextureUsageBit::SAMPLED,
|
||||
info.renderPassInfo.depthStencilAttachment.format,
|
||||
_width,
|
||||
_height});
|
||||
}
|
||||
}
|
||||
|
||||
generateFrameBuffer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderWindow::destroy() {
|
||||
clearCameras();
|
||||
|
||||
// Gfx objects invoke destroy in VK\GL\MTL Object destructor.
|
||||
_frameBuffer = nullptr;
|
||||
_renderPass = nullptr;
|
||||
_depthStencilTexture = nullptr;
|
||||
|
||||
// RefVector invokes RefCounted::release() when removing an element.
|
||||
_colorTextures.clear();
|
||||
}
|
||||
|
||||
void RenderWindow::resize(uint32_t width, uint32_t height) {
|
||||
if (_swapchain != nullptr) {
|
||||
_swapchain->resize(width, height, ORIENTATION_MAP.at(Device::getDeviceOrientation()));
|
||||
_width = _swapchain->getWidth();
|
||||
_height = _swapchain->getHeight();
|
||||
} else {
|
||||
for (auto *colorTexture : _colorTextures) {
|
||||
colorTexture->resize(width, height);
|
||||
}
|
||||
if (_depthStencilTexture != nullptr) {
|
||||
_depthStencilTexture->resize(width, height);
|
||||
}
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
generateFrameBuffer();
|
||||
|
||||
for (Camera *camera : _cameras) {
|
||||
camera->resize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWindow::extractRenderCameras(ccstd::vector<Camera *> &cameras) {
|
||||
for (Camera *camera : _cameras) {
|
||||
if (camera->isEnabled()) {
|
||||
camera->update();
|
||||
cameras.emplace_back(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWindow::onNativeWindowDestroy(uint32_t windowId) {
|
||||
if (_swapchain != nullptr && _swapchain->getWindowId() == windowId) {
|
||||
_swapchain->destroySurface();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWindow::onNativeWindowResume(uint32_t windowId) {
|
||||
if (_swapchain == nullptr || _swapchain->getWindowId() != windowId) {
|
||||
return;
|
||||
}
|
||||
auto *windowMgr = BasePlatform::getPlatform()->getInterface<ISystemWindowManager>();
|
||||
auto *hWnd = reinterpret_cast<void *>(windowMgr->getWindow(windowId)->getWindowHandle());
|
||||
_swapchain->createSurface(hWnd);
|
||||
generateFrameBuffer();
|
||||
}
|
||||
|
||||
void RenderWindow::generateFrameBuffer() {
|
||||
_frameBuffer = gfx::Device::getInstance()->createFramebuffer(gfx::FramebufferInfo{
|
||||
_renderPass,
|
||||
_colorTextures.get(),
|
||||
_depthStencilTexture});
|
||||
}
|
||||
|
||||
void RenderWindow::attachCamera(Camera *camera) {
|
||||
for (Camera *cam : _cameras) {
|
||||
if (cam == camera) return;
|
||||
}
|
||||
_cameras.emplace_back(camera);
|
||||
sortCameras();
|
||||
}
|
||||
|
||||
void RenderWindow::detachCamera(Camera *camera) {
|
||||
for (auto it = _cameras.begin(); it != _cameras.end(); ++it) {
|
||||
if (*it == camera) {
|
||||
_cameras.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWindow::clearCameras() {
|
||||
_cameras.clear();
|
||||
}
|
||||
|
||||
void RenderWindow::sortCameras() {
|
||||
std::stable_sort(_cameras.begin(), _cameras.end(), [](Camera *a, Camera *b) { return a->getPriority() < b->getPriority(); });
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
|
||||
} // namespace cc
|
||||
142
cocos/scene/RenderWindow.h
Normal file
142
cocos/scene/RenderWindow.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefVector.h"
|
||||
#include "base/std/optional.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
class Camera;
|
||||
|
||||
struct IRenderWindowInfo {
|
||||
ccstd::optional<ccstd::string> title;
|
||||
uint32_t width{0};
|
||||
uint32_t height{0};
|
||||
gfx::RenderPassInfo renderPassInfo;
|
||||
gfx::Swapchain *swapchain{nullptr};
|
||||
ccstd::optional<uint32_t> externalResLow{0}; // for vulkan vkImage/opengl es texture created from external
|
||||
ccstd::optional<uint32_t> externalResHigh{0}; // for vulkan vkImage created from external
|
||||
ccstd::optional<gfx::TextureFlags> externalFlag{gfx::TextureFlags::NONE}; // external texture type normal or oes
|
||||
};
|
||||
|
||||
/**
|
||||
* @en The render window represents the render target, it could be an off screen frame buffer or the on screen buffer.
|
||||
* @zh 渲染窗口代表了一个渲染目标,可以是离屏的帧缓冲,也可以是屏幕缓冲
|
||||
*/
|
||||
class RenderWindow : public RefCounted {
|
||||
public:
|
||||
RenderWindow();
|
||||
~RenderWindow() override;
|
||||
|
||||
bool initialize(gfx::Device *device, IRenderWindowInfo &info);
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @en Resize window.
|
||||
* @zh 重置窗口大小。
|
||||
* @param width The new width.
|
||||
* @param height The new height.
|
||||
*/
|
||||
void resize(uint32_t width, uint32_t height);
|
||||
|
||||
void extractRenderCameras(ccstd::vector<Camera *> &cameras);
|
||||
|
||||
void onNativeWindowDestroy(uint32_t windowId);
|
||||
void onNativeWindowResume(uint32_t windowId);
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 添加渲染相机
|
||||
* @param camera 渲染相机
|
||||
*/
|
||||
void attachCamera(Camera *camera);
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 移除渲染相机
|
||||
* @param camera 相机
|
||||
*/
|
||||
void detachCamera(Camera *camera);
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 销毁全部渲染相机
|
||||
*/
|
||||
void clearCameras();
|
||||
|
||||
void sortCameras();
|
||||
|
||||
/**
|
||||
* @en Get window width. Pre-rotated (i.e. rotationally invariant, always in identity/portrait mode) if possible.
|
||||
* If you want to get oriented size instead, you should use [[Camera.width]] which corresponds to the current screen rotation.
|
||||
* @zh 获取窗口宽度。如果支持交换链预变换,返回值将始终处于单位旋转(竖屏)坐标系下。如果需要获取旋转后的尺寸,请使用 [[Camera.width]]。
|
||||
*/
|
||||
inline uint32_t getWidth() const { return _width; }
|
||||
|
||||
/**
|
||||
* @en Get window height. Pre-rotated (i.e. rotationally invariant, always in identity/portrait mode) if possible.
|
||||
* If you want to get oriented size instead, you should use [[Camera.width]] which corresponds to the current screen rotation.
|
||||
* @zh 获取窗口高度。如果支持交换链预变换,返回值将始终处于单位旋转(竖屏)坐标系下。如果需要获取旋转后的尺寸,请使用 [[Camera.height]]。
|
||||
*/
|
||||
inline uint32_t getHeight() const { return _height; }
|
||||
|
||||
/**
|
||||
* @en Get the swapchain for this window, if there is one
|
||||
* @zh 如果存在的话,获取此窗口的交换链
|
||||
*/
|
||||
inline gfx::Swapchain *getSwapchain() {
|
||||
return _swapchain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get window frame buffer.
|
||||
* @zh 帧缓冲对象。
|
||||
*/
|
||||
inline gfx::Framebuffer *getFramebuffer() const { return _frameBuffer.get(); }
|
||||
|
||||
inline const ccstd::vector<IntrusivePtr<Camera>> &getCameras() const { return _cameras; }
|
||||
|
||||
private:
|
||||
void generateFrameBuffer();
|
||||
|
||||
uint32_t _width{1};
|
||||
uint32_t _height{1};
|
||||
gfx::Swapchain *_swapchain{nullptr};
|
||||
ccstd::string _title;
|
||||
IntrusivePtr<gfx::RenderPass> _renderPass;
|
||||
IntrusivePtr<gfx::Texture> _depthStencilTexture;
|
||||
IntrusivePtr<gfx::Framebuffer> _frameBuffer;
|
||||
ccstd::vector<IntrusivePtr<Camera>> _cameras;
|
||||
RefVector<gfx::Texture *> _colorTextures;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderWindow);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
215
cocos/scene/Shadow.cpp
Normal file
215
cocos/scene/Shadow.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Shadow.h"
|
||||
#include <cmath>
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "scene/Pass.h"
|
||||
#include "cocos/renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
// ShadowInfo
|
||||
|
||||
void ShadowsInfo::setEnabled(bool val) {
|
||||
if (_enabled == val) {
|
||||
return;
|
||||
}
|
||||
|
||||
_enabled = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setEnabled(val);
|
||||
if (val) {
|
||||
_resource->setType(_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setType(ShadowType val) {
|
||||
_type = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setType(val);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setShadowColor(const Color &val) {
|
||||
_shadowColor.set(val);
|
||||
if (_resource != nullptr) {
|
||||
_resource->setShadowColor(val);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setPlaneDirection(const Vec3 &val) {
|
||||
_normal = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setNormal(val);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setPlaneHeight(float val) {
|
||||
_distance = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setDistance(val);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setPlaneBias(float val) {
|
||||
_planeBias = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setPlaneBias(val);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setMaxReceived(uint32_t val) {
|
||||
_maxReceived = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setMaxReceived(val);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setShadowMapSize(float value) {
|
||||
_size.set(value, value);
|
||||
if (_resource != nullptr) {
|
||||
_resource->setShadowMapSize(value);
|
||||
_resource->setShadowMapDirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsInfo::setPlaneFromNode(const Node *node) {
|
||||
const auto &qt = node->getWorldRotation();
|
||||
_normal = Vec3::UNIT_Y;
|
||||
_normal.transformQuat(qt);
|
||||
_distance = _normal.dot(node->getWorldPosition());
|
||||
}
|
||||
|
||||
void ShadowsInfo::activate(Shadows *resource) {
|
||||
_resource = resource;
|
||||
_resource->initialize(*this);
|
||||
_resource->activate();
|
||||
}
|
||||
|
||||
//
|
||||
const float Shadows::COEFFICIENT_OF_EXPANSION{2.0F * std::sqrt(3.0F)};
|
||||
|
||||
void Shadows::initialize(const ShadowsInfo &shadowsInfo) {
|
||||
setEnabled(shadowsInfo.isEnabled());
|
||||
setType(shadowsInfo.getType());
|
||||
setNormal(shadowsInfo.getPlaneDirection());
|
||||
setDistance(shadowsInfo.getPlaneHeight());
|
||||
setPlaneBias(shadowsInfo.getPlaneBias());
|
||||
setMaxReceived(shadowsInfo.getMaxReceived());
|
||||
if (fabsf(shadowsInfo.getShadowMapSize() - _size.x) > 0.1F) {
|
||||
setSize(Vec2(shadowsInfo.getShadowMapSize(), shadowsInfo.getShadowMapSize()));
|
||||
_shadowMapDirty = true;
|
||||
}
|
||||
|
||||
setShadowColor(shadowsInfo.getShadowColor());
|
||||
}
|
||||
|
||||
void Shadows::destroy() {
|
||||
if (_material) {
|
||||
_material->destroy();
|
||||
_material = nullptr;
|
||||
}
|
||||
|
||||
if (_instancingMaterial) {
|
||||
_instancingMaterial->destroy();
|
||||
_instancingMaterial = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Shader *Shadows::getPlanarShader(const ccstd::vector<IMacroPatch> &patches) {
|
||||
if (!_material) {
|
||||
createMaterial();
|
||||
}
|
||||
|
||||
const auto &passes = _material->getPasses();
|
||||
CC_ASSERT(passes && !passes->empty());
|
||||
return (passes && !passes->empty()) ? passes->at(0)->getShaderVariant(patches) : nullptr;
|
||||
}
|
||||
|
||||
gfx::Shader *Shadows::getPlanarInstanceShader(const ccstd::vector<IMacroPatch> &patches) {
|
||||
if (!_instancingMaterial) {
|
||||
createInstanceMaterial();
|
||||
}
|
||||
|
||||
const auto &passes = _instancingMaterial->getPasses();
|
||||
CC_ASSERT(passes && !passes->empty());
|
||||
return (passes && !passes->empty()) ? passes->at(0)->getShaderVariant(patches) : nullptr;
|
||||
}
|
||||
|
||||
void Shadows::activate() {
|
||||
if (_enabled) {
|
||||
if (_type == ShadowType::PLANAR) {
|
||||
updatePlanarInfo();
|
||||
} else {
|
||||
auto *pipeline = Root::getInstance()->getPipeline();
|
||||
if (pipeline) {
|
||||
pipeline->setValue("CC_SHADOW_TYPE", 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto *pipeline = Root::getInstance()->getPipeline();
|
||||
if (pipeline) {
|
||||
pipeline->setValue("CC_SHADOW_TYPE", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shadows::updatePlanarInfo() {
|
||||
if (!_material) {
|
||||
createMaterial();
|
||||
}
|
||||
if (!_instancingMaterial) {
|
||||
createInstanceMaterial();
|
||||
}
|
||||
|
||||
auto *pipeline = Root::getInstance()->getPipeline();
|
||||
if (pipeline) {
|
||||
pipeline->setValue("CC_SHADOW_TYPE", 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Shadows::createInstanceMaterial() {
|
||||
_instancingMaterial = ccnew Material();
|
||||
|
||||
IMaterialInfo materialInfo;
|
||||
materialInfo.effectName = "pipeline/planar-shadow";
|
||||
MacroRecord microRecord{{"USE_INSTANCING", true}};
|
||||
materialInfo.defines = microRecord;
|
||||
_instancingMaterial->initialize(materialInfo);
|
||||
}
|
||||
|
||||
void Shadows::createMaterial() {
|
||||
_material = ccnew Material();
|
||||
|
||||
IMaterialInfo materialInfo;
|
||||
materialInfo.effectName = "pipeline/planar-shadow";
|
||||
_material->initialize(materialInfo);
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
459
cocos/scene/Shadow.h
Normal file
459
cocos/scene/Shadow.h
Normal file
@@ -0,0 +1,459 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/assets/Material.h"
|
||||
#include "core/geometry/Sphere.h"
|
||||
#include "math/Color.h"
|
||||
#include "math/Mat4.h"
|
||||
#include "math/Vec2.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "renderer/gfx-base/GFXShader.h"
|
||||
#include "scene/Define.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Node;
|
||||
|
||||
namespace scene {
|
||||
|
||||
/**
|
||||
* @zh 阴影贴图分辨率。
|
||||
* @en The shadow map size.
|
||||
* @static
|
||||
* @enum Shadows.ShadowSize
|
||||
*/
|
||||
enum class ShadowSize {
|
||||
/**
|
||||
* @zh 分辨率 256 * 256。
|
||||
* @en shadow resolution 256 * 256.
|
||||
* @readonly
|
||||
*/
|
||||
LOW_256X256 = 256,
|
||||
|
||||
/**
|
||||
* @zh 分辨率 512 * 512。
|
||||
* @en shadow resolution 512 * 512.
|
||||
* @readonly
|
||||
*/
|
||||
MEDIUM_512X512 = 512,
|
||||
|
||||
/**
|
||||
* @zh 分辨率 1024 * 1024。
|
||||
* @en shadow resolution 1024 * 1024.
|
||||
* @readonly
|
||||
*/
|
||||
HIGH_1024X1024 = 1024,
|
||||
|
||||
/**
|
||||
* @zh 分辨率 2048 * 2048。
|
||||
* @en shadow resolution 2048 * 2048.
|
||||
* @readonly
|
||||
*/
|
||||
ULTRA_2048X2048 = 2048
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh 阴影类型。
|
||||
* @en The shadow type
|
||||
* @enum Shadows.ShadowType
|
||||
*/
|
||||
enum class ShadowType {
|
||||
/**
|
||||
* @zh 平面阴影。
|
||||
* @en Planar shadow
|
||||
* @property Planar
|
||||
* @readonly
|
||||
*/
|
||||
PLANAR = 0,
|
||||
|
||||
/**
|
||||
* @zh 阴影贴图。
|
||||
* @en Shadow type
|
||||
* @property ShadowMap
|
||||
* @readonly
|
||||
*/
|
||||
SHADOW_MAP = 1,
|
||||
NONE
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh pcf阴影等级。
|
||||
* @en The pcf type
|
||||
* @static
|
||||
* @enum Shadows.PCFType
|
||||
*/
|
||||
enum class PCFType {
|
||||
/**
|
||||
* @zh x1 次采样
|
||||
* @en x1 times
|
||||
* @readonly
|
||||
*/
|
||||
HARD = 0,
|
||||
|
||||
/**
|
||||
* @zh x4 次采样
|
||||
* @en x4 times
|
||||
* @readonly
|
||||
*/
|
||||
SOFT = 1,
|
||||
|
||||
/**
|
||||
* @zh x9 次采样
|
||||
* @en x9 times
|
||||
* @readonly
|
||||
*/
|
||||
SOFT_2X = 2,
|
||||
|
||||
/**
|
||||
* @zh x16 次采样
|
||||
* @en x16 times
|
||||
* @readonly
|
||||
*/
|
||||
SOFT_4X = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh 级联阴影贴图层级。
|
||||
* @en The CSM shadow level
|
||||
* @static
|
||||
* @enum Shadows.CSMLevel
|
||||
*/
|
||||
enum class CSMLevel {
|
||||
/**
|
||||
* @zh 1 个层级
|
||||
* @en level 1
|
||||
* @readonly
|
||||
*/
|
||||
LEVEL_1 = 1,
|
||||
|
||||
/**
|
||||
* @zh 2 个层级
|
||||
* @en level 2
|
||||
* @readonly
|
||||
*/
|
||||
LEVEL_2 = 2,
|
||||
|
||||
/**
|
||||
* @zh 3 个层级
|
||||
* @en level 3
|
||||
* @readonly
|
||||
*/
|
||||
LEVEL_3 = 3,
|
||||
|
||||
/**
|
||||
* @zh 4 个层级
|
||||
* @en level 4
|
||||
* @readonly
|
||||
*/
|
||||
LEVEL_4 = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh 级联阴影性能优化模式。
|
||||
* @en The CSM performance optimization mode
|
||||
* @static
|
||||
* @enum Shadows.CSMOptimizationMode
|
||||
*/
|
||||
enum class CSMOptimizationMode {
|
||||
/**
|
||||
* @zh 没有性能优化
|
||||
* @en has no performance optimization
|
||||
* @readonly
|
||||
*/
|
||||
NONE = 1,
|
||||
|
||||
/**
|
||||
* @zh 剔除层与层之间重复物体
|
||||
* @en Eliminate duplicate objects between layers
|
||||
* @readonly
|
||||
*/
|
||||
REMOVE_DUPLICATES = 2,
|
||||
|
||||
/**
|
||||
* @zh 取消稳抖
|
||||
* @en Disable rotation fix
|
||||
* @readonly
|
||||
*/
|
||||
DISABLE_ROTATION_FIX = 3
|
||||
};
|
||||
|
||||
class Shadows;
|
||||
|
||||
class ShadowsInfo : public RefCounted {
|
||||
public:
|
||||
ShadowsInfo() = default;
|
||||
~ShadowsInfo() override = default;
|
||||
/**
|
||||
* @en Whether activate planar shadow
|
||||
* @zh 是否启用平面阴影?
|
||||
*/
|
||||
void setEnabled(bool val);
|
||||
inline bool isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void setType(ShadowType val);
|
||||
inline ShadowType getType() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Shadow color
|
||||
* @zh 阴影颜色
|
||||
*/
|
||||
void setShadowColor(const Color &val);
|
||||
inline const Color &getShadowColor() const {
|
||||
return _shadowColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The normal of the plane which receives shadow
|
||||
* @zh 阴影接收平面的法线
|
||||
*/
|
||||
void setPlaneDirection(const Vec3 &val);
|
||||
inline const Vec3 &getPlaneDirection() const {
|
||||
return _normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The distance from coordinate origin to the receiving plane.
|
||||
* @zh 阴影接收平面与原点的距离
|
||||
*/
|
||||
void setPlaneHeight(float val);
|
||||
inline float getPlaneHeight() const {
|
||||
return _distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Positional offset values in planar shading calculations.
|
||||
* @zh 平面阴影计算中的位置偏移值
|
||||
*/
|
||||
void setPlaneBias(float val);
|
||||
inline float getPlaneBias() const {
|
||||
return _planeBias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en get or set shadow max received
|
||||
* @zh 获取或者设置阴影接收的最大光源数量
|
||||
*/
|
||||
void setMaxReceived(uint32_t val);
|
||||
inline uint32_t getMaxReceived() const {
|
||||
return _maxReceived;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en get or set shadow map size
|
||||
* @zh 获取或者设置阴影纹理大小
|
||||
*/
|
||||
void setShadowMapSize(float value);
|
||||
inline float getShadowMapSize() const {
|
||||
return _size.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Set plane which receives shadow with the given node's world transformation
|
||||
* @zh 根据指定节点的世界变换设置阴影接收平面的信息
|
||||
* @param node The node for setting up the plane
|
||||
*/
|
||||
void setPlaneFromNode(const Node *node);
|
||||
|
||||
void activate(Shadows *resource);
|
||||
|
||||
bool _enabled{false};
|
||||
|
||||
ShadowType _type{ShadowType::PLANAR};
|
||||
|
||||
Shadows *_resource{nullptr};
|
||||
|
||||
uint32_t _maxReceived{4};
|
||||
|
||||
float _distance{0.F};
|
||||
float _planeBias{1.0F};
|
||||
|
||||
Vec2 _size{1024.F, 1024.F};
|
||||
|
||||
Vec3 _normal{0.F, 1.F, 0.F};
|
||||
|
||||
Color _shadowColor{0, 0, 0, 76};
|
||||
};
|
||||
|
||||
class Shadows final {
|
||||
public:
|
||||
/**
|
||||
* @en MAX_FAR. This is shadow camera max far.
|
||||
* @zh 阴影相机的最远视距。
|
||||
*/
|
||||
static constexpr float MAX_FAR{2000.F};
|
||||
|
||||
/**
|
||||
* @en EXPANSION_RATIO. This is shadow boundingBox Coefficient of expansion.
|
||||
* @zh 阴影包围盒扩大系数。
|
||||
*/
|
||||
static const float COEFFICIENT_OF_EXPANSION;
|
||||
|
||||
Shadows() = default;
|
||||
~Shadows() = default;
|
||||
|
||||
void initialize(const ShadowsInfo &shadowsInfo);
|
||||
void destroy();
|
||||
gfx::Shader *getPlanarShader(const ccstd::vector<IMacroPatch> &patches);
|
||||
gfx::Shader *getPlanarInstanceShader(const ccstd::vector<IMacroPatch> &patches);
|
||||
void activate();
|
||||
|
||||
/**
|
||||
* @en Whether activate shadow.
|
||||
* @zh 是否启用阴影?
|
||||
*/
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
inline void setEnabled(bool val) {
|
||||
_enabled = val;
|
||||
activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The normal of the plane which receives shadow.
|
||||
* @zh 阴影接收平面的法线。
|
||||
*/
|
||||
inline const Vec3 &getNormal() const { return _normal; }
|
||||
inline void setNormal(const Vec3 &val) { _normal.set(val); }
|
||||
|
||||
/**
|
||||
* @en The distance from coordinate origin to the receiving plane.
|
||||
* @zh 阴影接收平面与原点的距离。
|
||||
*/
|
||||
inline float getDistance() const { return _distance; }
|
||||
inline void setDistance(float val) { _distance = val; }
|
||||
|
||||
/**
|
||||
* @en Positional offset values in planar shading calculations.
|
||||
* @zh 平面阴影计算中的位置偏移值
|
||||
*/
|
||||
inline float getPlaneBias() const { return _planeBias; }
|
||||
inline void setPlaneBias(float val) { _planeBias = val; }
|
||||
|
||||
/**
|
||||
* @en Shadow color.
|
||||
* @zh 阴影颜色。
|
||||
*/
|
||||
inline const Color &getShadowColor() const { return _shadowColor; }
|
||||
inline void setShadowColor(const Color &color) {
|
||||
_shadowColor.set(color);
|
||||
_shadowColor4f[0] = static_cast<float>(color.r) / 255.F;
|
||||
_shadowColor4f[1] = static_cast<float>(color.g) / 255.F;
|
||||
_shadowColor4f[2] = static_cast<float>(color.b) / 255.F;
|
||||
_shadowColor4f[3] = static_cast<float>(color.a) / 255.F;
|
||||
}
|
||||
inline const ccstd::array<float, 4> &getShadowColor4f() const { return _shadowColor4f; }
|
||||
|
||||
/**
|
||||
* @en Shadow type.
|
||||
* @zh 阴影类型。
|
||||
*/
|
||||
inline ShadowType getType() const { return _type; }
|
||||
inline void setType(ShadowType val) {
|
||||
_type = _enabled ? val : ShadowType::NONE;
|
||||
activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @en get or set shadow camera orthoSize.
|
||||
* @zh 获取或者设置阴影纹理大小。
|
||||
*/
|
||||
inline const Vec2 &getSize() const { return _size; }
|
||||
inline void setSize(const Vec2 &val) {
|
||||
_size.set(val);
|
||||
_shadowMapDirty = true;
|
||||
}
|
||||
inline void setShadowMapSize(float value) {
|
||||
_size.set(value, value);
|
||||
_shadowMapDirty = true;
|
||||
}
|
||||
inline float getShadowMapSize() const {
|
||||
return _size.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en shadow Map size has been modified.
|
||||
* @zh 阴影贴图大小是否被修改。
|
||||
*/
|
||||
inline bool isShadowMapDirty() const { return _shadowMapDirty; }
|
||||
inline void setShadowMapDirty(bool val) { _shadowMapDirty = val; }
|
||||
|
||||
inline const Mat4 &getMatLight() const { return _matLight; }
|
||||
inline Mat4 &getMatLight() { return _matLight; }
|
||||
|
||||
inline Material *getMaterial() const { return _material.get(); }
|
||||
inline Material *getInstancingMaterial() const { return _instancingMaterial.get(); }
|
||||
|
||||
/**
|
||||
* @en get or set shadow max received
|
||||
* @zh 获取或者设置阴影接收的最大光源数量
|
||||
*/
|
||||
inline void setMaxReceived(uint32_t val) { _maxReceived = val; }
|
||||
inline uint32_t getMaxReceived() const { return _maxReceived; }
|
||||
|
||||
private:
|
||||
void updatePlanarInfo();
|
||||
void createInstanceMaterial();
|
||||
void createMaterial();
|
||||
|
||||
bool _enabled{false};
|
||||
bool _shadowMapDirty{false};
|
||||
|
||||
ShadowType _type{ShadowType::NONE};
|
||||
|
||||
IntrusivePtr<Material> _material{nullptr};
|
||||
IntrusivePtr<Material> _instancingMaterial{nullptr};
|
||||
|
||||
float _distance{0.F};
|
||||
float _planeBias{1.0F};
|
||||
|
||||
/**
|
||||
* @en get or set shadow max received.
|
||||
* @zh 阴影接收的最大灯光数量。
|
||||
*/
|
||||
uint32_t _maxReceived{4};
|
||||
|
||||
/**
|
||||
* @en The bounding sphere of the shadow map.
|
||||
* @zh 用于计算固定区域阴影 Shadow map 的场景包围球.
|
||||
*/
|
||||
geometry::Sphere _fixedSphere{0.0F, 0.0F, 0.0F, 0.01F};
|
||||
|
||||
Vec2 _size{1024.F, 1024.F};
|
||||
|
||||
// public properties of shadow
|
||||
Vec3 _normal{0.F, 1.F, 0.F};
|
||||
|
||||
Color _shadowColor{0, 0, 0, 76};
|
||||
ccstd::array<float, 4> _shadowColor4f{0.F, 0.F, 0.F, 76.F / 255.F};
|
||||
|
||||
Mat4 _matLight;
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
67
cocos/scene/Skin.cpp
Normal file
67
cocos/scene/Skin.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Skin.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
void SkinInfo::setEnabled(bool val) {
|
||||
if (_enabled == val) {
|
||||
return;
|
||||
}
|
||||
|
||||
_enabled = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setEnabled(val);
|
||||
}
|
||||
}
|
||||
|
||||
void SkinInfo::setBlurRadius(float val) {
|
||||
_blurRadius = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setBlurRadius(val);
|
||||
}
|
||||
}
|
||||
|
||||
void SkinInfo::setSSSIntensity(float val) {
|
||||
_sssIntensity = val;
|
||||
|
||||
if (_resource != nullptr) {
|
||||
_resource->setSSSIntensity(val);
|
||||
}
|
||||
}
|
||||
|
||||
void SkinInfo::activate(Skin *resource) {
|
||||
_resource = resource;
|
||||
_resource->initialize(*this);
|
||||
}
|
||||
|
||||
void Skin::initialize(const SkinInfo &skinInfo) {
|
||||
setEnabled(skinInfo.isEnabled());
|
||||
setBlurRadius(skinInfo.getBlurRadius());
|
||||
setSSSIntensity(skinInfo.getSSSIntensity());
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
121
cocos/scene/Skin.h
Normal file
121
cocos/scene/Skin.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/RefCounted.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
class Skin;
|
||||
|
||||
class SkinInfo : public RefCounted {
|
||||
public:
|
||||
SkinInfo() = default;
|
||||
~SkinInfo() override = default;
|
||||
|
||||
/**
|
||||
* @en Enable skip.
|
||||
* @zh 是否开启皮肤后效。
|
||||
*/
|
||||
void setEnabled(bool val);
|
||||
inline bool isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Getter/Setter sampler width.
|
||||
* @zh 设置或者获取采样宽度。
|
||||
*/
|
||||
void setBlurRadius(float val);
|
||||
inline float getBlurRadius() const {
|
||||
return _blurRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Getter/Setter depth unit scale.
|
||||
* @zh 设置或者获取深度单位比例。
|
||||
*/
|
||||
void setSSSIntensity(float val);
|
||||
inline float getSSSIntensity() const {
|
||||
return _sssIntensity;
|
||||
}
|
||||
|
||||
void activate(Skin *resource);
|
||||
|
||||
bool _enabled{true};
|
||||
|
||||
Skin *_resource{nullptr};
|
||||
|
||||
float _blurRadius{0.01F};
|
||||
float _sssIntensity{3.F};
|
||||
};
|
||||
|
||||
class Skin final {
|
||||
public:
|
||||
Skin() = default;
|
||||
~Skin() = default;
|
||||
|
||||
void initialize(const SkinInfo &skinInfo);
|
||||
|
||||
/**
|
||||
* @en Enable skip.
|
||||
* @zh 是否开启皮肤后效。
|
||||
*/
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
inline void setEnabled(bool val) {
|
||||
_enabled = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Getter/Setter sampler width.
|
||||
* @zh 设置或者获取采样宽度。
|
||||
*/
|
||||
inline float getBlurRadius() const {
|
||||
return _blurRadius;
|
||||
}
|
||||
inline void setBlurRadius(float val) {
|
||||
_blurRadius = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Getter/Setter depth unit scale.
|
||||
* @zh 设置或者获取深度单位比例。
|
||||
*/
|
||||
inline float getSSSIntensity() const {
|
||||
return _sssIntensity;
|
||||
}
|
||||
inline void setSSSIntensity(float val) {
|
||||
_sssIntensity = val;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _enabled{true};
|
||||
|
||||
float _blurRadius{0.01F};
|
||||
float _sssIntensity{3.F};
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
536
cocos/scene/Skybox.cpp
Normal file
536
cocos/scene/Skybox.cpp
Normal file
@@ -0,0 +1,536 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/Skybox.h"
|
||||
#include "3d/misc/CreateMesh.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/builtin/BuiltinResMgr.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "core/scene-graph/SceneGlobals.h"
|
||||
#include "pipeline/GlobalDescriptorSetManager.h"
|
||||
#include "primitive/Primitive.h"
|
||||
#include "renderer/core/MaterialInstance.h"
|
||||
#include "renderer/core/PassUtils.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
#include "scene/Ambient.h"
|
||||
#include "scene/Model.h"
|
||||
#include "scene/Pass.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
SkyboxInfo::SkyboxInfo(/* args */) = default;
|
||||
SkyboxInfo::~SkyboxInfo() = default;
|
||||
|
||||
void SkyboxInfo::setEnabled(bool val) {
|
||||
_enabled = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setEnabled(_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void SkyboxInfo::setUseIBL(bool val) const {
|
||||
if (_resource != nullptr) {
|
||||
_resource->setUseIBL(val);
|
||||
}
|
||||
}
|
||||
|
||||
void SkyboxInfo::setApplyDiffuseMap(bool val) const {
|
||||
if (_resource != nullptr) {
|
||||
_resource->setUseDiffuseMap(val);
|
||||
}
|
||||
}
|
||||
void SkyboxInfo::setEnvLightingType(EnvironmentLightingType val) {
|
||||
if (!getEnvmap() && EnvironmentLightingType::HEMISPHERE_DIFFUSE != val) {
|
||||
setUseIBL(false);
|
||||
setApplyDiffuseMap(false);
|
||||
_envLightingType = EnvironmentLightingType::HEMISPHERE_DIFFUSE;
|
||||
debug::warnID(15001);
|
||||
} else {
|
||||
if (EnvironmentLightingType::HEMISPHERE_DIFFUSE == val) {
|
||||
setUseIBL(false);
|
||||
setApplyDiffuseMap(false);
|
||||
} else if (EnvironmentLightingType::AUTOGEN_HEMISPHERE_DIFFUSE_WITH_REFLECTION == val) {
|
||||
setUseIBL(true);
|
||||
setApplyDiffuseMap(false);
|
||||
} else if (EnvironmentLightingType::DIFFUSEMAP_WITH_REFLECTION == val) {
|
||||
setUseIBL(true);
|
||||
setApplyDiffuseMap(true);
|
||||
}
|
||||
_envLightingType = val;
|
||||
}
|
||||
}
|
||||
void SkyboxInfo::setUseHDR(bool val) {
|
||||
Root::getInstance()->getPipeline()->getPipelineSceneData()->setHDR(val);
|
||||
_useHDR = val;
|
||||
|
||||
// Switch UI to and from LDR/HDR textures depends on HDR state
|
||||
if (_resource) {
|
||||
setEnvmap(_resource->getEnvmap());
|
||||
setDiffuseMap(_resource->getDiffuseMap());
|
||||
setReflectionMap(_resource->getReflectionMap());
|
||||
|
||||
if (_envLightingType == EnvironmentLightingType::DIFFUSEMAP_WITH_REFLECTION) {
|
||||
auto *diffuseMap = getDiffuseMap();
|
||||
if (!diffuseMap) {
|
||||
_envLightingType = EnvironmentLightingType::AUTOGEN_HEMISPHERE_DIFFUSE_WITH_REFLECTION;
|
||||
debug::warnID(15000);
|
||||
} else if (diffuseMap->isDefault()) {
|
||||
debug::warnID(15002);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_resource) {
|
||||
_resource->setUseHDR(_useHDR);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkyboxInfo::isUseHDR() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return _useHDR;
|
||||
}
|
||||
|
||||
void SkyboxInfo::setEnvmap(TextureCube *val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_envmapHDR = val;
|
||||
_reflectionHDR = nullptr;
|
||||
} else {
|
||||
_envmapLDR = val;
|
||||
_reflectionLDR = nullptr;
|
||||
}
|
||||
|
||||
if (!val) {
|
||||
if (isHDR) {
|
||||
_diffuseMapHDR = nullptr;
|
||||
} else {
|
||||
_diffuseMapLDR = nullptr;
|
||||
}
|
||||
setApplyDiffuseMap(false);
|
||||
setUseIBL(false);
|
||||
setEnvLightingType(EnvironmentLightingType::HEMISPHERE_DIFFUSE);
|
||||
debug::warnID(15001);
|
||||
}
|
||||
|
||||
if (_resource) {
|
||||
_resource->setEnvMaps(_envmapHDR, _envmapLDR);
|
||||
_resource->setDiffuseMaps(_diffuseMapHDR, _diffuseMapLDR);
|
||||
_resource->setReflectionMaps(_reflectionHDR, _reflectionLDR);
|
||||
_resource->setUseDiffuseMap(isApplyDiffuseMap());
|
||||
_resource->setEnvmap(val);
|
||||
}
|
||||
}
|
||||
|
||||
TextureCube *SkyboxInfo::getEnvmap() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _envmapHDR : _envmapLDR;
|
||||
}
|
||||
|
||||
void SkyboxInfo::setRotationAngle(float val) {
|
||||
_rotationAngle = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setRotationAngle(_rotationAngle);
|
||||
}
|
||||
}
|
||||
|
||||
void SkyboxInfo::setDiffuseMap(TextureCube *val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_diffuseMapHDR = val;
|
||||
} else {
|
||||
_diffuseMapHDR = val;
|
||||
}
|
||||
|
||||
if (_resource) {
|
||||
_resource->setDiffuseMaps(_diffuseMapHDR, _diffuseMapLDR);
|
||||
}
|
||||
}
|
||||
|
||||
TextureCube *SkyboxInfo::getDiffuseMap() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _diffuseMapHDR : _diffuseMapLDR;
|
||||
}
|
||||
|
||||
void SkyboxInfo::setReflectionMap(TextureCube *val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
_reflectionHDR = val;
|
||||
} else {
|
||||
_reflectionLDR = val;
|
||||
}
|
||||
|
||||
if (_resource) {
|
||||
_resource->setReflectionMaps(_reflectionHDR, _reflectionLDR);
|
||||
}
|
||||
}
|
||||
|
||||
TextureCube *SkyboxInfo::getReflectionMap() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
return _reflectionHDR;
|
||||
}
|
||||
return _reflectionLDR;
|
||||
}
|
||||
|
||||
void SkyboxInfo::setSkyboxMaterial(Material *val) {
|
||||
_editableMaterial = val;
|
||||
if (_resource != nullptr) {
|
||||
_resource->setSkyboxMaterial(val);
|
||||
}
|
||||
}
|
||||
|
||||
void SkyboxInfo::setMaterialProperty(const ccstd::string &name, const MaterialPropertyVariant &val, index_t passIdx /* = CC_INVALID_INDEX */) const {
|
||||
if (_resource == nullptr) return;
|
||||
auto *skyboxMat = _resource->getSkyboxMaterial();
|
||||
if (_resource->isEnabled() && skyboxMat != nullptr) {
|
||||
skyboxMat->setProperty(name, val, passIdx);
|
||||
auto &passs = skyboxMat->getPasses();
|
||||
for (const auto &pass : *passs) {
|
||||
pass->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkyboxInfo::updateEnvMap(TextureCube *val) {
|
||||
if (!val) {
|
||||
setApplyDiffuseMap(false);
|
||||
setUseIBL(false);
|
||||
setEnvLightingType(EnvironmentLightingType::HEMISPHERE_DIFFUSE);
|
||||
}
|
||||
if (_resource) {
|
||||
_resource->setEnvMaps(_envmapHDR, _envmapLDR);
|
||||
_resource->setDiffuseMaps(_diffuseMapHDR, _diffuseMapLDR);
|
||||
_resource->setReflectionMaps(_reflectionHDR, _reflectionLDR);
|
||||
_resource->setEnvmap(val);
|
||||
}
|
||||
}
|
||||
|
||||
void SkyboxInfo::activate(Skybox *resource) {
|
||||
_resource = resource; // weak reference
|
||||
Root::getInstance()->getPipeline()->getPipelineSceneData()->setHDR(_useHDR);
|
||||
if (_resource != nullptr) {
|
||||
_resource->initialize(*this);
|
||||
setEnvLightingType(this->_envLightingType);
|
||||
_resource->setEnvMaps(_envmapHDR, _envmapLDR);
|
||||
_resource->setDiffuseMaps(_diffuseMapHDR, _diffuseMapLDR);
|
||||
_resource->setReflectionMaps(_reflectionHDR, _reflectionLDR);
|
||||
_resource->setSkyboxMaterial(_editableMaterial);
|
||||
_resource->setRotationAngle(_rotationAngle);
|
||||
_resource->activate(); // update global DS first
|
||||
}
|
||||
}
|
||||
|
||||
TextureCube *Skybox::getEnvmap() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _envmapHDR : _envmapLDR;
|
||||
}
|
||||
|
||||
void Skybox::setEnvmap(TextureCube *val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
setEnvMaps(val, _envmapLDR);
|
||||
} else {
|
||||
setEnvMaps(_envmapHDR, val);
|
||||
}
|
||||
}
|
||||
|
||||
bool Skybox::isRGBE() const {
|
||||
auto *envmap = getEnvmap();
|
||||
return envmap != nullptr ? envmap->isRGBE : false;
|
||||
}
|
||||
|
||||
bool Skybox::isUsingConvolutionMap() const {
|
||||
auto *reflectionMap = getReflectionMap();
|
||||
if (reflectionMap) {
|
||||
return reflectionMap->isUsingOfflineMipmaps();
|
||||
}
|
||||
auto *envmap = getEnvmap();
|
||||
if (envmap) {
|
||||
return envmap->isUsingOfflineMipmaps();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TextureCube *Skybox::getDiffuseMap() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _diffuseMapHDR : _diffuseMapLDR;
|
||||
}
|
||||
void Skybox::setDiffuseMap(TextureCube *val) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
setDiffuseMaps(val, _diffuseMapLDR);
|
||||
} else {
|
||||
setDiffuseMaps(_diffuseMapHDR, val);
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::initialize(const SkyboxInfo &skyboxInfo) {
|
||||
_activated = false;
|
||||
_enabled = skyboxInfo.isEnabled();
|
||||
_useIBL = skyboxInfo.isUseIBL();
|
||||
_useDiffuseMap = skyboxInfo.isApplyDiffuseMap();
|
||||
_useHDR = skyboxInfo.isUseHDR();
|
||||
}
|
||||
|
||||
void Skybox::setEnvMaps(TextureCube *envmapHDR, TextureCube *envmapLDR) {
|
||||
_envmapHDR = envmapHDR;
|
||||
_envmapLDR = envmapLDR;
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
if (envmapHDR) {
|
||||
Root::getInstance()->getPipeline()->getPipelineSceneData()->getAmbient()->setMipmapCount(envmapHDR->mipmapLevel());
|
||||
}
|
||||
} else if (envmapLDR) {
|
||||
Root::getInstance()->getPipeline()->getPipelineSceneData()->getAmbient()->setMipmapCount(envmapLDR->mipmapLevel());
|
||||
}
|
||||
|
||||
updateGlobalBinding();
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
void Skybox::setDiffuseMaps(TextureCube *diffuseMapHDR, TextureCube *diffuseMapLDR) {
|
||||
_diffuseMapHDR = diffuseMapHDR;
|
||||
_diffuseMapLDR = diffuseMapLDR;
|
||||
updateGlobalBinding();
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
TextureCube *Skybox::getReflectionMap() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _reflectionHDR : _reflectionLDR;
|
||||
}
|
||||
void Skybox::setReflectionMaps(TextureCube *reflectionHDR, TextureCube *reflectionLDR) {
|
||||
_reflectionHDR = reflectionHDR;
|
||||
_reflectionLDR = reflectionLDR;
|
||||
updateGlobalBinding();
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
void Skybox::setSkyboxMaterial(Material *skyboxMat) {
|
||||
_editableMaterial = skyboxMat;
|
||||
}
|
||||
|
||||
void Skybox::setRotationAngle(float angle) {
|
||||
_rotationAngle = angle;
|
||||
}
|
||||
|
||||
void Skybox::activate() {
|
||||
auto *pipeline = Root::getInstance()->getPipeline();
|
||||
_globalDSManager = pipeline->getGlobalDSManager();
|
||||
_default = BuiltinResMgr::getInstance()->get<TextureCube>("default-cube-texture");
|
||||
|
||||
if (!_model) {
|
||||
_model = Root::getInstance()->createModel<scene::Model>();
|
||||
//The skybox material has added properties of 'environmentMap' that need local ubo
|
||||
//_model->initLocalDescriptors(CC_INVALID_INDEX);
|
||||
//_model->initWorldBoundDescriptors(CC_INVALID_INDEX);
|
||||
}
|
||||
auto *envmap = getEnvmap();
|
||||
bool isRGBE = envmap != nullptr ? envmap->isRGBE : _default->isRGBE;
|
||||
|
||||
bool isUseConvolutionMap = envmap != nullptr ? envmap->isUsingOfflineMipmaps() : _default->isUsingOfflineMipmaps();
|
||||
if (!_material) {
|
||||
auto *mat = _editableMaterial ? _editableMaterial.get() : ccnew Material();
|
||||
MacroRecord defines{{"USE_RGBE_CUBEMAP", isRGBE}};
|
||||
IMaterialInfo matInfo;
|
||||
matInfo.effectName = ccstd::string{"pipeline/skybox"};
|
||||
matInfo.defines = IMaterialInfo::DefinesType{defines};
|
||||
mat->initialize({matInfo});
|
||||
IMaterialInstanceInfo matInstInfo;
|
||||
matInstInfo.parent = mat;
|
||||
_material = ccnew MaterialInstance(matInstInfo);
|
||||
}
|
||||
|
||||
if (_enabled) {
|
||||
if (!_mesh) {
|
||||
IBoxOptions options;
|
||||
options.width = 2;
|
||||
options.height = 2;
|
||||
options.length = 2;
|
||||
|
||||
_mesh = MeshUtils::createMesh(
|
||||
createGeometry(
|
||||
PrimitiveType::BOX,
|
||||
PrimitiveOptions{options}));
|
||||
}
|
||||
_model->initSubModel(0, _mesh->getRenderingSubMeshes()[0], _material);
|
||||
}
|
||||
|
||||
if (!getEnvmap()) {
|
||||
setEnvmap(_default.get());
|
||||
}
|
||||
|
||||
if (!getDiffuseMap()) {
|
||||
setDiffuseMap(_default.get());
|
||||
}
|
||||
|
||||
updateGlobalBinding();
|
||||
updatePipeline();
|
||||
|
||||
_activated = true;
|
||||
}
|
||||
|
||||
void Skybox::setUseHDR(bool val) {
|
||||
Root::getInstance()->getPipeline()->getPipelineSceneData()->setHDR(val);
|
||||
_useHDR = val;
|
||||
setEnvMaps(_envmapHDR, _envmapLDR);
|
||||
}
|
||||
|
||||
void Skybox::updatePipeline() const {
|
||||
if (isEnabled() && _material != nullptr) {
|
||||
auto *envmap = getEnvmap();
|
||||
if (!envmap) {
|
||||
envmap = _default.get();
|
||||
}
|
||||
_material->setProperty("environmentMap", envmap);
|
||||
_material->recompileShaders({{"USE_RGBE_CUBEMAP", isRGBE()}});
|
||||
|
||||
if (_model != nullptr) {
|
||||
_model->setSubModelMaterial(0, _material);
|
||||
updateSubModes();
|
||||
}
|
||||
}
|
||||
|
||||
Root *root = Root::getInstance();
|
||||
auto *pipeline = root->getPipeline();
|
||||
|
||||
const bool useRGBE = isRGBE();
|
||||
const int32_t useIBLValue = isUseIBL() ? (useRGBE ? 2 : 1) : 0;
|
||||
const int32_t useDiffuseMapValue = (isUseIBL() && isUseDiffuseMap() && getDiffuseMap() != nullptr) ? (useRGBE ? 2 : 1) : 0;
|
||||
const bool useHDRValue = isUseHDR();
|
||||
const bool useConvMapValue = isUsingConvolutionMap();
|
||||
|
||||
bool valueChanged = false;
|
||||
auto iter = pipeline->getMacros().find("CC_USE_IBL");
|
||||
if (iter != pipeline->getMacros().end()) {
|
||||
const MacroValue ¯oIBL = iter->second;
|
||||
const int32_t *macroIBLPtr = ccstd::get_if<int32_t>(¯oIBL);
|
||||
if (macroIBLPtr != nullptr && (*macroIBLPtr != useIBLValue)) {
|
||||
pipeline->setValue("CC_USE_IBL", useIBLValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
} else {
|
||||
pipeline->setValue("CC_USE_IBL", useIBLValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
|
||||
auto iterDiffuseMap = pipeline->getMacros().find("CC_USE_DIFFUSEMAP");
|
||||
if (iterDiffuseMap != pipeline->getMacros().end()) {
|
||||
const MacroValue ¯oDIFFUSEMAP = iterDiffuseMap->second;
|
||||
const int32_t *macroDIFFUSEMAPPtr = ccstd::get_if<int32_t>(¯oDIFFUSEMAP);
|
||||
if (macroDIFFUSEMAPPtr != nullptr && ((*macroDIFFUSEMAPPtr != 0) != useDiffuseMapValue)) {
|
||||
pipeline->setValue("CC_USE_DIFFUSEMAP", useDiffuseMapValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
} else {
|
||||
pipeline->setValue("CC_USE_DIFFUSEMAP", useDiffuseMapValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
|
||||
auto iterUseHDR = pipeline->getMacros().find("CC_USE_HDR");
|
||||
if (iterUseHDR != pipeline->getMacros().end()) {
|
||||
const MacroValue ¯oHDR = iterUseHDR->second;
|
||||
const bool *macroHDRPtr = ccstd::get_if<bool>(¯oHDR);
|
||||
if (macroHDRPtr != nullptr && (*macroHDRPtr != useHDRValue)) {
|
||||
pipeline->setValue("CC_USE_HDR", useHDRValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
} else {
|
||||
pipeline->setValue("CC_USE_HDR", useHDRValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
|
||||
auto iterUseConvMap = pipeline->getMacros().find("CC_IBL_CONVOLUTED");
|
||||
if (iterUseConvMap != pipeline->getMacros().end()) {
|
||||
const MacroValue ¯oConvMap = iterUseConvMap->second;
|
||||
const bool *macroConvMaptr = ccstd::get_if<bool>(¯oConvMap);
|
||||
if (macroConvMaptr != nullptr && (*macroConvMaptr != useConvMapValue)) {
|
||||
pipeline->setValue("CC_IBL_CONVOLUTED", useConvMapValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
} else {
|
||||
pipeline->setValue("CC_IBL_CONVOLUTED", useConvMapValue);
|
||||
valueChanged = true;
|
||||
}
|
||||
|
||||
if (isEnabled() && _model != nullptr && _material != nullptr) {
|
||||
_model->setSubModelMaterial(0, _material);
|
||||
}
|
||||
|
||||
if (valueChanged && _activated) {
|
||||
root->onGlobalPipelineStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::updateGlobalBinding() {
|
||||
if (_globalDSManager != nullptr) {
|
||||
auto *device = Root::getInstance()->getDevice();
|
||||
|
||||
auto *convolutonMap = getReflectionMap();
|
||||
if (convolutonMap != nullptr) {
|
||||
auto *texture = convolutonMap->getGFXTexture();
|
||||
auto *sampler = device->getSampler(convolutonMap->getSamplerInfo());
|
||||
_globalDSManager->bindSampler(pipeline::ENVIRONMENT::BINDING, sampler);
|
||||
_globalDSManager->bindTexture(pipeline::ENVIRONMENT::BINDING, texture);
|
||||
} else {
|
||||
auto *envmap = getEnvmap();
|
||||
if (!envmap) {
|
||||
envmap = _default.get();
|
||||
}
|
||||
if (envmap != nullptr) {
|
||||
auto *texture = envmap->getGFXTexture();
|
||||
auto *sampler = device->getSampler(envmap->getSamplerInfo());
|
||||
_globalDSManager->bindSampler(pipeline::ENVIRONMENT::BINDING, sampler);
|
||||
_globalDSManager->bindTexture(pipeline::ENVIRONMENT::BINDING, texture);
|
||||
}
|
||||
}
|
||||
|
||||
auto *diffuseMap = getDiffuseMap();
|
||||
if (!diffuseMap) {
|
||||
diffuseMap = _default.get();
|
||||
}
|
||||
if (diffuseMap != nullptr) {
|
||||
auto *texture = diffuseMap->getGFXTexture();
|
||||
auto *sampler = device->getSampler(diffuseMap->getSamplerInfo());
|
||||
_globalDSManager->bindSampler(pipeline::DIFFUSEMAP::BINDING, sampler);
|
||||
_globalDSManager->bindTexture(pipeline::DIFFUSEMAP::BINDING, texture);
|
||||
}
|
||||
_globalDSManager->update();
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::updateSubModes() const {
|
||||
if (_model) {
|
||||
const auto &subModels = _model->getSubModels();
|
||||
for (const auto &subModel : subModels) {
|
||||
subModel->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
328
cocos/scene/Skybox.h
Normal file
328
cocos/scene/Skybox.h
Normal file
@@ -0,0 +1,328 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "3d/assets/Mesh.h"
|
||||
#include "base/Macros.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/assets/TextureCube.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace pipeline {
|
||||
class GlobalDSManager;
|
||||
}
|
||||
namespace scene {
|
||||
|
||||
enum class EnvironmentLightingType {
|
||||
/**
|
||||
* @zh
|
||||
* 半球漫反射
|
||||
* @en
|
||||
* hemisphere diffuse
|
||||
* @readonly
|
||||
*/
|
||||
HEMISPHERE_DIFFUSE = 0,
|
||||
/**
|
||||
* @zh
|
||||
* 半球漫反射和环境反射
|
||||
* @en
|
||||
* hemisphere diffuse and Environment reflection
|
||||
* @readonly
|
||||
*/
|
||||
AUTOGEN_HEMISPHERE_DIFFUSE_WITH_REFLECTION = 1,
|
||||
/**
|
||||
* @zh
|
||||
* 漫反射卷积图和环境反射
|
||||
* @en
|
||||
* diffuse convolution map and environment reflection
|
||||
* @readonly
|
||||
*/
|
||||
DIFFUSEMAP_WITH_REFLECTION = 2
|
||||
};
|
||||
|
||||
class Model;
|
||||
class Skybox;
|
||||
|
||||
/**
|
||||
* @en Skybox related information
|
||||
* @zh 天空盒相关信息
|
||||
*/
|
||||
// @ccclass('cc.SkyboxInfo')
|
||||
// @help('i18n:cc.Skybox')
|
||||
class SkyboxInfo : public RefCounted {
|
||||
public:
|
||||
SkyboxInfo(/* args */);
|
||||
~SkyboxInfo() override;
|
||||
|
||||
/**
|
||||
* @en Whether to use diffuse convolution map. Enabled -> Will use map specified. Disabled -> Will revert to hemispheric lighting
|
||||
* @zh 是否为IBL启用漫反射卷积图?不启用的话将使用默认的半球光照
|
||||
*/
|
||||
// @visible(function (this : SkyboxInfo) {
|
||||
// if (useIBL) {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// })
|
||||
// @editable
|
||||
// @tooltip('i18n:skybox.applyDiffuseMap')
|
||||
void setApplyDiffuseMap(bool val) const;
|
||||
|
||||
bool isApplyDiffuseMap() const {
|
||||
return EnvironmentLightingType::DIFFUSEMAP_WITH_REFLECTION == _envLightingType;
|
||||
}
|
||||
void setEnvLightingType(EnvironmentLightingType val);
|
||||
EnvironmentLightingType getEnvLightingType() const {
|
||||
return _envLightingType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Whether activate skybox in the scene
|
||||
* @zh 是否启用天空盒?
|
||||
*/
|
||||
// @editable
|
||||
// @tooltip('i18n:skybox.enabled')
|
||||
void setEnabled(bool val);
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
|
||||
/**
|
||||
* @en Whether use environment lighting
|
||||
* @zh 是否启用环境光照?
|
||||
*/
|
||||
// @editable
|
||||
// @tooltip('i18n:skybox.useIBL')
|
||||
void setUseIBL(bool val) const;
|
||||
inline bool isUseIBL() const {
|
||||
return EnvironmentLightingType::HEMISPHERE_DIFFUSE != _envLightingType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Toggle HDR (TODO: This SHOULD be moved into it's own subgroup away from skybox)
|
||||
* @zh 是否启用HDR?
|
||||
*/
|
||||
// @editable
|
||||
// @tooltip('i18n:skybox.useHDR')
|
||||
void setUseHDR(bool val);
|
||||
bool isUseHDR() const;
|
||||
/**
|
||||
* @en The texture cube used for the skybox
|
||||
* @zh 使用的立方体贴图
|
||||
*/
|
||||
// @editable
|
||||
// @type(TextureCube)
|
||||
// @tooltip('i18n:skybox.envmap')
|
||||
void setEnvmap(TextureCube *val);
|
||||
TextureCube *getEnvmap() const;
|
||||
|
||||
inline void setEnvmapForJS(TextureCube *val) {
|
||||
_envmapHDR = val;
|
||||
}
|
||||
inline TextureCube *getEnvmapForJS() const {
|
||||
return _envmapHDR;
|
||||
}
|
||||
|
||||
void setRotationAngle(float val);
|
||||
inline float getRotationAngle() const { return _rotationAngle; }
|
||||
|
||||
/**
|
||||
* @en The optional diffusion convolution map used in tandem with IBL
|
||||
* @zh 使用的漫反射卷积图
|
||||
*/
|
||||
// @visible(function (this : SkyboxInfo) {
|
||||
// if (this.useIBL) {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// })
|
||||
// @editable
|
||||
// @readOnly
|
||||
// @type(TextureCube)
|
||||
void setDiffuseMap(TextureCube *val);
|
||||
TextureCube *getDiffuseMap() const;
|
||||
|
||||
void setReflectionMap(TextureCube *val);
|
||||
TextureCube *getReflectionMap() const;
|
||||
|
||||
void setSkyboxMaterial(Material *val);
|
||||
inline Material *getSkyboxMaterial() const { return _editableMaterial; }
|
||||
|
||||
void setMaterialProperty(const ccstd::string &name, const MaterialPropertyVariant &val, index_t passIdx = CC_INVALID_INDEX) const;
|
||||
void updateEnvMap(TextureCube *val);
|
||||
|
||||
void activate(Skybox *resource);
|
||||
|
||||
// cjh JSB need to bind the property, so need to make it public
|
||||
// private:
|
||||
// @serializable
|
||||
// @type(TextureCube)
|
||||
// @formerlySerializedAs('_envmap')
|
||||
IntrusivePtr<TextureCube> _envmapHDR{nullptr};
|
||||
// @serializable
|
||||
// @type(TextureCube)
|
||||
IntrusivePtr<TextureCube> _envmapLDR{nullptr};
|
||||
// @serializable
|
||||
// @type(TextureCube)
|
||||
IntrusivePtr<TextureCube> _diffuseMapHDR{nullptr};
|
||||
// @serializable
|
||||
// @type(TextureCube)
|
||||
IntrusivePtr<TextureCube> _diffuseMapLDR{nullptr};
|
||||
IntrusivePtr<TextureCube> _reflectionHDR{nullptr};
|
||||
IntrusivePtr<TextureCube> _reflectionLDR{nullptr};
|
||||
// @serializable
|
||||
bool _enabled{false};
|
||||
// @serializable
|
||||
bool _useHDR{true};
|
||||
EnvironmentLightingType _envLightingType{EnvironmentLightingType::HEMISPHERE_DIFFUSE};
|
||||
IntrusivePtr<Material> _editableMaterial;
|
||||
float _rotationAngle{0.F};
|
||||
Skybox *_resource{nullptr};
|
||||
};
|
||||
|
||||
class Skybox final {
|
||||
public:
|
||||
Skybox() = default;
|
||||
~Skybox() = default;
|
||||
|
||||
void initialize(const SkyboxInfo &skyboxInfo);
|
||||
|
||||
void setEnvMaps(TextureCube *envmapHDR, TextureCube *envmapLDR);
|
||||
|
||||
void setDiffuseMaps(TextureCube *diffuseMapHDR, TextureCube *diffuseMapLDR);
|
||||
|
||||
void setReflectionMaps(TextureCube *reflectionHDR, TextureCube *reflectionLDR);
|
||||
|
||||
void activate();
|
||||
|
||||
inline Model *getModel() const { return _model.get(); }
|
||||
|
||||
/**
|
||||
* @en Whether activate skybox in the scene
|
||||
* @zh 是否启用天空盒?
|
||||
*/
|
||||
inline bool isEnabled() const { return _enabled; }
|
||||
inline void setEnabled(bool val) {
|
||||
_enabled = val;
|
||||
if (val) {
|
||||
activate();
|
||||
} else {
|
||||
updatePipeline();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @en HDR
|
||||
* @zh 是否启用HDR?
|
||||
*/
|
||||
inline bool isUseHDR() const { return _useHDR; }
|
||||
void setUseHDR(bool val);
|
||||
|
||||
/**
|
||||
* @en Whether use environment lighting
|
||||
* @zh 是否启用环境光照?
|
||||
*/
|
||||
inline bool isUseIBL() const { return _useIBL; }
|
||||
inline void setUseIBL(bool val) {
|
||||
_useIBL = val;
|
||||
updatePipeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Whether use diffuse convolution map lighting
|
||||
* @zh 是否为IBL启用漫反射卷积图?
|
||||
*/
|
||||
inline bool isUseDiffuseMap() const { return _useDiffuseMap; }
|
||||
inline void setUseDiffuseMap(bool val) {
|
||||
_useDiffuseMap = val;
|
||||
setDiffuseMaps(nullptr, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The texture cube used for the skybox
|
||||
* @zh 使用的立方体贴图
|
||||
*/
|
||||
TextureCube *getEnvmap() const;
|
||||
void setEnvmap(TextureCube *val);
|
||||
|
||||
/**
|
||||
* @en Whether enable RGBE data support in skybox shader
|
||||
* @zh 是否需要开启 shader 内的 RGBE 数据支持?
|
||||
*/
|
||||
bool isRGBE() const;
|
||||
|
||||
/**
|
||||
* @en Whether to use offline baked convolutional maps
|
||||
* @zh 是否使用离线烘焙的卷积图?
|
||||
*/
|
||||
bool isUsingConvolutionMap() const;
|
||||
|
||||
/**
|
||||
* @en The texture cube used diffuse convolution map
|
||||
* @zh 使用的漫反射卷积图
|
||||
*/
|
||||
TextureCube *getDiffuseMap() const;
|
||||
void setDiffuseMap(TextureCube *val);
|
||||
void setSkyboxMaterial(Material *skyboxMat);
|
||||
inline Material *getSkyboxMaterial() const { return _material; }
|
||||
/**
|
||||
* @en Set skybox rotate angle
|
||||
* @zh 设置天空盒旋转角度
|
||||
* @param angle @en rotation angle @zh 旋转角度
|
||||
*/
|
||||
void setRotationAngle(float angle);
|
||||
float getRotationAngle() const { return _rotationAngle; };
|
||||
|
||||
TextureCube *getReflectionMap() const;
|
||||
|
||||
private:
|
||||
void updatePipeline() const;
|
||||
void updateGlobalBinding();
|
||||
void updateSubModes() const;
|
||||
|
||||
IntrusivePtr<TextureCube> _envmapLDR;
|
||||
IntrusivePtr<TextureCube> _envmapHDR;
|
||||
IntrusivePtr<TextureCube> _diffuseMapLDR;
|
||||
IntrusivePtr<TextureCube> _diffuseMapHDR;
|
||||
IntrusivePtr<TextureCube> _reflectionHDR;
|
||||
IntrusivePtr<TextureCube> _reflectionLDR;
|
||||
pipeline::GlobalDSManager *_globalDSManager{nullptr};
|
||||
IntrusivePtr<Model> _model;
|
||||
IntrusivePtr<Mesh> _mesh;
|
||||
IntrusivePtr<Material> _material;
|
||||
IntrusivePtr<TextureCube> _default;
|
||||
bool _enabled{false};
|
||||
bool _useIBL{false};
|
||||
bool _useHDR{true};
|
||||
bool _useDiffuseMap{false};
|
||||
bool _activated{false};
|
||||
IntrusivePtr<Material> _editableMaterial;
|
||||
float _rotationAngle{0.F};
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Skybox);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
71
cocos/scene/SphereLight.cpp
Normal file
71
cocos/scene/SphereLight.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/SphereLight.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
SphereLight::SphereLight() {
|
||||
_type = LightType::SPHERE;
|
||||
}
|
||||
|
||||
void SphereLight::initialize() {
|
||||
Light::initialize();
|
||||
|
||||
_size = 0.15F;
|
||||
_range = 1.0F;
|
||||
setLuminance(1700 / Light::nt2lm(_size));
|
||||
_luminanceLDR = 1.0;
|
||||
}
|
||||
|
||||
void SphereLight::update() {
|
||||
if (_node && (_node->getChangedFlags() || _needUpdate)) {
|
||||
_node->updateWorldTransform();
|
||||
_pos = _node->getWorldPosition();
|
||||
_aabb.set(_pos, {_range, _range, _range});
|
||||
_needUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
float SphereLight::getLuminance() const {
|
||||
auto *sceneData = Root::getInstance()->getPipeline()->getPipelineSceneData();
|
||||
auto isHDR = sceneData->isHDR();
|
||||
return isHDR ? _luminanceHDR : _luminanceLDR;
|
||||
}
|
||||
|
||||
void SphereLight::setLuminance(float value) {
|
||||
auto *sceneData = Root::getInstance()->getPipeline()->getPipelineSceneData();
|
||||
auto isHDR = sceneData->isHDR();
|
||||
if (isHDR) {
|
||||
_luminanceHDR = value;
|
||||
} else {
|
||||
_luminanceLDR = value;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
78
cocos/scene/SphereLight.h
Normal file
78
cocos/scene/SphereLight.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/geometry/AABB.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "scene/Light.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class SphereLight final : public Light {
|
||||
public:
|
||||
SphereLight();
|
||||
~SphereLight() override = default;
|
||||
|
||||
void initialize() override;
|
||||
void update() override;
|
||||
|
||||
inline const Vec3 &getPosition() const { return _pos; }
|
||||
inline void setPosition(const Vec3 &pos) { _pos = pos; }
|
||||
|
||||
inline float getSize() const { return _size; }
|
||||
inline void setSize(float size) { _size = size; }
|
||||
|
||||
inline float getRange() const { return _range; }
|
||||
inline void setRange(float range) {
|
||||
_range = range;
|
||||
_needUpdate = true;
|
||||
}
|
||||
|
||||
float getLuminance() const;
|
||||
void setLuminance(float);
|
||||
|
||||
inline void setLuminanceHDR(float illum) { _luminanceHDR = illum; }
|
||||
inline float getLuminanceHDR() const { return _luminanceHDR; }
|
||||
|
||||
inline void setLuminanceLDR(float illum) { _luminanceLDR = illum; }
|
||||
inline float getLuminanceLDR() const { return _luminanceLDR; }
|
||||
|
||||
inline const geometry::AABB &getAABB() const { return _aabb; }
|
||||
|
||||
private:
|
||||
bool _needUpdate{false};
|
||||
float _luminanceHDR{0.F};
|
||||
float _luminanceLDR{0.F};
|
||||
float _range{0.F};
|
||||
float _size{0.F};
|
||||
Vec3 _pos;
|
||||
geometry::AABB _aabb;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(SphereLight);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
97
cocos/scene/SpotLight.cpp
Normal file
97
cocos/scene/SpotLight.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/SpotLight.h"
|
||||
#include <cmath>
|
||||
#include "core/Root.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "math/Math.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/RenderPipeline.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
SpotLight::SpotLight() {
|
||||
_type = LightType::SPOT;
|
||||
_aabb = ccnew geometry::AABB();
|
||||
_aabb->addRef();
|
||||
_frustum = ccnew geometry::Frustum();
|
||||
_frustum->addRef();
|
||||
}
|
||||
|
||||
SpotLight::~SpotLight() {
|
||||
_aabb->release();
|
||||
_frustum->release();
|
||||
}
|
||||
|
||||
void SpotLight::initialize() {
|
||||
Light::initialize();
|
||||
|
||||
_size = 0.15F;
|
||||
setLuminance(1700 / Light::nt2lm(_size));
|
||||
setLuminanceLDR(1.F);
|
||||
_range = cos(math::PI / 6);
|
||||
_dir.set(1.0, -1.0, -1.0);
|
||||
}
|
||||
|
||||
float SpotLight::getLuminance() const {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
return isHDR ? _luminanceHDR : _luminanceLDR;
|
||||
}
|
||||
|
||||
void SpotLight::setLuminance(float value) {
|
||||
const bool isHDR = Root::getInstance()->getPipeline()->getPipelineSceneData()->isHDR();
|
||||
if (isHDR) {
|
||||
setLuminanceHDR(value);
|
||||
} else {
|
||||
setLuminanceLDR(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SpotLight::update() {
|
||||
if (_node && (_node->getChangedFlags() || _needUpdate)) {
|
||||
Mat4 matView;
|
||||
Mat4 matProj;
|
||||
Mat4 matViewProj;
|
||||
Mat4 matViewProjInv;
|
||||
_pos = _node->getWorldPosition();
|
||||
_dir = _forward;
|
||||
_dir.transformQuat(_node->getWorldRotation());
|
||||
_dir.normalize();
|
||||
_aabb->set(_pos, {_range, _range, _range});
|
||||
matView = _node->getWorldRT();
|
||||
matView.inverse();
|
||||
|
||||
Mat4::createPerspective(_angle, 1.0F, 0.001F, _range, &matProj);
|
||||
|
||||
Mat4::multiply(matProj, matView, &matViewProj);
|
||||
|
||||
_frustum->update(matViewProj, matViewProjInv);
|
||||
|
||||
_needUpdate = false;
|
||||
}
|
||||
}
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
114
cocos/scene/SpotLight.h
Normal file
114
cocos/scene/SpotLight.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/geometry/AABB.h"
|
||||
#include "core/geometry/Frustum.h"
|
||||
#include "scene/Light.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
class SpotLight final : public Light {
|
||||
public:
|
||||
SpotLight();
|
||||
~SpotLight() override;
|
||||
|
||||
void initialize() override;
|
||||
void update() override;
|
||||
|
||||
inline const Vec3 &getPosition() const { return _pos; }
|
||||
|
||||
inline float getSize() const { return _size; }
|
||||
inline void setSize(float size) { _size = size; }
|
||||
|
||||
inline float getRange() const { return _range; }
|
||||
inline void setRange(float range) {
|
||||
_range = range;
|
||||
_needUpdate = true;
|
||||
}
|
||||
|
||||
inline void setLuminanceHDR(float value) { _luminanceHDR = value; }
|
||||
inline void setLuminanceLDR(float value) { _luminanceLDR = value; }
|
||||
|
||||
float getLuminance() const;
|
||||
void setLuminance(float value);
|
||||
|
||||
inline const Vec3 &getDirection() const { return _dir; }
|
||||
|
||||
inline float getSpotAngle() const { return _spotAngle; }
|
||||
inline void setSpotAngle(float val) {
|
||||
_angle = val;
|
||||
_spotAngle = cos(val * 0.5F);
|
||||
_needUpdate = true;
|
||||
}
|
||||
|
||||
inline float getAngle() const { return _angle; }
|
||||
|
||||
inline const geometry::AABB &getAABB() const { return *_aabb; }
|
||||
|
||||
inline const geometry::Frustum &getFrustum() const { return *_frustum; }
|
||||
inline float getLuminanceHDR() const { return _luminanceHDR; }
|
||||
inline float getLuminanceLDR() const { return _luminanceLDR; }
|
||||
|
||||
inline void setFrustum(const geometry::Frustum &frustum) { *_frustum = frustum; }
|
||||
|
||||
inline void setShadowEnabled(bool enabled) { _shadowEnabled = enabled; }
|
||||
inline bool isShadowEnabled() const { return _shadowEnabled; }
|
||||
|
||||
inline float getShadowPcf() const { return _shadowPcf; }
|
||||
inline void setShadowPcf(float pcf) { _shadowPcf = pcf; }
|
||||
|
||||
inline void setShadowBias(float bias) { _shadowBias = bias; }
|
||||
inline float getShadowBias() const { return _shadowBias; }
|
||||
|
||||
inline void setShadowNormalBias(float normalBias) { _shadowNormalBias = normalBias; }
|
||||
inline float getShadowNormalBias() const { return _shadowNormalBias; }
|
||||
|
||||
private:
|
||||
bool _needUpdate{false};
|
||||
float _luminanceHDR{0.F};
|
||||
float _luminanceLDR{0.F};
|
||||
float _range{0.F};
|
||||
float _size{0.F};
|
||||
float _angle{0.F};
|
||||
float _spotAngle{0.F};
|
||||
Vec3 _dir;
|
||||
Vec3 _pos;
|
||||
geometry::AABB *_aabb{nullptr};
|
||||
geometry::Frustum *_frustum{nullptr};
|
||||
|
||||
// shadow info
|
||||
bool _shadowEnabled{false};
|
||||
// TODO(minggo): use PCTFType instead.
|
||||
float _shadowPcf{0.0F};
|
||||
float _shadowBias{0.00001F};
|
||||
float _shadowNormalBias{0.0F};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(SpotLight);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
406
cocos/scene/SubModel.cpp
Normal file
406
cocos/scene/SubModel.cpp
Normal file
@@ -0,0 +1,406 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "scene/SubModel.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "pipeline/Define.h"
|
||||
#include "pipeline/InstancedBuffer.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
|
||||
#include "renderer/pipeline/forward/ForwardPipeline.h"
|
||||
#include "scene/Model.h"
|
||||
#include "scene/Pass.h"
|
||||
#include "scene/Shadow.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
|
||||
const ccstd::string INST_MAT_WORLD = "a_matWorld0";
|
||||
const ccstd::string INST_SH = "a_sh_linear_const_r";
|
||||
|
||||
cc::TypedArray getTypedArrayConstructor(const cc::gfx::FormatInfo &info, cc::ArrayBuffer *buffer, uint32_t byteOffset, uint32_t length) {
|
||||
const uint32_t stride = info.size / info.count;
|
||||
switch (info.type) {
|
||||
case cc::gfx::FormatType::UNORM:
|
||||
case cc::gfx::FormatType::UINT: {
|
||||
switch (stride) {
|
||||
case 1: return cc::Uint8Array(buffer, byteOffset, length);
|
||||
case 2: return cc::Uint16Array(buffer, byteOffset, length);
|
||||
case 4: return cc::Uint32Array(buffer, byteOffset, length);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cc::gfx::FormatType::SNORM:
|
||||
case cc::gfx::FormatType::INT: {
|
||||
switch (stride) {
|
||||
case 1: return cc::Int8Array(buffer, byteOffset, length);
|
||||
case 2: return cc::Int16Array(buffer, byteOffset, length);
|
||||
case 4: return cc::Int32Array(buffer, byteOffset, length);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cc::gfx::FormatType::FLOAT: {
|
||||
return cc::Float32Array(buffer, byteOffset, length);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return cc::Float32Array(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
SubModel::SubModel() {
|
||||
_id = generateId();
|
||||
}
|
||||
|
||||
const static uint32_t MAX_PASS_COUNT = 8;
|
||||
|
||||
void SubModel::update() {
|
||||
const auto &passes = *_passes;
|
||||
for (Pass *pass : passes) {
|
||||
pass->update();
|
||||
}
|
||||
_descriptorSet->update();
|
||||
|
||||
if (_worldBoundDescriptorSet) {
|
||||
_worldBoundDescriptorSet->update();
|
||||
}
|
||||
}
|
||||
|
||||
void SubModel::setPasses(const SharedPassArray &pPasses) {
|
||||
if (!pPasses || pPasses->size() > MAX_PASS_COUNT) {
|
||||
debug::errorID(12004, MAX_PASS_COUNT);
|
||||
return;
|
||||
}
|
||||
|
||||
_passes = pPasses;
|
||||
flushPassInfo();
|
||||
|
||||
const auto &passes = *_passes;
|
||||
// DS layout might change too
|
||||
if (_descriptorSet) {
|
||||
_descriptorSet->destroy();
|
||||
gfx::DescriptorSetInfo dsInfo;
|
||||
dsInfo.layout = passes[0]->getLocalSetLayout();
|
||||
_descriptorSet = _device->createDescriptorSet(dsInfo);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Shader *SubModel::getShader(uint32_t index) const {
|
||||
if (index >= _shaders.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _shaders[index];
|
||||
}
|
||||
|
||||
Pass *SubModel::getPass(uint32_t index) const {
|
||||
auto &passes = *_passes;
|
||||
if (index >= passes.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return passes[index];
|
||||
}
|
||||
|
||||
void SubModel::initialize(RenderingSubMesh *subMesh, const SharedPassArray &pPasses, const ccstd::vector<IMacroPatch> &patches) {
|
||||
_device = Root::getInstance()->getDevice();
|
||||
CC_ASSERT(!pPasses->empty());
|
||||
gfx::DescriptorSetInfo dsInfo;
|
||||
dsInfo.layout = (*pPasses)[0]->getLocalSetLayout();
|
||||
_inputAssembler = _device->createInputAssembler(subMesh->getIaInfo());
|
||||
_descriptorSet = _device->createDescriptorSet(dsInfo);
|
||||
|
||||
const auto *pipeline = Root::getInstance()->getPipeline();
|
||||
const auto *occlusionPass = pipeline->getPipelineSceneData()->getOcclusionQueryPass();
|
||||
if (occlusionPass) {
|
||||
cc::gfx::DescriptorSetInfo occlusionDSInfo;
|
||||
occlusionDSInfo.layout = occlusionPass->getLocalSetLayout();
|
||||
_worldBoundDescriptorSet = _device->createDescriptorSet(occlusionDSInfo);
|
||||
}
|
||||
|
||||
_subMesh = subMesh;
|
||||
ccstd::vector<IMacroPatch> tmp = patches;
|
||||
std::sort(tmp.begin(), tmp.end(), IMacroPatch::compare);
|
||||
_patches = tmp;
|
||||
_passes = pPasses;
|
||||
|
||||
flushPassInfo();
|
||||
|
||||
const auto &passes = *_passes;
|
||||
_priority = pipeline::RenderPriority::DEFAULT;
|
||||
|
||||
// initialize resources for reflection material
|
||||
if (passes[0]->getPhase() == pipeline::getPhaseID("reflection")) {
|
||||
const auto *mainWindow = Root::getInstance()->getMainWindow();
|
||||
uint32_t texWidth = mainWindow->getWidth();
|
||||
uint32_t texHeight = mainWindow->getHeight();
|
||||
const uint32_t minSize = 512;
|
||||
if (texHeight < texWidth) {
|
||||
texWidth = minSize * texWidth / texHeight;
|
||||
texHeight = minSize;
|
||||
} else {
|
||||
texWidth = minSize;
|
||||
texHeight = minSize * texHeight / texWidth;
|
||||
}
|
||||
_reflectionTex = _device->createTexture(gfx::TextureInfo{
|
||||
gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::STORAGE | gfx::TextureUsageBit::TRANSFER_SRC | gfx::TextureUsageBit::SAMPLED,
|
||||
gfx::Format::RGBA8,
|
||||
texWidth,
|
||||
texHeight,
|
||||
});
|
||||
_descriptorSet->bindTexture(pipeline::REFLECTIONTEXTURE::BINDING, _reflectionTex);
|
||||
|
||||
const gfx::SamplerInfo samplerInfo{
|
||||
gfx::Filter::LINEAR,
|
||||
gfx::Filter::LINEAR,
|
||||
gfx::Filter::NONE,
|
||||
gfx::Address::CLAMP,
|
||||
gfx::Address::CLAMP,
|
||||
gfx::Address::CLAMP,
|
||||
};
|
||||
_reflectionSampler = _device->getSampler(samplerInfo);
|
||||
_descriptorSet->bindSampler(pipeline::REFLECTIONTEXTURE::BINDING, _reflectionSampler);
|
||||
_descriptorSet->bindTexture(pipeline::REFLECTIONSTORAGE::BINDING, _reflectionTex);
|
||||
}
|
||||
}
|
||||
|
||||
void SubModel::destroy() {
|
||||
CC_SAFE_DESTROY_NULL(_descriptorSet);
|
||||
CC_SAFE_DESTROY_NULL(_inputAssembler);
|
||||
CC_SAFE_DESTROY_NULL(_worldBoundDescriptorSet);
|
||||
|
||||
_priority = pipeline::RenderPriority::DEFAULT;
|
||||
|
||||
_patches.clear();
|
||||
_globalPatches.clear();
|
||||
_subMesh = nullptr;
|
||||
_passes.reset();
|
||||
_shaders.clear();
|
||||
|
||||
CC_SAFE_DESTROY_NULL(_reflectionTex);
|
||||
_reflectionSampler = nullptr;
|
||||
}
|
||||
|
||||
void SubModel::onPipelineStateChanged() {
|
||||
const auto *pipeline = Root::getInstance()->getPipeline();
|
||||
ccstd::vector<IMacroPatch> pipelinePatches(pipeline->getMacros().begin(), pipeline->getMacros().end());
|
||||
ccstd::vector<IMacroPatch> globalPatches(_globalPatches.begin(), _globalPatches.end());
|
||||
if (pipelinePatches.empty() && globalPatches.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(pipelinePatches.begin(), pipelinePatches.end(), IMacroPatch::compare);
|
||||
std::sort(globalPatches.begin(), globalPatches.end(), IMacroPatch::compare);
|
||||
if (std::equal(std::begin(pipelinePatches), std::end(pipelinePatches), std::begin(globalPatches), std::end(globalPatches))) {
|
||||
return;
|
||||
}
|
||||
_globalPatches = pipeline->getMacros();
|
||||
|
||||
const auto &passes = *_passes;
|
||||
if (passes.empty()) return;
|
||||
|
||||
for (Pass *pass : passes) {
|
||||
pass->beginChangeStatesSilently();
|
||||
pass->tryCompile(); // force update shaders
|
||||
pass->endChangeStatesSilently();
|
||||
}
|
||||
flushPassInfo();
|
||||
}
|
||||
|
||||
void SubModel::onMacroPatchesStateChanged(const ccstd::vector<IMacroPatch> &patches) {
|
||||
if (patches.empty() && _patches.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccstd::vector<IMacroPatch> tmp = patches;
|
||||
std::sort(tmp.begin(), tmp.end(), IMacroPatch::compare);
|
||||
if (std::equal(std::begin(tmp), std::end(tmp), std::begin(_patches), std::end(_patches))) {
|
||||
return;
|
||||
}
|
||||
_patches = tmp;
|
||||
const auto &passes = *_passes;
|
||||
if (passes.empty()) return;
|
||||
for (Pass *pass : passes) {
|
||||
pass->beginChangeStatesSilently();
|
||||
pass->tryCompile(); // force update shaders
|
||||
pass->endChangeStatesSilently();
|
||||
}
|
||||
flushPassInfo();
|
||||
}
|
||||
|
||||
void SubModel::onGeometryChanged() {
|
||||
if (!_subMesh) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update draw info
|
||||
const auto &drawInfo = _subMesh->getDrawInfo();
|
||||
if (drawInfo.has_value()) {
|
||||
_inputAssembler->setDrawInfo(drawInfo.value());
|
||||
}
|
||||
}
|
||||
|
||||
void SubModel::updateInstancedAttributes(const ccstd::vector<gfx::Attribute> &attributes) {
|
||||
auto *pass = getPass(0);
|
||||
_instancedWorldMatrixIndex = -1;
|
||||
_instancedSHIndex = -1;
|
||||
if (!pass->getDevice()->hasFeature(gfx::Feature::INSTANCED_ARRAYS)) return;
|
||||
// free old data
|
||||
|
||||
uint32_t size = 0;
|
||||
for (const gfx::Attribute &attribute : attributes) {
|
||||
if (!attribute.isInstanced) continue;
|
||||
size += gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(attribute.format)].size;
|
||||
}
|
||||
auto &attrs = _instancedAttributeBlock;
|
||||
attrs.buffer = Uint8Array(size);
|
||||
attrs.views.clear();
|
||||
attrs.attributes.clear();
|
||||
attrs.views.reserve(attributes.size());
|
||||
attrs.attributes.reserve(attributes.size());
|
||||
|
||||
uint32_t offset = 0;
|
||||
|
||||
for (const gfx::Attribute &attribute : attributes) {
|
||||
if (!attribute.isInstanced) continue;
|
||||
gfx::Attribute attr;
|
||||
attr.format = attribute.format;
|
||||
attr.name = attribute.name;
|
||||
attr.isNormalized = attribute.isNormalized;
|
||||
attr.location = attribute.location;
|
||||
attrs.attributes.emplace_back(attr);
|
||||
const auto &info = gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(attribute.format)];
|
||||
auto *buffer = attrs.buffer.buffer();
|
||||
auto typeViewArray = getTypedArrayConstructor(info, buffer, offset, info.count);
|
||||
attrs.views.emplace_back(typeViewArray);
|
||||
offset += info.size;
|
||||
}
|
||||
if (pass->getBatchingScheme() == BatchingSchemes::INSTANCING) {
|
||||
pass->getInstancedBuffer()->destroy();
|
||||
}
|
||||
_instancedWorldMatrixIndex = getInstancedAttributeIndex(INST_MAT_WORLD);
|
||||
_instancedSHIndex = getInstancedAttributeIndex(INST_SH);
|
||||
}
|
||||
|
||||
void SubModel::updateInstancedWorldMatrix(const Mat4 &mat, int32_t idx) {
|
||||
auto &attrs = _instancedAttributeBlock.views;
|
||||
auto &v1 = ccstd::get<Float32Array>(attrs[idx]);
|
||||
auto &v2 = ccstd::get<Float32Array>(attrs[idx + 1]);
|
||||
auto &v3 = ccstd::get<Float32Array>(attrs[idx + +2]);
|
||||
const uint32_t copyBytes = sizeof(float) * 3;
|
||||
auto *buffer = const_cast<uint8_t *>(v1.buffer()->getData());
|
||||
|
||||
uint8_t *dst = buffer + v1.byteOffset();
|
||||
memcpy(dst, mat.m, copyBytes);
|
||||
v1[3] = mat.m[12];
|
||||
|
||||
dst = buffer + v2.byteOffset();
|
||||
memcpy(dst, mat.m + 4, copyBytes);
|
||||
v2[3] = mat.m[13];
|
||||
|
||||
dst = buffer + v3.byteOffset();
|
||||
memcpy(dst, mat.m + 8, copyBytes);
|
||||
v3[3] = mat.m[14];
|
||||
}
|
||||
|
||||
void SubModel::updateInstancedSH(const Float32Array &data, int32_t idx) {
|
||||
auto &attrs = _instancedAttributeBlock.views;
|
||||
const auto count = (pipeline::UBOSH::SH_QUADRATIC_R_OFFSET - pipeline::UBOSH::SH_LINEAR_CONST_R_OFFSET) / 4;
|
||||
auto offset = 0;
|
||||
|
||||
for (auto i = idx; i < idx + count; i++) {
|
||||
auto &attr = ccstd::get<Float32Array>(attrs[i]);
|
||||
for (auto k = 0; k < 4; k++) {
|
||||
attr[k] = data[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubModel::flushPassInfo() {
|
||||
const auto &passes = *_passes;
|
||||
if (passes.empty()) return;
|
||||
if (!_shaders.empty()) {
|
||||
_shaders.clear();
|
||||
}
|
||||
_shaders.resize(passes.size());
|
||||
for (size_t i = 0; i < passes.size(); ++i) {
|
||||
_shaders[i] = passes[i]->getShaderVariant(_patches);
|
||||
}
|
||||
}
|
||||
|
||||
void SubModel::setSubMesh(RenderingSubMesh *subMesh) {
|
||||
const auto &passes = *_passes;
|
||||
_inputAssembler->destroy();
|
||||
_inputAssembler->initialize(subMesh->getIaInfo());
|
||||
_subMesh = subMesh;
|
||||
}
|
||||
|
||||
void SubModel::setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteLength) {
|
||||
const auto &attributes = _instancedAttributeBlock.attributes;
|
||||
auto &views = _instancedAttributeBlock.views;
|
||||
for (size_t i = 0, len = attributes.size(); i < len; ++i) {
|
||||
const auto &attribute = attributes[i];
|
||||
if (attribute.name == name) {
|
||||
const auto &info = gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(attribute.format)];
|
||||
switch (info.type) {
|
||||
case gfx::FormatType::NONE:
|
||||
case gfx::FormatType::UNORM:
|
||||
case gfx::FormatType::SNORM:
|
||||
case gfx::FormatType::UINT:
|
||||
case gfx::FormatType::INT: {
|
||||
CC_ABORT();
|
||||
} break;
|
||||
case gfx::FormatType::FLOAT:
|
||||
case gfx::FormatType::UFLOAT: {
|
||||
CC_ASSERT(ccstd::holds_alternative<Float32Array>(views[i]));
|
||||
auto &view = ccstd::get<Float32Array>(views[i]);
|
||||
auto *dstData = reinterpret_cast<float *>(view.buffer()->getData() + view.byteOffset());
|
||||
CC_ASSERT(byteLength <= view.byteLength());
|
||||
memcpy(dstData, value, byteLength);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t SubModel::getInstancedAttributeIndex(const ccstd::string &name) const {
|
||||
const auto &attributes = _instancedAttributeBlock.attributes;
|
||||
for (index_t i = 0; i < static_cast<index_t>(attributes.size()); ++i) {
|
||||
if (attributes[i].name == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return CC_INVALID_INDEX;
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
136
cocos/scene/SubModel.h
Normal file
136
cocos/scene/SubModel.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "base/Ptr.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "core/assets/RenderingSubMesh.h"
|
||||
#include "renderer/gfx-base/GFXDescriptorSet.h"
|
||||
#include "renderer/gfx-base/GFXInputAssembler.h"
|
||||
#include "renderer/gfx-base/GFXShader.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
#include "scene/Define.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
class Pass;
|
||||
struct InstancedAttributeBlock {
|
||||
Uint8Array buffer;
|
||||
ccstd::vector<TypedArray> views;
|
||||
ccstd::vector<gfx::Attribute> attributes;
|
||||
};
|
||||
|
||||
using SharedPassArray = std::shared_ptr<ccstd::vector<IntrusivePtr<Pass>>>;
|
||||
|
||||
class SubModel : public RefCounted {
|
||||
public:
|
||||
SubModel();
|
||||
~SubModel() override = default;
|
||||
|
||||
void update();
|
||||
|
||||
gfx::Shader *getShader(uint32_t) const;
|
||||
Pass *getPass(uint32_t) const;
|
||||
|
||||
inline void setWorldBoundDescriptorSet(gfx::DescriptorSet *descriptorSet) { _worldBoundDescriptorSet = descriptorSet; }
|
||||
inline void setDescriptorSet(gfx::DescriptorSet *descriptorSet) { _descriptorSet = descriptorSet; }
|
||||
inline void setInputAssembler(gfx::InputAssembler *ia) { _inputAssembler = ia; }
|
||||
inline void setShaders(const ccstd::vector<IntrusivePtr<gfx::Shader>> &shaders) { _shaders = shaders; }
|
||||
void setPasses(const SharedPassArray &passes);
|
||||
inline void setPriority(pipeline::RenderPriority priority) { _priority = priority; }
|
||||
inline void setOwner(Model *model) { _owner = model; }
|
||||
void setSubMesh(RenderingSubMesh *subMesh);
|
||||
inline void setInstancedWorldMatrixIndex(int32_t worldMatrixIndex) { _instancedWorldMatrixIndex = worldMatrixIndex; }
|
||||
inline void setInstancedSHIndex(int32_t index) { _instancedSHIndex = index; }
|
||||
void setInstancedAttribute(const ccstd::string &name, const float *value, uint32_t byteLength);
|
||||
|
||||
inline gfx::DescriptorSet *getDescriptorSet() const { return _descriptorSet; }
|
||||
inline gfx::DescriptorSet *getWorldBoundDescriptorSet() const { return _worldBoundDescriptorSet; }
|
||||
inline gfx::InputAssembler *getInputAssembler() const { return _inputAssembler; }
|
||||
inline const ccstd::vector<IntrusivePtr<gfx::Shader>> &getShaders() const { return _shaders; }
|
||||
inline const SharedPassArray &getPasses() const { return _passes; }
|
||||
inline const ccstd::vector<IMacroPatch> &getPatches() const { return _patches; }
|
||||
inline pipeline::RenderPriority getPriority() const { return _priority; }
|
||||
inline RenderingSubMesh *getSubMesh() const { return _subMesh; }
|
||||
inline Model *getOwner() const { return _owner; }
|
||||
inline uint32_t getId() const { return _id; }
|
||||
inline InstancedAttributeBlock &getInstancedAttributeBlock() { return _instancedAttributeBlock; }
|
||||
inline int32_t getInstancedWorldMatrixIndex() const { return _instancedWorldMatrixIndex; }
|
||||
inline int32_t getInstancedSHIndex() const { return _instancedSHIndex; }
|
||||
int32_t getInstancedAttributeIndex(const ccstd::string &name) const;
|
||||
|
||||
void initialize(RenderingSubMesh *subMesh, const SharedPassArray &passes, const ccstd::vector<IMacroPatch> &patches);
|
||||
void destroy();
|
||||
void onPipelineStateChanged();
|
||||
void onMacroPatchesStateChanged(const ccstd::vector<IMacroPatch> &patches);
|
||||
void onGeometryChanged();
|
||||
void updateInstancedAttributes(const ccstd::vector<gfx::Attribute> &attributes);
|
||||
void updateInstancedWorldMatrix(const Mat4 &mat, int32_t idx);
|
||||
void updateInstancedSH(const Float32Array &data, int32_t idx);
|
||||
inline int32_t getReflectionProbeType() const { return _reflectionProbeType; }
|
||||
void setReflectionProbeType(int32_t val) { _reflectionProbeType = val; }
|
||||
|
||||
protected:
|
||||
void flushPassInfo();
|
||||
|
||||
pipeline::RenderPriority _priority{pipeline::RenderPriority::DEFAULT};
|
||||
|
||||
int32_t _id{-1};
|
||||
int32_t _instancedWorldMatrixIndex{-1};
|
||||
int32_t _instancedSHIndex{-1};
|
||||
|
||||
gfx::Device *_device{nullptr};
|
||||
Model *_owner{nullptr};
|
||||
gfx::Sampler *_reflectionSampler{nullptr};
|
||||
|
||||
IntrusivePtr<gfx::InputAssembler> _inputAssembler;
|
||||
IntrusivePtr<gfx::DescriptorSet> _descriptorSet;
|
||||
IntrusivePtr<gfx::DescriptorSet> _worldBoundDescriptorSet;
|
||||
IntrusivePtr<gfx::Texture> _reflectionTex;
|
||||
IntrusivePtr<RenderingSubMesh> _subMesh;
|
||||
|
||||
InstancedAttributeBlock _instancedAttributeBlock{};
|
||||
MacroRecord _globalPatches;
|
||||
|
||||
ccstd::vector<IMacroPatch> _patches;
|
||||
ccstd::vector<IntrusivePtr<gfx::Shader>> _shaders;
|
||||
|
||||
SharedPassArray _passes;
|
||||
|
||||
int32_t _reflectionProbeType{0};
|
||||
|
||||
private:
|
||||
static inline int32_t generateId() {
|
||||
static int32_t generator = 0;
|
||||
return generator++;
|
||||
}
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(SubModel);
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
} // namespace cc
|
||||
Reference in New Issue
Block a user