2012-12-09 46 views
1

我是Processing的新手,我一直在模擬電子運動。 一切似乎都很好,直到我嘗試爲每個粒子添加漸變顏色爲止。幀速率顯着下降。處理:高效地繪製一個梯度

這是我到目前爲止已經試過:

float a=0; 
float s; 
void setup() 
{ 
    size(500,500); 
    smooth(); 
    frameRate(500); 
    colorMode(HSB,360,100,100); 
    noStroke(); 
    ellipseMode(RADIUS); 
} 

void draw() 
{ 
    background(200,0,100); 
    pushMatrix(); 
    translate(width/2, height/2); 
    rotate(radians(-18)); 
    for (int r = width ; r >= 0; r = r - 1) 
    { 
    s = 500*exp(-r); 
    fill(202, s, 100); 
    ellipse(100*cos(a), 50*sin(a), r, r); 

    } 
    a+=0.1; 
    popMatrix(); 
} 
+0

好這個問題已經產生了良好的和有用的答案畢竟... –

回答

9

你的問題不是關於模擬電子運動,但更多關於處理有效繪製漸變。我看到你已經開始使用示例>基礎>顏色> RadialGradient示例。請注意,示例本身運行速度很慢,可能是因爲關注如何使用顏色(HSB)和繪圖函數,而不是性能。

你可以做的就是使用PGraphicsPImage來緩存梯度,你可以隨意使用它。

下面是一個使用PGraphics一個例子,如果你不習慣使用像素,這可能是簡單的:使用image()功能類似

PImage e; 
void setup(){ 
    size(500,500); 
    e = getElectronImg(30,30,0,100,100);//create a cached drawing 
} 
void draw(){ 
    background(255); 
    translate(width * .5, height * .5); 
    float a = frameCount * .1; 
    image(e,100*cos(a), 50*sin(a)); 
} 

PImage getElectronImg(int w,int h,int hue,int satMax,int brightness){ 
    PGraphics electron = createGraphics(w+1,h+1);//create a PGraphics object 
    electron.beginDraw();//init drawing using the same Processing drawing functions 
    electron.colorMode(HSB,360,100,100); 
    electron.background(0,0);//transparent bg 
    electron.noStroke(); 
    int cx = electron.width/2; 
    int cy = electron.height/2; 
    for (int r = w; r > 0; --r) { 
     electron.fill(hue,map(r,0,w,satMax,0),brightness); 
     electron.ellipse(cx, cy, r, r); 
    } 
    electron.endDraw(); 
    return electron; 
} 

另外值得一提的是,PGraphics延伸PImage,因此可顯示和其他PImage。

下面是使用像素做了同樣的緩存概念:

PImage e; 
void setup(){ 
    size(500,500); 
    e = getElectronImg(30,30,0,100,100); 
} 
void draw(){ 
    background(255); 
    translate(width * .5, height * .5); 
    float a = frameCount * .1; 
    image(e,100*cos(a), 50*sin(a)); 
} 

PImage getElectronImg(int w,int h,int hue,int satMax,int brightness){ 
    pushStyle();//isolate drawing styles such as color Mode 
    colorMode(HSB,360,100,100); 
    PImage electron = createImage(w,h,ARGB);//create an image with an alpha channel 
    int np = w * h;//total number of pixels 
    int cx = electron.width/2;//center on x 
    int cy = electron.height/2;//center on y 
    for(int i = 0 ; i < np; i++){//for each pixel 
     int x = i%electron.width;//compute x from pixel index 
     int y = (int)(i/electron.width);//compute y from pixel index 
     float d = dist(x,y,cx,cy);//compute distance from centre to current pixel 
     electron.pixels[i] = color(hue,map(d,0,cx,satMax,0),brightness,map(d,0,cx,255,0));//map the saturation and transparency based on the distance to centre 
    } 
    electron.updatePixels();//finally update all the pixels 
    popStyle(); 
    return electron; 
} 

當然,這將可以很容易地使用更多的電子。從真實的電子運動 題外話,這裏有一些有趣的測試,通過使小的調整,得出():

void draw(){ 
    background(255); 
    translate(width * .5, height * .5); 
    for(int i = 0 ; i < 200 ; i++){ 
    float a = (frameCount * .025 + (i*.1)); 
    image(e,(100+i)*cos(a + i), (50+i)*sin(a + i)); 
    } 
} 

200

void draw(){ 
    background(255); 
    translate(width * .5, height * .5); 
    for(int i = 0 ; i < 1000 ; i++){ 
    float a = (frameCount * .025 + (i*.1)); 
    image(e,(100+(i * .25))*cos(a + i), (50+(i * .25))*sin(a + i)); 
    } 
} 

1000

void draw(){ 
    background(255); 
    translate(width * .5, height * .5); 
    scale(.25); 
    for(int i = 0 ; i < 5000 ; i++){ 
    float a = (frameCount * .025 + (i*.1)); 
    image(e,sin(a) * (100+(i * .5))*cos(a + i), (50+(i * .25))*sin(a + i)); 
    } 
} 

5K

玩的開心!

現在你可以實際運行的代碼就在這裏(使用鍵1,2,3,4改變演示):

var e,demo = 2; 
 
function setup(){ 
 
    createCanvas(500,500); 
 
    e = getGradientImg(30,30,0,100,100); 
 
} 
 
function draw(){ 
 
    background(255); 
 
    translate(width * .5, height * .5); 
 
    if(demo == 1){ 
 
    var a = frameCount * .1; 
 
    image(e,100*cos(a), 50*sin(a)); 
 
    } 
 
    if(demo == 2){ 
 
    for(var i = 0 ; i < 200 ; i++){ 
 
     var a = (frameCount * .025 + (i*.1)); 
 
     image(e,(100+i)*cos(a + i), (50+i)*sin(a + i)); 
 
    } 
 
    } 
 
    if(demo == 3){ 
 
    for(var i = 0 ; i < 1000 ; i++){ 
 
     var a = (frameCount * .025 + (i*.1)); 
 
     image(e,(100+(i * .25))*cos(a + i), (50+(i * .25))*sin(a + i)); 
 
    } 
 
    } 
 
    if(demo == 4){ 
 
    scale(.2); 
 
    for(var i = 0 ; i < 5000 ; i++){ 
 
     var a = (frameCount * .025 + (i*.1)); 
 
     image(e,sin(a) * (100+(i * .5))*cos(a + i), (50+(i * .25))*sin(a + i)); 
 
    } 
 
    } 
 
} 
 
function keyReleased(){ 
 
    if(key === '1') demo = 1; 
 
    if(key === '2') demo = 2; 
 
    if(key === '3') demo = 3; 
 
    if(key === '4') demo = 4; 
 
} 
 

 
function getGradientImg(w,h,hue,satMax,brightness){ 
 
    push();//isolate drawing styles such as color Mode 
 
    colorMode(HSB,360,100,100); 
 
    var gradient = createImage(w,h);//create an image with an alpha channel 
 
    var np = w * h;//total number of pixels 
 
    var np4 = np*4; 
 
    var cx = floor(gradient.width * 0.5);//center on x 
 
    var cy = floor(gradient.height * 0.5);//center on y 
 
    gradient.loadPixels(); 
 
    for(var i = 0 ; i < np4; i+=4){//for each pixel 
 
     var id4 = floor(i * .25); 
 
     var x = id4%gradient.width;//compute x from pixel index 
 
     var y = floor(id4/gradient.width);//compute y from pixel index 
 
     var d = dist(x,y,cx,cy);//compute distance from centre to current pixel 
 
     //map the saturation and transparency based on the distance to centre 
 
     gradient.pixels[i] = hue; 
 
     gradient.pixels[i+1] = map(d,0,cx,satMax,0); 
 
     gradient.pixels[i+2] = brightness; 
 
     gradient.pixels[i+3] = map(d,0,cx,255,0); 
 
    } 
 
    gradient.updatePixels();//finally update all the pixels 
 
    pop(); 
 
    return gradient; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>