| Keine Panik
Registriert seit: Apr 2010 Ort: Düsseldorf (im ernst)
Beiträge: 1.869
|
sehr schön.
nachdem ich jetzt paar Tage mit rumgespielt habe häng ich auch mal an, was bei mir rumgekommen ist: Zitat: |
Die nächsten Schritte wären nun: Kurven statt Linien zwischen den Punkten zeichnen und die Flächen des Grids interpoliert füllen (Farben auf Flächen interpolieren wäre die perfekte Aufgabe für Molehill), dann bekäme man diese weichen Flächen wie in FlamePainter.
| die Umsetzung auf curveTo war nicht sonderlich schwer, das füllen der Flächen war da schon aufwändiger.
in dem Code unten hab ich nun beide Varianten kombiniert:
Die Punkte (spot.px und spot.ox alias mouseX), werden nur noch als "Stützpunkte" für die Kurve verwendet.
nun wird eine beliebige Anzahl an Zwischenschritten auf einer quadratischen Bezierkurve berechnet (pro Spot), und mit diesem "Gitter" und der Funktion drawTriangles lassen sich schon jetzt sehr schön die Flächen füllen.
Der code müsste noch aufgeräumt werden, aber hier schonmal was zum kosten.
Bon Appétit (Demo im Anhang) PHP-Code: package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.TriangleCulling;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.ui.Mouse;
/**
* ...
* @author thomas ersosi
*/
[SWF(width="800", height="600", frameRate="40", backgroundColor="#000000", quality = "LOW")]
public class Filaments5 extends Sprite
{
//Anzahl der Schritte die interpoliert werden sollen/frame
//aus 1 neuen Punkt mach 1P+3Zwischenschritte
private var numSteps:uint = 4;
//Anzahl der Punkte die an der Maus hängen
private var numSpots:uint = 60;
private var effect:String = BlendMode.ADD;
private var spots:Vector.<Spot> = new Vector.<Spot>();
private var drawing:Shape = new Shape();
private var cursors:Shape = new Shape();
private var buffer:BitmapData;
private var canvas:BitmapData;
private var bCanvas:Bitmap = new Bitmap();
private var palette:BitmapData = new BitmapData(1024, 1, true, 0);
private var bPalette:Bitmap = new Bitmap(palette);
private var vertices:Vector.<Number>;
private var indices:Vector.<int>;
private var uvtData:Vector.<Number>;
private var isMouseDown:Boolean = false;
public function Filaments5()
{
super();
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
Mouse.hide();
stage.scaleMode = "noScale";
stage.align = "TL";
// stage.frameRate = 10; // ;) hier zeigt sich die Stärke dieser Variante
// der cursor ruckelt, aber die Kurven sind "rund"
bCanvas.smoothing = true;
addChild(bCanvas);
addChild(cursors);
addChild(bPalette);
resize(null);
stage.addEventListener(Event.RESIZE, resize);
addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
addEventListener(MouseEvent.MOUSE_UP, mouseDownHandler);
addEventListener(Event.ENTER_FRAME, loop);
setPalette1([0xFF4422], 1, 0);
// setPalette2([0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0xFF0000], [0, 1, 0]);
// palette.perlinNoise(Math.random() * 300 + 50, Math.random() * 100 + 30, 1, Math.random() * int.MAX_VALUE, false, false, 15, false);
for (var i:int = 0; i < numSpots; ++i) {
var spot:Spot = new Spot();
spot.speed = 1.1 - (i / numSpots);
spot.delay = 0.75;
spot.color = palette.getPixel(i / numSpots * palette.width, 0);
spot.reset(mouseX, mouseY);
spots[i] = spot;
}
buildUVMap();
}
private function buildUVMap():void
{
var numPoints:uint = 1 + numSteps;
var i:int, j:int, k:int;
vertices = new Vector.<Number>();
indices = new Vector.<int>();
uvtData = new Vector.<Number>();
for (i = 0, j = 0; i < numSpots; ++i, j += numPoints) {
var f:Number = i / (numSpots - 1);
if (i) {
for (k = 0; k < numSteps; ++k) {
indices.push(
k+j - numPoints + 1, k+j - numPoints, k+j,
k+j, k+j+1, k+j-numPoints+1
);
}
}
for (k = 0; k <= numSteps; ++k) {
vertices.push(0.0, 0.0);
uvtData.push(f, k/numSteps, 1);
}
}
}
//RGB wird gleichmässig interpoliert
//alpha wird anhand einer Sinuskurve von 0 nach 1 nach 0 interpoliert
public function setPalette1(cols:Array, alpha:Number = 1, outerAlpha:Number = NaN):void
{
var a:Number = (alpha * 255) << 24;
var da:Number = isNaN(outerAlpha)? 0: alpha - outerAlpha;
var l:int = cols.length - 1;
var col:int = cols[0];
for (var i:int = 1024; i--; ) {
var f:Number = i / 1023;
if(l){
var f1:Number = f * l;
var j:int = f1>>0;
f1 -= j;
if (f1) {
var f2:Number = 1 - f1;
var c1:int = cols[j];
var c2:int = cols[j + 1];
col = (((c1>>16)&0xFF)*f2 + ((c2>>16)&0xFF)*f1)<<16 | (((c1>>8)&0xFF)*f2 + ((c2>>8)&0xFF)*f1)<<8 | ((c1&0xFF)*f2 + (c2&0xFF)*f1);
}else{
col = cols[j];
}
}
if(da){
// a = Math.sin(Math.PI * f); //halbe Sinuskurve
a = .5 - Math.cos(2 * Math.PI * f) * .5; //etwas richtung Gausssche-Glockenkurve
a = ((a*da + outerAlpha) * 0xFF) << 24;
}
palette.setPixel32(i, 0, 0xFFFFFF&col | a);
}
}
//RGB wird gleichmässig interpoliert. Alpha auch. jedoch beide unabhängig voneinander
public function setPalette2(cols:Array, alphas:Array=null):void
{
var cl:int = cols.length - 1;
var al:int = alphas? alphas.length - 1: 0;
var col:int = cols[0];
var a:Number = alphas? ((alphas[0]*0xFF)<<24): 0xFF000000;
for (var i:int = 1024; i--; ) {
var f:Number = i / 1023, f1:Number, f2:Number, j:int;
if(cl){
f1 = f * cl;
j = f1>>0;
f1 -= j;
if (f1) {
f2 = 1 - f1;
var c1:int = cols[j];
var c2:int = cols[j + 1];
col = (((c1>>16)&0xFF)*f2 + ((c2>>16)&0xFF)*f1)<<16 | (((c1>>8)&0xFF)*f2 + ((c2>>8)&0xFF)*f1)<<8 | ((c1&0xFF)*f2 + (c2&0xFF)*f1);
}else{
col = cols[j];
}
}
if (al) {
f1 = f * al;
j = f1 >> 0;
f1 -= j;
a = f1? (alphas[j] * (1 - f1) + alphas[j + 1] * f1): alphas[j];
a = (a * 0xFF) << 24;
}
palette.setPixel32(i, 0, 0xFFFFFF&col | a);
}
}
private function loop(e:Event):void
{
cursors.graphics.clear();
cursors.graphics.lineStyle(1, 0xFFFFFF);
cursors.graphics.drawCircle(mouseX, mouseY, 5);
var i:int = 0;
for each(var spot:Spot in spots)
{
spot.vx += ((mouseX - spot.px) * spot.speed - spot.vx) * spot.delay;
spot.vy += ((mouseY - spot.py) * spot.speed - spot.vy) * spot.delay;
spot.px += spot.vx;
spot.py += spot.vy;
spot.mx = (spot.ox + spot.px) / 2;
spot.my = (spot.oy + spot.py) / 2;
vertices[i ] = spot.omx;
vertices[i+1] = spot.omy;
i += 2;
for (var j:int = 1; j < numSteps; ++j) {
var t:Number = j / numSteps, t2:Number = 1 - t;
var c0:Number = t2 * t2, c1:Number = 2.0 * t * t2, c2:Number = t*t;
vertices[i ] = c0 * spot.omx + c1 * spot.ox + c2 * spot.mx;
vertices[i+1] = c0 * spot.omy + c1 * spot.oy + c2 * spot.my;
i += 2;
}
vertices[i ] = spot.mx;
vertices[i+1] = spot.my;
i += 2;
spot.ox = spot.px;
spot.oy = spot.py;
spot.omx = spot.mx;
spot.omy = spot.my;
// cursors.graphics.lineStyle(1, 0xFFFFFF);
cursors.graphics.lineStyle(1, spot.color);
cursors.graphics.drawRect(spot.px - 1, spot.py - 1, 2, 2);
}
if (isMouseDown) {
drawing.graphics.clear();
drawing.graphics.beginBitmapFill(palette, null, false, true);
drawing.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NONE);
//TODO: durchprobieren, bei welchen BlendModes der buffer weggelassen werden kann
if (effect == BlendMode.NORMAL) {
canvas.draw(drawing, null, null, effect);
}else{
buffer.fillRect(buffer.rect, 0);
buffer.draw(drawing);
canvas.draw(buffer, null, null, effect);
}
}
}
private function mouseDownHandler(e:MouseEvent):void
{
isMouseDown = e.type == MouseEvent.MOUSE_DOWN;
}
private function resize(e:Event):void
{
var canvas2:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight - 12, false, 0);
if (canvas) {
//alte Inhalte kopieren (zentriert)
canvas2.copyPixels(canvas, canvas.rect, new Point((canvas2.width - canvas.width) / 2, (canvas2.height - canvas.height) / 2));
canvas.dispose();
}
bCanvas.bitmapData = canvas = canvas2;
if (buffer) buffer.dispose();
buffer = new BitmapData(canvas2.width, canvas2.height, true, 0); //immer Transparent!
//Farbpalette unten anordnen
bPalette.width = stage.stageWidth;
bPalette.y = stage.stageHeight-10;
bPalette.height = 10;
}
}
}
class Spot
{
public var px:Number = 0;
public var py:Number = 0;
public var ox:Number = 0;
public var oy:Number = 0;
public var mx:Number = 0;
public var my:Number = 0;
public var omx:Number = 0;
public var omy:Number = 0;
public var vx:Number = 0;
public var vy:Number = 0;
public var delay:Number = 1;
public var speed:Number = 1;
public var color:uint = 0xFFFFFF;
function Spot()
{ }
public function reset(targetX:Number=0, targetY:Number=0):void
{
px = ox = targetX;
py = oy = targetY;
vx = vy = 0;
}
}
|