Swift: сделайте так, чтобы полупрозрачные перекрывающиеся линии одного цвета не меняли цвет при пересечении.

В настоящее время я нарисовал на экране 2 линии одного цвета, но обе имеют альфа-значение меньше 1. Когда эти линии пересекаются, цвет пересечения отличается от цвета остальных линий. Предыдущее сообщение было посвящено той же проблеме: ">быстрое рисование полупрозрачных линий, как сделать так, чтобы перекрывающиеся части не становились темнее? Однако на этот пост не было дано достаточного ответа. В настоящее время я рисую линии следующим образом:

    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)

Помните, что нужно НЕ добавлять первую созданную вами строку в сцену, а скорее в родительский SKNode, который вы создали в начале. Кроме того, установите альфа-значение на 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)

После этого все, что вы назовете перекрестием, станет вашей текстурой, и вы можете изменить значение альфа-канала, как я сделал здесь, на все, что вам нравится, и изображение не будет иметь разные цвета. Не забудьте затем добавить эту текстуру к сцене.

Наконец, вы можете заметить, что текстура находится не в том положении, в котором вы изначально разместили точки. Вы можете вернуть его в то же положение следующим образом:

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

Надеюсь, это поможет :) Спасибо @Confused за текстурную часть программы :D



person J.Treutlein    schedule 21.12.2016    source источник
comment
Это происходит потому, что в точках пересечения цвета перекрываются. Таким образом, вы можете справиться с этим, не используя Альфу ‹ 1. Выберите проданный цвет с альфой 1.0, и этого не произойдет.   -  person Umair Afzal    schedule 21.12.2016
comment
@UmairAfzal Я понимаю, почему это происходит, но есть ли способ сделать перекресток таким же, чтобы он выглядел намного лучше? Он хочет альфу, не хочет смешения.   -  person Confused    schedule 21.12.2016
comment
Эти линии статичны или движутся? Есть ли способ объединить 2 SKShapeNodes в один узел, а затем перерисовать его как единую фигуру? Я знаю, что есть способ извлечь текстуру, созданную из спрайта и узла обрезки, и вы можете сгенерировать из этого новый узел. Однако возможный удар по производительности, особенно если это нужно делать много раз в секунду.   -  person Steve Ives    schedule 21.12.2016
comment
Да, они двигаются, так что это немного сложно, и они обновляются несколько раз в секунду, но все равно спасибо.   -  person J.Treutlein    schedule 21.12.2016
comment
Есть ли что-то за ними? Почему они должны быть прозрачными? Разве вы не можете просто использовать сплошной цвет вместо этого? Если они просто на сплошном черном фоне, то добавление прозрачности ничего вам не даст.   -  person Fogmeister    schedule 21.12.2016
comment
Есть цветной фон. Это просто тестовый проект, чтобы продемонстрировать мою точку зрения.   -  person J.Treutlein    schedule 21.12.2016


Ответы (4)


Это техника. Это не решает вашу проблему и не дает прямого ответа на ваш вопрос. Вместо этого он предлагает способ получить желаемый результат, но без гибкости и естественной природы линий, которые вам действительно нужны.

Вы можете создавать текстуры из всего, что вы рисуете, с любым количеством узлов, с любым количеством техник.

Вы делаете это (самый простой способ), присоединяя все элементы рисования к одному узлу в пространстве SKView, к которому у вас есть доступ, а затем визуализируйте «родительский» узел ваших нарисованных объектов в текстуру.

Как это помогает?

Я рад, что вы спросили:

Вы можете нарисовать все с уровнем непрозрачности 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)

и вот результат:

введите здесь описание изображения

person Confused    schedule 21.12.2016
comment
Спасибо!! Поскольку этот способ работает, я как-нибудь попытаюсь реализовать его в своей программе. - person J.Treutlein; 21.12.2016
comment
Если у вас есть какие-либо проблемы, дайте мне знать. Я не эксперт... но немного разбираюсь в графике. - person Confused; 21.12.2016
comment
Огромное спасибо! Я отредактировал свой пост с моей проблемой сейчас. Тем не менее, спасибо за решение, оно работает очень хорошо. Я просто пытаюсь понять, как решить мою проблему сейчас. - person J.Treutlein; 22.12.2016
comment
В приведенном выше примере кода cross — это SKSpriteNode, поэтому у него есть позиция. Вы можете сказать ему, куда вы хотите, чтобы он пошел: cross.position.x = 300, cross.position.y = 400 или cross.position = CGPoint(x: 300, y: 400) - person Confused; 22.12.2016
comment
@J.Treutlein, вы также можете настроить zPosition каждого перекрестного объекта, который вы делаете. А крестики можно добавить к другому узлу, к, чтобы можно было двигать их все вместе. Вроде как связывание в Photoshop или After Effects. - person Confused; 22.12.2016
comment
Я действительно заметил, что при изменении положения креста красный крест тоже перемещается. Я думаю это потому что текстура берется из вида, поэтому все в виде. Есть ли способ решить это? - person J.Treutlein; 22.12.2016
comment
Не волнуйся, я сам догадался. Теперь я собираюсь отредактировать свой исходный пост с тем, что было решено. - person J.Treutlein; 22.12.2016
comment
Единственная проблема заключается в том, что создание новой текстуры происходит очень медленно, вам лучше использовать SKEffectNode для ускорения, как в ответе Николая. - person Knight0fDragon; 22.12.2016
comment
Я не делаю это несколько раз в секунду или каждую секунду, так что все должно быть в порядке. - person J.Treutlein; 22.12.2016

НЕТ! Я думаю, к сожалению, ответ.

Существуют следующие режимы наложения, ни один из которых не дает желаемого результата:

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).

Единственный вариант, который может сработать, — это пользовательский шейдер, который выясняет, не перекрывает ли он себя каким-то образом. Но я НЕ ПОНИМАЮ, где вообще начать делать что-то подобное, и возможно ли это вообще.

person Confused    schedule 21.12.2016
comment
Я увижу эффект от них в своей программе. Спасибо! - person J.Treutlein; 21.12.2016
comment
Как я проверил, вы правы, так как ни один из них не дает нужного эффекта. Должен быть способ добиться этого, поскольку я думаю, что это не будет редкой проблемой. - person J.Treutlein; 21.12.2016
comment
Сейчас я создал новый пост, который, если он будет решен, может заменить эту проблему. - person J.Treutlein; 21.12.2016

  1. Сделайте цвет обводки полностью непрозрачным.
  2. Добавьте узлы пути в файл SKEffectNode.
  3. Установите альфа узла эффекта на желаемое значение.
  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)
person Nikolai Ruhe    schedule 21.12.2016
comment
Спасибо за это. Единственная проблема, связанная с этим, заключается в том, что я не думаю, что смогу изменить индивидуально изменение цвета каждой линии, которую я добавляю к пути. - person J.Treutlein; 21.12.2016

Проблема в том, что вы делаете альфа-смешение на уровне цвета, делаете альфа-смешение на уровне узла.

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)
person Knight0fDragon    schedule 21.12.2016
comment
Странно, это должно быть только SKEffectNode..... аааа, он отображает дочерние элементы в отдельный буфер, вот почему - person Knight0fDragon; 21.12.2016
comment
Возможно, вы захотите просто применить шейдер для пересечения, не зная, сколько ресурсов будет потреблять узел эффекта. - person Knight0fDragon; 21.12.2016
comment
Что такое шейдер и как его использовать? - person J.Treutlein; 22.12.2016
comment
это код, который используется на GPU, но не имеет значения, так как SKShapeNode его не поддерживает - person Knight0fDragon; 22.12.2016
comment
Есть ли возможность заставить ваш оригинальный пост работать? Если бы это было возможно, это было бы действительно полезно. - person J.Treutlein; 22.12.2016
comment
Я имею в виду ваш оригинальный пост без SKEffectorNode. Когда вы добавили строки в родительский узел, то изменили альфа родителя. Разве это не должно изменить альфа-значение всех дочерних элементов. - person J.Treutlein; 22.12.2016
comment
Не могу, пробовал написать шейдер. Но я не слишком много знаю о них - person Knight0fDragon; 22.12.2016
comment
Должен ли я попробовать создать новый пост об этом? - person J.Treutlein; 22.12.2016
comment
Нет, это не предполагается, но я предполагаю, что из-за того, что он оптимизируется с использованием одного прохода отрисовки, он смешивается таким образом. - person Knight0fDragon; 22.12.2016
comment
Хотя другие люди могут написать шейдер, верно? Поскольку вы сказали, что не слишком много знаете о них, другие люди знают и могут написать об этом. - person J.Treutlein; 22.12.2016
comment
Абсолютно не понимаю, почему бы и нет - person Knight0fDragon; 22.12.2016