Swift: 使同色的半透明重叠线相交时不改变颜色

Swift: Make translucent overlapping lines of the same color not change color when intersecting

目前我在屏幕上画了 2 条颜色相同但 alpha 值都小于 1 的线。当这些线相交时,交点的颜色与其余线的颜色不同。之前有一个 post 解决了同样的问题:swift drawing translucent lines, how to make overlapping parts not getting darker? 然而,这个 post 没有得到充分的回答。我现在画的线是这样的:

    var points = [CGPoint]()

    points = [CGPoint(x: -100, y: 100), CGPoint(x: 100, y: -100)]
    let FirstLine = SKShapeNode(points: &points, count: points.count)
    FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 0.5)
    FirstLine.lineWidth = 30
    addChild(FirstLine)

    points = [CGPoint(x: 100, y: 100), CGPoint(x: -100, y: -100)]
    let SecondLine = SKShapeNode(points: &points, count: points.count)
    SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 0.5)
    SecondLine.lineWidth = 30
    addChild(SecondLine)

这是它的样子:

我明白为什么会这样,但是有什么方法可以让交叉路口看起来一样,这样看起来会好很多吗?

编辑: 我决定实施@Confused 的回答。但是,现在的问题是纹理总是居中到屏幕中间。这是一个例子:

红色十字位于正确的位置,因为它将指定的点连接在一起。然而,一旦我将红十字作为纹理,它总是居中于屏幕的中间(绿十字是作为纹理的红十字)。我可以使用任何可以将纹理重新定位到正确位置的代码吗?注意:此代码不能仅适用于此示例,我需要一个无论红十字的位置如何都能一直工作的代码。


针对有相同问题的人的最终编辑

首先,像这样设置一切:

var points = [CGPoint]()
let crossParent = SKNode()
addChild(crossParent)

请注意您必须为纹理创建父 SKNode,否则屏幕上的所有内容都将成为纹理,而不仅仅是您想要的节点。然后,将该父节点添加到场景中。

之后,创建您想要的线条(在本例中为绿色十字):

//The first line of the green cross
points = [CGPoint(x: -300, y: 300), CGPoint(x: -100, y: 100)]
let FirstLine = SKShapeNode(points: &points, count: points.count)
FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1.0)
FirstLine.lineWidth = 30
crossParent.addChild(FirstLine)

记住不要将您创建的第一行添加到场景中,而是添加到您在开始。此外,将绘制的每条线的 alpha 值设置为 1.0。然后添加您的其他行:

//The second line of the green cross
points = [CGPoint(x: -100, y: 300), CGPoint(x: -300, y: 100)]
let SecondLine = SKShapeNode(points: &points, count: points.count)
SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1.0)
SecondLine.lineWidth = 30
FirstLine.addChild(SecondLine)

请注意,您必须将该行添加到第一行,而不是添加到场景中。如果您在添加第一行后添加多行,则将其添加到第一行,就像我在这里对每个连续的操作一样 您添加的行。

现在,像这样创建纹理:

 let tex = view?.texture(from: FirstLine)
 let cross = SKSpriteNode(texture: tex, color: .clear, size: (tex?.size())!)
 cross.alpha = 0.5
 addChild(cross)

完成此操作后,您称之为交叉的任何东西都将成为您的纹理,您可以像我在这里所做的那样将 alpha 值更改为您喜欢的任何值,并且图像不会有不同的颜色。记得然后将该纹理添加到场景中。

最后,您可能会注意到纹理与您最初放置点的位置不同。你可以像这样把它放回原来的位置:

cross.position = CGPoint(x: (FirstLine.frame.midX), y: (FirstLine.frame.midY))

希望这会有所帮助:)感谢@Confused 提供程序的纹理部分:D


不!不幸的是,我认为这是答案。

有以下混合模式,none 提供您正在寻找的结果:

case alpha // Blends the source and destination colors by multiplying the source alpha value.

case add // Blends the source and destination colors by adding them up.

case subtract // Blends the source and destination colors by subtracting the source from the destination.

case multiply // Blends the source and destination colors by multiplying them.

case multiplyX2 // Blends the source and destination colors by multiplying them and doubling the result.

case screen // Blends the source and destination colors by multiplying one minus the source with the destination and adding the source.

case replace // Replaces the destination with the source (ignores alpha).

唯一可行的选项是自定义着色器,它可以通过某种方式判断自己是否重叠。但我不知道从哪里开始制作类似的东西,或者是否有可能。

这是一种技巧。它不能解决您的问题,也不能直接回答您的问题。相反,它提供了一种获得所需结果的方法,但没有您真正想要的线条的灵活性和固有特性。

您可以使用任意数量的节点和任意数量的技术从您绘制的任何内容创建纹理。

您可以通过将所有绘图元素附加到您有权访问的 SKView space 中的单个节点来执行此操作(最简单的方法),然后渲染绘制的 "parent" 节点对象到纹理。

这有什么帮助?

很高兴你提出这个问题:

您可以在不透明度为 100% 的情况下绘制所有内容,并将其渲染为纹理,然后将您绘图的纹理放在您喜欢的位置,并将其不透明度降低到您喜欢的任何百分比,然后得到一个均匀的结果。事物相互重叠时没有亮点。

这是执行上述所有操作的代码:

   var points = [CGPoint]()

   points = [CGPoint(x: -100, y: 100), CGPoint(x: 100, y: -100)]
   let FirstLine = SKShapeNode(points: &points, count: points.count)
   FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
   FirstLine.lineWidth = 30
//      ^^ Note the FirstLine is not added to the Scene

   points = [CGPoint(x: 100, y: 100), CGPoint(x: -100, y: -100)]
   let SecondLine = SKShapeNode(points: &points, count: points.count)
   SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
   SecondLine.lineWidth = 30
   FirstLine.addChild(SecondLine)
// ^^ Note SecondLine being added to FirstLine, and that they both have alpha of 1

// Now the magic: use the view of the SKScene to render FirstLine and its child (SecondLine)
// They are rendered into a texture, named, imaginatively, "tex"

   let tex = view.texture(from: FirstLine)
   let cross = SKSpriteNode(texture: tex, color: .clear, size: (tex?.size())!)
       cross.alpha = 0.5

// ^^ The alpha of the above sprite is set to your original desire of 0.5
// And then added to the scene, with the desired result.
   addChild(cross)

结果如下:

  1. 使描边颜色完全不透明。
  2. 将您的路径节点添加到 SKEffectNode
  3. 将效果节点的 alpha 设置为所需值。
  4. 将效果节点放入您的主场景中。

在执行此操作时,您还可以将所有线条放在一个形状节点中:

let path = CGMutablePath()
path.move(   to: CGPoint(x: -100, y:  100))
path.addLine(to: CGPoint(x:  100, y: -100))
path.move(   to: CGPoint(x:  100, y:  100))
path.addLine(to: CGPoint(x: -100, y: -100))

let shape = SKShapeNode(path: path)
shape.strokeColor = UIColor(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
shape.lineWidth = 30

let effect = SKEffectNode()
effect.addChild(shape)
effect.alpha = 0.5
addChild(effect)

问题是您在颜色级别进行 alpha 混合,在节点级别进行 alpha 混合

var points = [CGPoint]()
var cross = SKEffectNode()
points = [CGPoint(x: -100, y: 100), CGPoint(x: 100, y: -100)]
let FirstLine = SKShapeNode(points: &points, count: points.count)
FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
FirstLine.lineWidth = 30
cross.addChild(FirstLine)

points = [CGPoint(x: 100, y: 100), CGPoint(x: -100, y: -100)]
let SecondLine = SKShapeNode(points: &points, count: points.count)
SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
SecondLine.lineWidth = 30
cross.addChild(SecondLine)
cross.alpha = 0.5
addChild(cross)