Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add reflection probe #17388

Merged
merged 9 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cocos/rendering/custom/framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import { RenderWindow } from '../../render-scene/core/render-window';
import { supportsR32FloatTexture } from '../define';
import { Format } from '../../gfx/base/define';

export { packRGBE } from '../../core/math/color';

//-----------------------------------------------------------------
// Editor preview begin
//-----------------------------------------------------------------
Expand Down
90 changes: 78 additions & 12 deletions editor/assets/default_renderpipeline/builtin-pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ if (rendering) {
// Internal cached resources
private readonly _clearColor = new Color(0, 0, 0, 1);
private readonly _clearColorTransparentBlack = new Color(0, 0, 0, 0);
private readonly _reflectionProbeClearColor = new Vec3(0, 0, 0);
private readonly _viewport = new Viewport();
private readonly _configs = new PipelineConfigs();
private readonly _cameraConfigs = new CameraConfigs();
Expand Down Expand Up @@ -717,7 +718,7 @@ if (rendering) {
this.forwardLighting.addSpotlightShadowPasses(ppl, camera, this._configs.mobileMaxSpotLightShadowMaps);
}

// this._tryAddReflectionProbePasses(ppl, id, mainLight, camera.scene);
this._tryAddReflectionProbePasses(ppl, id, mainLight, camera.scene);

// Forward Lighting
let lastPass: rendering.BasicRenderPassBuilder;
Expand Down Expand Up @@ -1386,6 +1387,62 @@ if (rendering) {
return pass;
}

private _buildReflectionProbePass(
pass: rendering.BasicRenderPassBuilder,
id: number,
camera: renderer.scene.Camera,
colorName: string,
depthStencilName: string,
mainLight: renderer.scene.DirectionalLight | null,
scene: renderer.RenderScene | null = null,
): void {
// set viewport
const colorStoreOp = this._cameraConfigs.enableMSAA ? StoreOp.DISCARD : StoreOp.STORE;

// bind output render target
if (forwardNeedClearColor(camera)) {
this._reflectionProbeClearColor.x = camera.clearColor.x;
this._reflectionProbeClearColor.y = camera.clearColor.y;
this._reflectionProbeClearColor.z = camera.clearColor.z;
const clearColor = rendering.packRGBE(this._reflectionProbeClearColor);
this._clearColor.x = clearColor.x;
this._clearColor.y = clearColor.y;
this._clearColor.z = clearColor.z;
this._clearColor.w = clearColor.w;
pass.addRenderTarget(colorName, LoadOp.CLEAR, colorStoreOp, this._clearColor);
} else {
pass.addRenderTarget(colorName, LoadOp.LOAD, colorStoreOp);
}

// bind depth stencil buffer
if (camera.clearFlag & ClearFlagBit.DEPTH_STENCIL) {
pass.addDepthStencil(
depthStencilName,
LoadOp.CLEAR,
StoreOp.DISCARD,
camera.clearDepth,
camera.clearStencil,
camera.clearFlag & ClearFlagBit.DEPTH_STENCIL,
);
} else {
pass.addDepthStencil(depthStencilName, LoadOp.LOAD, StoreOp.DISCARD);
}

// Set shadow map if enabled
if (this._cameraConfigs.enableMainLightShadowMap) {
pass.addTexture(`ShadowMap${id}`, 'cc_shadowMap');
}

// TODO(zhouzhenglong): Separate OPAQUE and MASK queue

// add opaque and mask queue
pass.addQueue(QueueHint.NONE, 'reflect-map') // Currently we put OPAQUE and MASK into one queue, so QueueHint is NONE
.addScene(camera,
SceneFlags.OPAQUE | SceneFlags.MASK | SceneFlags.REFLECTION_PROBE,
mainLight || undefined,
scene ? scene : undefined);
}

private _tryAddReflectionProbePasses(ppl: rendering.BasicPipeline, id: number,
mainLight: renderer.scene.DirectionalLight | null,
scene: renderer.RenderScene | null,
Expand Down Expand Up @@ -1414,18 +1471,27 @@ if (rendering) {

// Rendering
const probePass = ppl.addRenderPass(width, height, 'default');
probePass.name = `PlanarProbe${probeID}`;
this._viewport.left = 0;
this._viewport.top = 0;
this._viewport.width = width;
this._viewport.height = height;
this._buildForwardMainLightPass(probePass, id, probe.camera,
colorName, depthStencilName, StoreOp.DISCARD, mainLight, scene);
probePass.name = `PlanarReflectionProbe${probeID}`;
this._buildReflectionProbePass(probePass, id, probe.camera,
colorName, depthStencilName, mainLight, scene);
} else if (EDITOR) {
// for (let faceIdx = 0; faceIdx < probe.bakedCubeTextures.length; faceIdx++) {
// probe.updateCameraDir(faceIdx);
// buildReflectionProbeRes(ppl, probe, probe.bakedCubeTextures[faceIdx].window!, faceIdx);
// }
for (let faceIdx = 0; faceIdx < probe.bakedCubeTextures.length; faceIdx++) {
probe.updateCameraDir(faceIdx);
const window: renderer.RenderWindow = probe.bakedCubeTextures[faceIdx].window!;
const colorName = `CubeProbeRT${probeID}${faceIdx}`;
const depthStencilName = `CubeProbeDS${probeID}${faceIdx}`;
// ProbeResource
ppl.addRenderWindow(colorName,
this._cameraConfigs.radianceFormat, width, height, window);
ppl.addDepthStencil(depthStencilName,
gfx.Format.DEPTH_STENCIL, width, height, ResourceResidency.MEMORYLESS);

// Rendering
const probePass = ppl.addRenderPass(width, height, 'default');
probePass.name = `CubeProbe${probeID}${faceIdx}`;
this._buildReflectionProbePass(probePass, id, probe.camera,
colorName, depthStencilName, mainLight, scene);
}
probe.needRender = false;
}
++probeID;
Expand Down
8 changes: 5 additions & 3 deletions native/cocos/renderer/pipeline/custom/NativePipelineTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ struct ProbeHelperQueue {

void removeMacro() const;

static uint32_t getPassIndexFromLayout(const IntrusivePtr<scene::SubModel>& subModel, LayoutGraphData::vertex_descriptor phaseLayoutId);
static int32_t getPassIndexFromLayout(const IntrusivePtr<scene::SubModel>& subModel, LayoutGraphData::vertex_descriptor phaseLayoutId);

void applyMacro(const LayoutGraphData &lg, const scene::Model& model, LayoutGraphData::vertex_descriptor probeLayoutId);

Expand Down Expand Up @@ -1277,11 +1277,12 @@ struct FrustumCullingKey {
const scene::Light* light{nullptr};
uint32_t lightLevel{0xFFFFFFFF};
bool castShadow{false};
bool probePass{false};
};

inline bool operator==(const FrustumCullingKey& lhs, const FrustumCullingKey& rhs) noexcept {
return std::forward_as_tuple(lhs.camera, lhs.probe, lhs.light, lhs.lightLevel, lhs.castShadow) ==
std::forward_as_tuple(rhs.camera, rhs.probe, rhs.light, rhs.lightLevel, rhs.castShadow);
return std::forward_as_tuple(lhs.camera, lhs.probe, lhs.light, lhs.lightLevel, lhs.castShadow, lhs.probePass) ==
std::forward_as_tuple(rhs.camera, rhs.probe, rhs.light, rhs.lightLevel, rhs.castShadow, rhs.probePass);
}

inline bool operator!=(const FrustumCullingKey& lhs, const FrustumCullingKey& rhs) noexcept {
Expand Down Expand Up @@ -1742,6 +1743,7 @@ inline hash_t hash<cc::render::FrustumCullingKey>::operator()(const cc::render::
hash_combine(seed, val.light);
hash_combine(seed, val.lightLevel);
hash_combine(seed, val.castShadow);
hash_combine(seed, val.probePass);
return seed;
}

Expand Down
5 changes: 2 additions & 3 deletions native/cocos/renderer/pipeline/custom/NativeRenderQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
****************************************************************************/

#include <algorithm>
#include <iterator>
#include "NativePipelineTypes.h"
#include "cocos/renderer/pipeline/Define.h"
#include "cocos/renderer/pipeline/InstancedBuffer.h"
Expand Down Expand Up @@ -60,7 +59,7 @@ void ProbeHelperQueue::removeMacro() const {
}
}

uint32_t ProbeHelperQueue::getPassIndexFromLayout(
int32_t ProbeHelperQueue::getPassIndexFromLayout(
const cc::IntrusivePtr<cc::scene::SubModel> &subModel,
LayoutGraphData::vertex_descriptor phaseLayoutId) {
const auto &passes = subModel->getPasses();
Expand All @@ -69,7 +68,7 @@ uint32_t ProbeHelperQueue::getPassIndexFromLayout(
return static_cast<int>(k);
}
}
return 0xFFFFFFFF;
return -1;
}

void ProbeHelperQueue::applyMacro(
Expand Down
32 changes: 24 additions & 8 deletions native/cocos/renderer/pipeline/custom/NativeSceneCulling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ namespace cc {

namespace render {

const static uint32_t REFLECTION_PROBE_DEFAULT_MASK = ~static_cast<uint32_t>(pipeline::LayerList::UI_2D) & ~static_cast<uint32_t>(pipeline::LayerList::PROFILER) & ~static_cast<uint32_t>(pipeline::LayerList::UI_3D) & ~static_cast<uint32_t>(pipeline::LayerList::GIZMOS) & ~static_cast<uint32_t>(pipeline::LayerList::SCENE_GIZMO) & ~static_cast<uint32_t>(pipeline::LayerList::EDITOR);
const static uint32_t REFLECTION_PROBE_DEFAULT_MASK =
~static_cast<uint32_t>(pipeline::LayerList::UI_2D) &
~static_cast<uint32_t>(pipeline::LayerList::PROFILER) &
~static_cast<uint32_t>(pipeline::LayerList::UI_3D) &
~static_cast<uint32_t>(pipeline::LayerList::GIZMOS) &
~static_cast<uint32_t>(pipeline::LayerList::SCENE_GIZMO) &
~static_cast<uint32_t>(pipeline::LayerList::EDITOR);

void NativeRenderQueue::clear() noexcept {
probeQueue.clear();
Expand All @@ -43,6 +49,7 @@ FrustumCullingID SceneCulling::getOrCreateFrustumCulling(const SceneData& sceneD

// check cast shadow
const bool bCastShadow = any(sceneData.flags & SceneFlags::SHADOW_CASTER);
const bool bProbePass = any(sceneData.flags & SceneFlags::REFLECTION_PROBE);

// get or create query source
// make query key
Expand All @@ -52,6 +59,7 @@ FrustumCullingID SceneCulling::getOrCreateFrustumCulling(const SceneData& sceneD
sceneData.light.light,
sceneData.light.level,
bCastShadow,
bProbePass,
};

// find query source
Expand Down Expand Up @@ -182,14 +190,15 @@ uint32_t isModelVisible(const scene::Model& model, uint32_t visibility) {
}

bool isReflectProbeMask(const scene::Model& model) {
return ((model.getNode()->getLayer() & REFLECTION_PROBE_DEFAULT_MASK) == model.getNode()->getLayer()) || (REFLECTION_PROBE_DEFAULT_MASK & static_cast<uint32_t>(model.getVisFlags()));
return ((model.getNode()->getLayer() & REFLECTION_PROBE_DEFAULT_MASK) == model.getNode()->getLayer()) ||
(REFLECTION_PROBE_DEFAULT_MASK & static_cast<uint32_t>(model.getVisFlags()));
}

bool isIntersectAABB(const geometry::AABB& lAABB, const geometry::AABB& rAABB) {
return !lAABB.aabbAabb(rAABB);
}

bool isFrustumVisible(const scene::Model& model, const geometry::Frustum& frustum, bool castShadow) {
bool isFrustumCulled(const scene::Model& model, const geometry::Frustum& frustum, bool castShadow) {
const auto* const modelWorldBounds = model.getWorldBounds();
if (!modelWorldBounds) {
return false;
Expand Down Expand Up @@ -246,6 +255,7 @@ void bruteForceCulling(
const scene::Camera& camera,
const geometry::Frustum& cameraOrLightFrustum,
bool bCastShadow,
bool bProbePass,
const scene::ReflectionProbe* probe,
ccstd::vector<const scene::Model*>& models) {
const auto visibility = camera.getVisibility();
Expand All @@ -263,12 +273,12 @@ void bruteForceCulling(
if (scene.isCulledByLod(&camera, &model)) {
continue;
}
if (!probe || (probe && probe->getProbeType() == cc::scene::ReflectionProbe::ProbeType::CUBE)) {
if (!bProbePass || (probe && probe->getProbeType() == cc::scene::ReflectionProbe::ProbeType::CUBE)) {
// filter model by view visibility
if (isNodeVisible(model.getNode(), visibility) || isModelVisible(model, visibility)) {
const auto* const wBounds = model.getWorldBounds();
// frustum culling
if (wBounds && ((!probe && isFrustumVisible(model, cameraOrLightFrustum, bCastShadow)) ||
if (wBounds && ((!probe && isFrustumCulled(model, cameraOrLightFrustum, bCastShadow)) ||
(probe && isIntersectAABB(*wBounds, *probe->getBoundingBox())))) {
continue;
}
Expand All @@ -287,8 +297,10 @@ void sceneCulling(
const scene::Camera& camera,
const geometry::Frustum& cameraOrLightFrustum,
bool bCastShadow,
bool bProbePass,
const scene::ReflectionProbe* probe,
ccstd::vector<const scene::Model*>& models) {
CC_EXPECTS(bProbePass || !probe);
const auto* const octree = scene.getOctree();
if (octree && octree->isEnabled() && !probe) {
octreeCulling(
Expand All @@ -297,7 +309,7 @@ void sceneCulling(
} else {
bruteForceCulling(
skyboxModel,
scene, camera, cameraOrLightFrustum, bCastShadow, probe, models);
scene, camera, cameraOrLightFrustum, bCastShadow, bProbePass, probe, models);
}
}

Expand All @@ -316,6 +328,7 @@ void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) {
const auto* light = key.light;
const auto level = key.lightLevel;
const auto bCastShadow = key.castShadow;
const auto bProbePass = key.probePass;
const auto* probe = key.probe;
const auto& camera = probe ? *probe->getCamera() : *key.camera;
CC_EXPECTS(frustomCulledResultID.value < frustumCullingResults.size());
Expand All @@ -327,6 +340,7 @@ void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) {
*scene, camera,
camera.getFrustum(),
bCastShadow,
bProbePass,
probe,
models);
continue;
Expand All @@ -340,6 +354,7 @@ void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) {
*scene, camera,
dynamic_cast<const scene::SpotLight*>(light)->getFrustum(),
bCastShadow,
bProbePass,
nullptr,
models);
break;
Expand All @@ -352,6 +367,7 @@ void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) {
*scene, camera,
*frustum,
bCastShadow,
bProbePass,
nullptr,
models);
}
Expand All @@ -366,6 +382,7 @@ void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) {
*scene, camera,
camera.getFrustum(),
bCastShadow,
bProbePass,
nullptr,
models);
}
Expand Down Expand Up @@ -602,8 +619,7 @@ void SceneCulling::fillRenderQueues(
}
// not culled by light bounds
return frustumCullingResults.at(frustomCulledResultID.value);
}
();
}();

// native queue target
CC_EXPECTS(targetID.value < renderQueues.size());
Expand Down
Loading