Skip to content

Commit a3534ec

Browse files
authored
Refactor scene rendering with explicit per-view state (#3256)
* Refactor scene rendering with explicit per-view state - Introduce `SceneViewData` and `SceneRenderState` to carry immutable per-pass view, projection, renderer, and camera-mask data through scene traversal. - Remove the global visiting-Camera state and migrate render commands, background brushes, offscreen rendering, extensions, tests, and Lua bindings to explicit view data. - Rework OpenXR rendering to build independent per-eye views without mutating persistent Camera objects. - Unify VR pointer-ray hit testing across 2D, UI, terrain, and multi-camera scenes, with consistent world-space hit results and reticle rendering. - Fix view-dependent regressions in skyboxes, VideoPlayer controls, RenderTexture paths, and grid-based transition effects.
1 parent 3b1e776 commit a3534ec

192 files changed

Lines changed: 2023 additions & 1578 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

axmol/2d/AtlasNode.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,19 @@ void AtlasNode::updateAtlasValues()
130130
}
131131

132132
// AtlasNode - draw
133-
void AtlasNode::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
133+
void AtlasNode::draw(const SceneRenderState& state, const Mat4& transform, uint32_t flags)
134134
{
135135
if (_textureAtlas->getTotalQuads() == 0)
136136
return;
137137

138138
auto programState = _quadCommand.unsafePS();
139139

140-
const auto& projectionMat = Camera::getVisitingViewProjectionMatrix();
140+
const auto& projectionMat = state.getViewProjectionMatrix();
141141
programState->setUniform(_mvpMatrixLocation, projectionMat.m, sizeof(projectionMat.m));
142142

143143
_quadCommand.init(_globalZOrder, _textureAtlas->getTexture(), _blendFunc, _textureAtlas->getQuads(), _quadsToDraw,
144-
transform, flags);
145-
renderer->addCommand(&_quadCommand);
144+
transform, flags, state.getView());
145+
state.getRenderer()->addCommand(&_quadCommand);
146146
}
147147

148148
// AtlasNode - RGBA protocol

axmol/2d/AtlasNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class AX_DLL AtlasNode : public Node, public TextureProtocol
6767
virtual void updateAtlasValues();
6868

6969
// Overrides
70-
void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override;
70+
void draw(const SceneRenderState& state, const Mat4& transform, uint32_t flags) override;
7171
Texture2D* getTexture() const override;
7272
void setTexture(Texture2D* texture) override;
7373
bool isOpacityModifyRGB() const override;

axmol/2d/ClippingNode.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,26 +134,26 @@ void ClippingNode::onExit()
134134
Node::onExit();
135135
}
136136

137-
void ClippingNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags)
137+
void ClippingNode::visit(const SceneRenderState& state, const Mat4& parentTransform, uint32_t parentFlags)
138138
{
139139
if (!_visible || !hasContent())
140140
return;
141141

142142
AXASSERT(_stencil, "No stencil set");
143143

144-
uint32_t flags = processParentFlags(parentTransform, parentFlags);
144+
uint32_t flags = processParentFlags(state, parentTransform, parentFlags);
145145

146146
// Add group command
147147

148-
auto* groupCommandStencil = renderer->getNextGroupCommand();
148+
auto* groupCommandStencil = state.getRenderer()->getNextGroupCommand();
149149
groupCommandStencil->init(_globalZOrder);
150-
renderer->addCommand(groupCommandStencil);
150+
state.getRenderer()->addCommand(groupCommandStencil);
151151

152-
renderer->pushGroup(groupCommandStencil->getRenderQueueID());
152+
state.getRenderer()->pushGroup(groupCommandStencil->getRenderQueueID());
153153

154154
// _beforeVisitCmd.init(_globalZOrder);
155155
// _beforeVisitCmd.func = AX_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
156-
// renderer->addCommand(&_beforeVisitCmd);
156+
// state.getRenderer()->addCommand(&_beforeVisitCmd);
157157
_stencilStateManager->onBeforeVisit(_globalZOrder);
158158

159159
auto alphaThreshold = this->getAlphaThreshold();
@@ -167,23 +167,23 @@ void ClippingNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32
167167

168168
AX_SAFE_RELEASE_NULL(programState);
169169
}
170-
_stencil->visit(renderer, _modelViewTransform, flags);
170+
_stencil->visit(state, _modelViewTransform, flags);
171171

172-
auto afterDrawStencilCmd = renderer->nextCallbackCommand();
172+
auto afterDrawStencilCmd = state.getRenderer()->nextCallbackCommand();
173173
afterDrawStencilCmd->init(_globalZOrder);
174174
afterDrawStencilCmd->func = AX_CALLBACK_0(StencilStateManager::onAfterDrawStencil, _stencilStateManager);
175-
renderer->addCommand(afterDrawStencilCmd);
175+
state.getRenderer()->addCommand(afterDrawStencilCmd);
176176

177-
bool visibleByCamera = isVisitableByVisitingCamera();
177+
bool visibleByCamera = isVisitableByCamera(state.cameraFlag);
178178

179179
// `_groupCommandChildren` is used as a barrier
180180
// to ensure commands above be executed before children nodes
181-
auto* groupCommandChildren = renderer->getNextGroupCommand();
181+
auto* groupCommandChildren = state.getRenderer()->getNextGroupCommand();
182182

183183
groupCommandChildren->init(_globalZOrder);
184-
renderer->addCommand(groupCommandChildren);
184+
state.getRenderer()->addCommand(groupCommandChildren);
185185

186-
renderer->pushGroup(groupCommandChildren->getRenderQueueID());
186+
state.getRenderer()->pushGroup(groupCommandChildren->getRenderQueueID());
187187

188188
if (!_children.empty())
189189
{
@@ -195,30 +195,30 @@ void ClippingNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32
195195
auto node = _children.at(i);
196196

197197
if (node && node->getLocalZOrder() < 0)
198-
node->visit(renderer, _modelViewTransform, flags);
198+
node->visit(state, _modelViewTransform, flags);
199199
else
200200
break;
201201
}
202202
// self draw
203203
if (visibleByCamera)
204-
this->draw(renderer, _modelViewTransform, flags);
204+
this->draw(state, _modelViewTransform, flags);
205205

206206
for (auto it = _children.cbegin() + i, itCend = _children.cend(); it != itCend; ++it)
207-
(*it)->visit(renderer, _modelViewTransform, flags);
207+
(*it)->visit(state, _modelViewTransform, flags);
208208
}
209209
else if (visibleByCamera)
210210
{
211-
this->draw(renderer, _modelViewTransform, flags);
211+
this->draw(state, _modelViewTransform, flags);
212212
}
213213

214-
renderer->popGroup();
214+
state.getRenderer()->popGroup();
215215

216-
auto _afterVisitCmd = renderer->nextCallbackCommand();
216+
auto _afterVisitCmd = state.getRenderer()->nextCallbackCommand();
217217
_afterVisitCmd->init(_globalZOrder);
218218
_afterVisitCmd->func = AX_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
219-
renderer->addCommand(_afterVisitCmd);
219+
state.getRenderer()->addCommand(_afterVisitCmd);
220220

221-
renderer->popGroup();
221+
state.getRenderer()->popGroup();
222222
}
223223

224224
void ClippingNode::setGlobalZOrder(float globalZOrder)

axmol/2d/ClippingNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class AX_DLL ClippingNode : public Node
135135
* @lua NA
136136
*/
137137
void onExit() override;
138-
void visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) override;
138+
void visit(const SceneRenderState& state, const Mat4& parentTransform, uint32_t parentFlags) override;
139139

140140
void setGlobalZOrder(float globalZOrder) override;
141141

axmol/2d/ClippingRectangleNode.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,19 @@ void ClippingRectangleNode::onAfterVisitScissor()
9191
_director->getRenderer()->setScissorTest(_oldScissorTest);
9292
}
9393

94-
void ClippingRectangleNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags)
94+
void ClippingRectangleNode::visit(const SceneRenderState& state, const Mat4& parentTransform, uint32_t parentFlags)
9595
{
96-
auto beforeVisitCmdScissor = renderer->nextCallbackCommand();
96+
auto beforeVisitCmdScissor = state.getRenderer()->nextCallbackCommand();
9797
beforeVisitCmdScissor->init(_globalZOrder);
9898
beforeVisitCmdScissor->func = AX_CALLBACK_0(ClippingRectangleNode::onBeforeVisitScissor, this);
99-
renderer->addCommand(beforeVisitCmdScissor);
99+
state.getRenderer()->addCommand(beforeVisitCmdScissor);
100100

101-
Node::visit(renderer, parentTransform, parentFlags);
101+
Node::visit(state, parentTransform, parentFlags);
102102

103-
auto afterVisitCmdScissor = renderer->nextCallbackCommand();
103+
auto afterVisitCmdScissor = state.getRenderer()->nextCallbackCommand();
104104
afterVisitCmdScissor->init(_globalZOrder);
105105
afterVisitCmdScissor->func = AX_CALLBACK_0(ClippingRectangleNode::onAfterVisitScissor, this);
106-
renderer->addCommand(afterVisitCmdScissor);
106+
state.getRenderer()->addCommand(afterVisitCmdScissor);
107107
}
108108

109109
} // namespace ax

axmol/2d/ClippingRectangleNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class AX_DLL ClippingRectangleNode : public Node
8282
void setClippingEnabled(bool enabled) { _clippingEnabled = enabled; }
8383

8484
// virtual void draw(Renderer* renderer, const Mat4 &transform, uint32_t flags) override;
85-
void visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) override;
85+
void visit(const SceneRenderState& state, const Mat4& parentTransform, uint32_t parentFlags) override;
8686

8787
protected:
8888
ClippingRectangleNode() = default;

axmol/2d/DrawNode.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,10 @@ void DrawNode::updateBlendState(CustomCommand& cmd)
195195
}
196196
}
197197

198-
void DrawNode::updateUniforms(const Mat4& transform, CustomCommand& cmd)
198+
void DrawNode::updateUniforms(const SceneRenderState& state, const Mat4& transform, CustomCommand& cmd)
199199
{
200200
auto pipelinePS = cmd.unsafePS();
201-
const auto& matrixP = Camera::getVisitingViewProjectionMatrix();
201+
const auto& matrixP = state.getViewProjectionMatrix();
202202
Mat4 matrixMVP = matrixP * transform;
203203
auto mvpLocation = pipelinePS->getUniformLocation("u_MVPMatrix");
204204
pipelinePS->setUniform(mvpLocation, matrixMVP.m, sizeof(matrixMVP.m));
@@ -209,33 +209,33 @@ void DrawNode::updateUniforms(const Mat4& transform, CustomCommand& cmd)
209209
pipelinePS->setUniform(alphaUniformLocation, &alpha, sizeof(alpha));
210210
}
211211

212-
void DrawNode::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
212+
void DrawNode::draw(const SceneRenderState& state, const Mat4& transform, uint32_t flags)
213213
{
214214
if (_trianglesDirty || _pointsDirty || _linesDirty)
215215
updateBuffers();
216216

217217
if (_customCommandTriangle.getVertexDrawCount() > 0)
218218
{
219219
updateBlendState(_customCommandTriangle);
220-
updateUniforms(transform, _customCommandTriangle);
220+
updateUniforms(state, transform, _customCommandTriangle);
221221
_customCommandTriangle.init(_globalZOrder);
222-
renderer->addCommand(&_customCommandTriangle);
222+
state.getRenderer()->addCommand(&_customCommandTriangle);
223223
}
224224

225225
if (_customCommandPoint.getVertexDrawCount() > 0)
226226
{
227227
updateBlendState(_customCommandPoint);
228-
updateUniforms(transform, _customCommandPoint);
228+
updateUniforms(state, transform, _customCommandPoint);
229229
_customCommandPoint.init(_globalZOrder);
230-
renderer->addCommand(&_customCommandPoint);
230+
state.getRenderer()->addCommand(&_customCommandPoint);
231231
}
232232

233233
if (_customCommandLine.getVertexDrawCount() > 0)
234234
{
235235
updateBlendState(_customCommandLine);
236-
updateUniforms(transform, _customCommandLine);
236+
updateUniforms(state, transform, _customCommandLine);
237237
_customCommandLine.init(_globalZOrder);
238-
renderer->addCommand(&_customCommandLine);
238+
state.getRenderer()->addCommand(&_customCommandLine);
239239
}
240240
}
241241

@@ -688,16 +688,16 @@ void DrawNode::setBlendFunc(const BlendFunc& blendFunc)
688688
_blendFunc = blendFunc;
689689
}
690690

691-
void DrawNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags)
691+
void DrawNode::visit(const SceneRenderState& state, const Mat4& parentTransform, uint32_t parentFlags)
692692
{
693693
if (_isolated)
694694
{
695695
// ignore `parentTransform` from parent
696-
Node::visit(renderer, Mat4::identity, parentFlags);
696+
Node::visit(state, Mat4::identity, parentFlags);
697697
}
698698
else
699699
{
700-
Node::visit(renderer, parentTransform, parentFlags);
700+
Node::visit(state, parentTransform, parentFlags);
701701
}
702702
}
703703

axmol/2d/DrawNode.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,9 +538,9 @@ class AX_DLL DrawNode : public Node, public BlendProtocol
538538
void setBlendFunc(const BlendFunc& blendFunc) override;
539539

540540
// Overrides
541-
void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override;
541+
void draw(const SceneRenderState& state, const Mat4& transform, uint32_t flags) override;
542542

543-
void visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) override;
543+
void visit(const SceneRenderState& state, const Mat4& parentTransform, uint32_t parentFlags) override;
544544

545545
/**
546546
* When isolated is set, the position of the node is no longer affected by parent nodes.
@@ -564,7 +564,7 @@ class AX_DLL DrawNode : public Node, public BlendProtocol
564564
void freeShaderInternal(CustomCommand& cmd);
565565

566566
void updateBlendState(CustomCommand& cmd);
567-
void updateUniforms(const Mat4& transform, CustomCommand& cmd);
567+
void updateUniforms(const SceneRenderState& state, const Mat4& transform, CustomCommand& cmd);
568568

569569
bool _trianglesDirty : 1 = false;
570570
bool _pointsDirty : 1 = false;

axmol/2d/FastTMXLayer.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -211,23 +211,24 @@ int FastTMXLayer::batchIndexForGID(uint32_t gid) const
211211
return -1;
212212
}
213213

214-
void FastTMXLayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
214+
void FastTMXLayer::draw(const SceneRenderState& state, const Mat4& transform, uint32_t flags)
215215
{
216216
updateTotalQuads();
217217

218218
const float refTileX = _batches.empty() ? 1.0f : _batches[0].tilesetInfo->_tileSize.x;
219-
auto cam = Camera::getVisitingCamera();
219+
auto cam = state.getCamera();
220220
if (!cam)
221221
return;
222-
if (flags != 0 || _dirty || _quadsDirty || !_cameraPositionDirty.fuzzyEquals(cam->getPosition(), refTileX) ||
222+
const Vec2 cameraPosition(state.getView().position.x, state.getView().position.y);
223+
if (flags != 0 || _dirty || _quadsDirty || !_cameraPositionDirty.fuzzyEquals(cameraPosition, refTileX) ||
223224
_cameraZoomDirty != cam->getZoom())
224225
{
225-
_cameraPositionDirty = cam->getPosition();
226+
_cameraPositionDirty = cameraPosition;
226227
auto zoom = _cameraZoomDirty = cam->getZoom();
227228
Vec2 s = _director->getVisibleSize();
228229
const Vec2& anchor = getAnchorPoint();
229-
auto rect = Rect(cam->getPositionX() - s.width * zoom * (anchor.x == 0.0f ? 0.5f : anchor.x),
230-
cam->getPositionY() - s.height * zoom * (anchor.y == 0.0f ? 0.5f : anchor.y), s.width * zoom,
230+
auto rect = Rect(cameraPosition.x - s.width * zoom * (anchor.x == 0.0f ? 0.5f : anchor.x),
231+
cameraPosition.y - s.height * zoom * (anchor.y == 0.0f ? 0.5f : anchor.y), s.width * zoom,
231232
s.height * zoom);
232233

233234
Mat4 inv = transform;
@@ -240,7 +241,7 @@ void FastTMXLayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flag
240241
_dirty = false;
241242
}
242243

243-
const auto& projectionMat = Camera::getVisitingViewProjectionMatrix();
244+
const auto& projectionMat = state.getViewProjectionMatrix();
244245
Mat4 finalMat = projectionMat * _modelViewTransform;
245246
// Submit batches lowest-firstGid first so base/terrain tiles (low GIDs) draw behind
246247
// overlay/object tiles (high GIDs) that share the same vertexZ.
@@ -252,7 +253,7 @@ void FastTMXLayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flag
252253
{
253254
// All commands in a batch share the same program, so the cached location is valid.
254255
cmd->unsafePS()->setUniform(it->mvpMatrixLocation, finalMat.m, sizeof(finalMat.m));
255-
renderer->addCommand(cmd);
256+
state.getRenderer()->addCommand(cmd);
256257
}
257258
}
258259
}

axmol/2d/FastTMXLayer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ class AX_DLL FastTMXLayer : public Node
306306
// Override
307307
//
308308
std::string getDescription() const override;
309-
void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override;
309+
void draw(const SceneRenderState& state, const Mat4& transform, uint32_t flags) override;
310310
void removeChild(Node* child, bool cleanup = true) override;
311311

312312
/** Map from gid of animated tile to its instance.

0 commit comments

Comments
 (0)