Skip to content

Add background style support in 3D rendering context.#1384

Closed
StarryThrone wants to merge 6 commits into
mainfrom
bugfix/jasonrjchen_3D_alpha_problem
Closed

Add background style support in 3D rendering context.#1384
StarryThrone wants to merge 6 commits into
mainfrom
bugfix/jasonrjchen_3D_alpha_problem

Conversation

@StarryThrone
Copy link
Copy Markdown
Collaborator

在 3D 渲染上下文中支持背景样式(如 BackgroundBlurStyle)。

主要改动:

  • 在 BSP 合成阶段新增背景样式执行能力,通过 DrawPolygon3D 中存储的 Layer* 指针访问图层的 layerStyles 列表
  • Context3DCompositor 新增 drawBackgroundStyles、syncToBackgroundContext 等方法,在 BSP 遍历中按"背景样式 → 内容绘制 → 同步背景"三步处理每个 polygon
  • 3D 叶子节点(canPreserve3D=false 但 parent canPreserve3D=true)在 createChildArgs 中创建独立的 backgroundContext,使子树中的图层能正常使用背景模糊
  • 修复 Layer::draw 中 backgroundMatrix 的计算:互逆 3D 矩阵投影到 2D 后不互逆,改为从 2D 投影直接计算逆矩阵
  • 新增 is3DContextLeafNode 和 CreateChildBackgroundContext 方法
  • getLayerStyleSource 新增 hasActiveStyle 检查,避免无效的 content image 录制
  • 新增 BackgroundBlurTest.3DLayer 测试用例,覆盖 Preserve3D、Flat、Preserve3DFallback、DirectDraw 四种场景


// The color space used for the compositor's render target.
static const auto TargetColorSpace = ColorSpace::SRGB;
static inline std::shared_ptr<Image> ToImageWithOffset(std::shared_ptr<Picture> picture,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToImageWithOffset在layer里也有,写个工具方法?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这部分逻辑会重构,暂时不抽离工具函数。

const auto sequenceIndex = _depthSequenceCounters[depth]++;
auto polygon = std::make_unique<DrawPolygon3D>(std::move(image), matrix, depth, sequenceIndex,
alpha, antiAlias);
auto polygon = std::make_unique<DrawPolygon3D>(sourceLayer, std::move(image), imageOffset, matrix,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imageOffset可以放在matrix里吗?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

背景绘制逻辑发生改变,这个变量已经不需要。

*/
DrawPolygon3D(std::shared_ptr<Image> image, const Matrix3D& matrix, int depth, int sequenceIndex,
float alpha, bool antiAlias);
DrawPolygon3D(Layer* sourceLayer, std::shared_ptr<Image> image, const Point& imageOffset,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sourceLayer是否耦合程度太高了,目的是什么

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

绘制背景需要通过layer拿到必要数据,这个逻辑已经重构。

Comment thread src/layers/Layer.cpp
return !canPreserve3D() && _parent && _parent->canPreserve3D();
}

std::shared_ptr<BackgroundContext> Layer::CreateChildBackgroundContext(const DrawArgs& args,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个行为是不是应该让使用方来处理

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这部分逻辑会重构,暂时不处理。

Copy link
Copy Markdown
Collaborator

@Hparty Hparty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Architecture Suggestion: Split DrawPolygon3D into Three Layers

The current DrawPolygon3D carries four distinct responsibilities at once:

# Role Members Consumer
1 BSP splittable geometry _points, _normal, _isSplit, splitAnother(), signedDistanceTo(), isFacingPositiveZ() BspTree
2 Draw data container _image, _imageOffset, _matrix, _alpha, _antiAlias Context3DCompositor::drawPolygon/drawQuads
3 Sort key _depth, _sequenceIndex DrawPolygon3DOrder, splitAnother (coplanar ordering)
4 Layer back-reference _sourceLayer, sourceLayer() Context3DCompositor::drawBackgroundStyles

The most visible symptom: BSP split copies ALL fields (image, matrix, sourceLayer, alpha…) even though front/back fragments always share identical draw data — only the geometry (points/normal) differs.

Proposed Design: DrawItem3D + Polygon3D + BackgroundStyleProvider

DrawItem3D — "what to draw" (pure data, shared_ptr-managed):

class DrawItem3D {
 public:
  DrawItem3D(std::shared_ptr<Image> image, const Point& imageOffset,
             const Matrix3D& matrix, int depth, int sequenceIndex,
             float alpha, bool antiAlias,
             std::shared_ptr<BackgroundStyleProvider> styleProvider = nullptr);

  const std::shared_ptr<Image>& image() const;
  const Point& imageOffset() const;
  const Matrix3D& matrix() const;
  int depth() const;
  int sequenceIndex() const;
  float alpha() const;
  bool antiAlias() const;
  BackgroundStyleProvider* styleProvider() const;

  // Creates a copy with different image/alpha. No style provider (for style rendering).
  std::shared_ptr<DrawItem3D> makeVariant(std::shared_ptr<Image> image, float alpha) const;
};

Polygon3D — "how to split" (pure geometry, owns shared_ptr<DrawItem3D>):

class Polygon3D {
 public:
  Polygon3D(std::shared_ptr<DrawItem3D> drawItem);  // computes points from image bounds + matrix

  void splitAnother(std::unique_ptr<Polygon3D> polygon,
                    std::unique_ptr<Polygon3D>* front,
                    std::unique_ptr<Polygon3D>* back,
                    bool* isCoplanar) const;

  float signedDistanceTo(const Vec3& point) const;
  bool isFacingPositiveZ() const;
  bool isSplit() const;
  const std::vector<Vec3>& points() const;
  const DrawItem3D& drawItem() const;
  std::vector<Quad> toQuads() const;  // uses drawItem().matrix() internally

 private:
  Polygon3D(std::shared_ptr<DrawItem3D> drawItem, std::vector<Vec3> points, const Vec3& normal);
  std::shared_ptr<DrawItem3D> _drawItem;
  std::vector<Vec3> _points;
  Vec3 _normal;
  bool _isSplit = false;
};

BackgroundStyleProvider — interface to decouple compositor from Layer.h:

class BackgroundStyleProvider {
 public:
  virtual ~BackgroundStyleProvider() = default;
  virtual bool hasBackgroundStyles() const = 0;
  virtual const std::vector<std::shared_ptr<LayerStyle>>& backgroundStyles() const = 0;
  virtual Rect layerBounds() const = 0;
  virtual std::shared_ptr<Image> getScaledBackgroundImage(...) const = 0;
  virtual std::shared_ptr<Image> getScaledOpaqueContentImage(...) const = 0;
};

LayerBackgroundStyleProvider implements it holding Layer*. Only Render3DContext::onImageReady constructs it.

Key Benefits

1. BSP split becomes trivially cheap:

// Before: copy ALL fields
*front = new DrawPolygon3D(polygon->_sourceLayer, polygon->_image, polygon->_imageOffset,
                           polygon->_matrix, frontPoints, polygon->_normal, ...);
// After: share DrawItem3D, copy only geometry
*front = make_unique<Polygon3D>(polygon->_drawItem, frontPoints, polygon->_normal);
*back  = make_unique<Polygon3D>(polygon->_drawItem, backPoints, polygon->_normal);

2. Compositor no longer depends on Layer.h:

  • Remove #include "tgfx/layers/Layer.h" from Context3DCompositor.cpp
  • Remove friend class Context3DCompositor from Layer.h
  • getScaledBackgroundImage / getScaledOpaqueContentImage move from compositor into LayerBackgroundStyleProvider where they logically belong

3. Each class has exactly one reason to change:

  • DrawItem3D: draw parameters change
  • Polygon3D: BSP/geometry algorithm changes
  • BackgroundStyleProvider: Layer style access pattern changes

4. Cleaner sort comparator:

static bool Polygon3DOrder(const unique_ptr<Polygon3D>& x, const unique_ptr<Polygon3D>& y) {
  const auto& a = x->drawItem();
  const auto& b = y->drawItem();
  return (a.depth() != b.depth()) ? a.depth() < b.depth()
                                   : a.sequenceIndex() < b.sequenceIndex();
}

Impact on Other Files

File Change
Context3DCompositor addImage()addPolygon(unique_ptr<Polygon3D>). Access draw data via polygon->drawItem(). drawBackgroundStyles uses drawItem().styleProvider(). Remove getScaledBackgroundImage/getScaledOpaqueContentImage (moved to provider).
BspTree Rename DrawPolygon3DPolygon3D, no logic change
Render3DContext::onImageReady Construct DrawItem3D + BackgroundStyleProviderPolygon3D, pass to compositor
Opaque3DContext::onImageReady Construct DrawItem3D (no provider) → use directly
Layer3DContext sourceLayer stays in Context3DRecordState, passed through to onImageReady as before
Layer.h Remove friend class Context3DCompositor

The overall code volume stays similar — we are splitting one large class into three focused ones, not adding complexity.

@StarryThrone StarryThrone force-pushed the bugfix/jasonrjchen_3D_alpha_problem branch from 2a4ad3a to 3b5eca3 Compare April 24, 2026 10:29
@StarryThrone StarryThrone force-pushed the bugfix/jasonrjchen_3D_alpha_problem branch from 3b5eca3 to d1b86b8 Compare April 28, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants