2013-07-02 15 views
5

Also habe ich eine Animation, die ich in Javascript und HTML5 (keine Bibliotheken, keine Plugins, nichts und ich würde es gerne so bleiben). Die Animation verwendet die Physik (im Prinzip eine Reihe ungewöhnlicher Federn, die an Massen befestigt sind), um eine einfache Flüssigkeit zu simulieren. Die Ausgabe von diesem Teil des Programms ist ein Raster (2d-Array) von Objekten mit jeweils einem z-Wert. Das funktioniert ganz gut. Mein Problem tritt auf, wenn die Daten zu einem HTML5 Canvas gezeichnet werden.HTML5 Leinwand Creative Alpha-Blending

That's what it looks like. Trust me, it's better when animated.

Das ist, wie es aussieht. Vertrau mir, es ist besser, wenn es animiert wird.

Für jeden Datenpunkt zeichnet das Programm einen Kreis mit einer Farbe, die durch den z-Wert bestimmt wird. Beim Zeichnen dieser Punkte ist das Gittermuster jedoch schmerzhaft offensichtlich und es ist schwierig, die Flüssigkeit zu erkennen, die es darstellt. Um das zu lösen, habe ich die Kreise größer und transparenter gemacht, so dass sie sich überlappen und die Farben ineinander übergehen, wodurch eine einfache Faltungsunschärfe entsteht. Das Ergebnis war sowohl schnell als auch schön, aber für einen kleinen Fehler:

Da die Kreise in der Reihenfolge gezeichnet werden, stapeln sich ihre Farbwerte nicht gleichmäßig, und so verdecken später gezeichnete Kreise die früher gezeichneten Kreise. Mathematisch nimmt der Renderer wiederholte gewichtete Mittelwerte der Farbwerte der Kreise an. Dies funktioniert gut für zwei Kreise und gibt jedem einen Wert von 0,5 * alpha_n, aber für drei Kreise nimmt der Renderer den Durchschnitt des neuesten Kreises mit dem Durchschnitt der anderen zwei, was dem neuesten Kreis einen Wert von 0,5 * alpha_n gibt, aber die früheren Kreise hatten jeweils einen Wert von 0,25 * alpha_n. Wenn sich mehr Kreise überschneiden, geht der Prozess weiter und erzeugt eine Tendenz zu neueren Kreisen und zu älteren Kreisen. Was ich will, ist stattdessen, dass jeder von drei oder mehr Kreisen einen Wert von 0,33 * alpha_n erhält, so dass frühere Kreise nicht verdeckt werden.

Hier ist ein Bild von Alpha-Blending in Aktion. Beachten Sie, dass der spätere blauen Kreis früher roten und grünen gezogen verschleiert:

Later blue circle obscures earlier drawn ones.

Here's what the problem looks like in action. Notice the different appearance of the left side of the lump.

Hier ist, was das Problem wie in Aktion sieht. Beachten Sie das unterschiedliche Aussehen der linken Seite der Beule.

  • Mit verschiedener Leinwand "blend-Modi":

    Um dieses Problem zu lösen, ich verschiedene Methoden ausprobiert habe. "Multiplizieren" (wie im obigen Bild zu sehen) hat den Trick gemacht, aber unglückliche Farbverzerrungen verursacht.

  • Sammeln Zeichnung Aufrufe. Anstatt jeden Kreis zu einem separaten Leinwandpfad zu machen, habe ich versucht, sie alle zu einem zusammenzufassen. Leider ist dies nicht mit separaten Füllfarben zu vereinbaren, und der Pfad verschmilzt überhaupt nicht mit sich selbst und erzeugt eine matte, monotone Silhouette.
  • Interlacing Zeichnungsreihenfolge. Anstatt die Kreise in der Reihenfolge von 0 bis n zu zeichnen, habe ich zuerst versucht, die Evens und dann die Odds zu zeichnen. Dies löste das Problem nur teilweise und erzeugte ein unansehnliches Schichtmuster, in dem die Chancen schienen, über den Gleichen zu schweben.
  • Erstellen eines eigenen Mischmodus mit putImageData. Ich habe versucht, einen manuellen Pixel-Shader zu erstellen, der meinen Bedürfnissen mit Javascript entspricht, aber wie erwartet war es viel zu langsam.

An diesem Punkt bin ich ein bisschen fest. Ich suche nach kreativen Wegen, um dieses Problem zu lösen oder zu umgehen, und ich begrüße Ihre Ideen. Ich bin nicht sehr daran interessiert zu erfahren, dass das unmöglich ist, weil ich das selbst herausfinden kann.Wie würden Sie aus solchen Datenpunkten elegant eine Flüssigkeit ziehen?

+0

PS: Ich bin ziemlich begabt bei Javascript und HTML5, also müssen Sie mir nichts beibringen. Wenn Ihnen das wie ein triviales Problem erscheint, denken Sie daran, dass ich Sie nicht zur Antwort zwinge. Es stört mich nur und ich möchte daran arbeiten, es zu lösen. – mindoftea

+4

verdammt optische Täuschungen, Ihre Bilder sehen animiert aus, auch wenn sie nicht sind. – Philipp

+0

Kann mir jemand sagen warum die down vote? – mindoftea

Antwort

2

Wenn Sie Ihre Kreise in zwei Gruppen zerfallen können (Evens und Chancen), so dass es keine Überlappung gibt unter Kreisen innerhalb einer Gruppe, soll die folgende Sequenz, die die gewünschte Wirkung ergeben:

  1. löschen des Hintergrund
  2. Evens das mit einem alpha von 1,0 Draw (opaque)
  3. Zeichnen die Chancen mit einem Alpha von 1,0 (opaque)
  4. die Evens Zeichnen mit einem Alpha von 0,5

Orten, die weder von Evens odds noch abgedeckt werden, wird den Hintergrund zeigen. Jene, die nur von even abgedeckt sind, zeigen die even bei 100% Opazität. Diejenigen, die von Quoten abgedeckt sind, zeigen die Chancen mit 100% Opazität. Diejenigen, die von beiden abgedeckt werden, zeigen eine 50% ige Mischung.

Es gibt andere Ansätze, die man verwenden kann, um drei oder mehr Objektmengen zu mischen, aber "genau" zu tun ist kompliziert. Ein alternativer Ansatz, wenn man drei oder mehr Bilder hat, die gleichmäßig gemäß ihrem Alphakanal gemischt werden sollen, ist das wiederholte Zeichnen aller Bilder, während das globale Alpha von 1 nach 0 abfällt (beachte, dass das zuvor genannte Verfahren dies tatsächlich tut, aber es ist numerisch präzise, ​​wenn nur zwei Bilder vorhanden sind). Numerische Rundungsprobleme begrenzen die Genauigkeit dieser Technik, aber selbst das Ausführen von zwei oder drei Durchläufen kann die Schwere von durch die Anordnung verursachten visuellen Artefakten wesentlich verringern, während weniger Schritte verwendet werden, als für das genaue Mischen erforderlich wären.

Übrigens, wenn das Mischungsmuster fest ist, kann es möglich sein, das Rendern enorm zu beschleunigen, indem man die Evens und Odds auf separaten Leinwänden nicht als Kreise, sondern als undurchsichtige Rechtecke abzieht und vom Alphakanal eines der Die Leinwände enthalten den Inhalt einer festen "cookie-cutter" Leinwand oder eines Füllmusters. Wenn man den Inhalt von Leinwände für Keksausstecher richtig berechnet, kann dieser Ansatz für mehr als zwei Sätze von Leinwänden verwendet werden. Das Bestimmen des Inhalts der Keksausstecher-Leinwände kann etwas langsam sein, aber es muss nur einmal durchgeführt werden.

+0

Schön! Ich hätte nicht daran gedacht, die Kreise iterativ neu zu zeichnen, aber das eröffnet eine völlig neue Welt der Mischmöglichkeiten! – mindoftea

3

Nun, vielen Dank für die Hilfe, Jungs. :) Aber, ich verstehe, es war eine seltsame Frage und schwer zu beantworten.

Ich setze das hier in Teil, so dass es eine Ressource für zukünftige Zuschauer bereitstellen wird. Ich bin immer noch ziemlich an anderen möglichen Lösungen interessiert, also hoffe ich, dass andere ihre Antworten veröffentlichen werden, wenn sie Ideen haben.

Wie auch immer, ich habe selbst eine Lösung gefunden: Bevor ich die Kreise gezeichnet habe, habe ich eine comb sort auf sie gesetzt, um sie mit dem Z-Wert in Reihenfolge zu bringen, dann zeichnete sie umgekehrt. Das Ergebnis war, dass die Objekte mit dem höchsten Wert (die näher am Betrachter sein sollten) zuletzt gezeichnet wurden und daher nicht von anderen Kreisen verdeckt wurden. Das Ergebnis ist, dass der verdunkelnde Effekt immer noch da ist, aber jetzt geschieht es in einer Weise, die mit der Geometrie sinnvoll ist. Hier ist, was die Simulation wie mit dieser Korrektur sieht, merkt, dass es jetzt symmetrisch:

Normal use Lump test