使用lerp功能(处理)更改位置



+++EDIT++

我有一个单独的矩形网格。现在,我想用Lerp函数将每个单独的矩形移动到一个新的位置(当前为MouseX、MouseY(。到目前为止,我只设法将网格作为一个整体——带有一个不必要的失真。。。这可能是由于translate((;和PushMatrix((中的括号;PopMatrix((;?

我是否必须以完全不同的方式构建网格,以使每个单独的矩形流向鼠标指针?或者是lerp((;只是函数做得不对?

这就是我迄今为止所取得的成就:

float size;
float pixel;
float lx;
float ly;
void setup() {
size(600, 600);
pixel = 100;
size = width/pixel;
rectMode(CENTER);
}
void draw() {
background(0);
//DRAW THE GRID
lx = 0;
ly = 0;
for (int y = 0; y < pixel; y++) {
ly = lerp(ly, mouseY, 0.05);
for (int x = 0; x < pixel; x++) {
lx = lerp(lx, mouseX, 0.05);
pushMatrix();
translate(size/2, size/2);
translate(x*size, y*size);
rotate(radians(45));
fill(255);
noStroke();
rect(lx, ly, size, size);
popMatrix();
}
}
}

以我构建网格的方式,这可能吗?

您的lerp函数用于计算两个位置之间的步长,因此您需要转换的起始位置和结束位置,并且您将多次调用lerp来重新计算每个步长。您可以将lerp视为计算源和目标之间距离的百分比,同时以递增的步骤将最后一个参数从0.0更改为1.0。

rectY=?;
rectX=?; // Replace the '?' marks with the left and top starting positions of your rectangle
for (int step=1; step<=20; step++) {
lx = lerp(rectX, mouseX, 0.05 * step);
ly = lerp(rectY, mouseY, 0.05 * step);
...
}

您已经通过lerp()获得了缓解。

下面是一个使用单个网格元素的简化示例:

float easeAmount = 0.05;
float lx, ly;
void setup(){
size(600, 600); 
}
void draw(){
lx = lerp(lx, mouseX, easeAmount);
ly = lerp(ly, mouseY, easeAmount);

background(0);
quad(lx, ly, 30);
}
void quad(float x, float y, float size){
float halfSize = size * 0.5;
quad(x            , y - halfSize, // top
x + halfSize , y           , // right
x            , y + halfSize, // bottom
x - halfSize , y             // left
);
}

人工宽松非常相似:

float easeAmount = 0.05;
float lx, ly;
void setup(){
size(600, 600); 
}
void draw(){
lx += (mouseX - lx) * easeAmount;
ly += (mouseY - ly) * easeAmount;;

background(0);
quad(lx, ly, 30);
}
void quad(float x, float y, float size){
float halfSize = size * 0.5;
quad(x            , y - halfSize, // top
x + halfSize , y           , // right
x            , y + halfSize, // bottom
x - halfSize , y             // left
);
}

上面草图的想法是简单地回到单个元素(并放弃推/弹出矩阵和旋转调用(

您的方法的一个问题是,所有网格元素都有一对lx/ly坐标:拥有独立的对可能更容易:每个元素一对。

下面是一个使用2D阵列为每个网格元素存储一对缓和位置的示例:

float easeAmount = 0.05;
// rows and columns
int gridSize = 100;
int numElements = gridSize * gridSize;
float gridElementSize = 6;
float[][] positions = new float[numElements][2];
void setup(){
size(600, 600); 

// initialise grid positions
int elementIndex = 0;
for(int y = 0 ; y < gridSize; y++){
for(int x = 0; x < gridSize; x++){
// grid x position
positions[elementIndex][0] = x * gridElementSize; 
// grid y position
positions[elementIndex][1] = y * gridElementSize; 
// increment element counter
elementIndex++;
}
}
}
void draw(){
background(0);

for(int elementIndex = 0; elementIndex < numElements; elementIndex++){
positions[elementIndex][0]  = lerp(positions[elementIndex][0] , mouseX, easeAmount);
positions[elementIndex][1]  = lerp(positions[elementIndex][1] , mouseY, easeAmount);

// render updated quad
quad(positions[elementIndex][0], positions[elementIndex][1], gridElementSize);
}

}
void quad(float x, float y, float size){
float halfSize = size * 0.5;
quad(x            , y - halfSize, // top
x + halfSize , y           , // right
x            , y + halfSize, // bottom
x - halfSize , y             // left
);
}

请注意,单个元素向鼠标移动,但移动速度相同,看起来像是一个组。

然而,你可以添加一点随机性来打破单调的运动:

float easeAmount = 0.05;
// rows and columns
int gridSize = 100;
int numElements = gridSize * gridSize;
float gridElementSize = 6;
float[][] positions = new float[gridSize * gridSize][2];
void setup(){
size(600, 600); 
noStroke();
// initialise grid positions
int elementIndex = 0;
for(int y = 0 ; y < gridSize; y++){
for(int x = 0; x < gridSize; x++){
// grid x position
positions[elementIndex][0] = x * gridElementSize; 
// grid y position
positions[elementIndex][1] = y * gridElementSize; 
// increment element counter
elementIndex++;
}
}
}
void draw(){
background(0);
// render all quads in one go
beginShape(QUADS);
for(int elementIndex = 0; elementIndex < numElements; elementIndex++){
positions[elementIndex][0]  = lerp(positions[elementIndex][0] , mouseX, random(easeAmount));
positions[elementIndex][1]  = lerp(positions[elementIndex][1] , mouseY, random(easeAmount));

// render updated quad
quad(positions[elementIndex][0], positions[elementIndex][1], gridElementSize);
}
endShape();

}
void quad(float x, float y, float size){
float halfSize = size * 0.5;
vertex(x            , y - halfSize); // top
vertex(x + halfSize , y           ); // right
vertex(x            , y + halfSize); // bottom
vertex(x - halfSize , y           ); // left
}

请随意探索其他选择。

它可能有助于将功能封装在可重用的类中并使用PVector。如果这是目前的一个高级话题,请查看Daniel Shiffman的《代码的本质》视频和(免费(在线书籍。

以下是Daniel Shiffman的Repeller示例的修改版本,该示例被修改为使用网格:

// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
ParticleSystem ps;
Repeller repeller;
void setup() {
size(600,600);
strokeWeight(6);

ps = new ParticleSystem(new PVector(width/2,50));
repeller = new Repeller(width/2-20,height/2);

}
void draw() {
repeller.position.set(mouseX, mouseY);

background(255);

ps.applyRepeller(repeller);

ps.run();
}
void mousePressed(){
repeller.G = -1000;
}
void mouseReleased(){
repeller.G = 1000;
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class Particle {
PVector position;
PVector velocity;
PVector acceleration;
float lifespan;

float mass = 100; // Let's do something better here!

PVector initialPosition;

Particle(PVector l) {
initialPosition = l.get();
reset();
}

void reset(){
acceleration = new PVector(0,0);
velocity = new PVector();
position = initialPosition.get();
lifespan = 255.0;
}
void run() {
update();
display(g);
}
void applyForce(PVector force) {
PVector f = force.get();
f.div(mass);   
acceleration.add(f);
}
// Method to update position
void update() {
velocity.add(acceleration);
position.add(velocity);
acceleration.mult(0);
lifespan -= .2;
}
// Method to display
void display(PGraphics g) {
g.stroke(0,lifespan);
g.vertex(position.x,position.y);
}
// Is the particle still useful?
boolean isDead() {
if (lifespan < 0.0) {
return true;
} else {
return false;
}
}
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
class ParticleSystem {
ArrayList<Particle> particles;
PVector origin;

int numParticles = 10000;
int particleIndex = 0;
ParticleSystem(PVector position) {
origin = position.get();
particles = new ArrayList<Particle>();
for(int i = 0; i < numParticles; i++){
addParticle();
}
}
void addParticle() {
particles.add(new Particle(new PVector(particleIndex % 100 * 6, particleIndex / 100 * 6)));
particleIndex++;
}
// A function to apply a force to all Particles
void applyForce(PVector f) {
for (Particle p: particles) {
p.applyForce(f);
}
}
void applyRepeller(Repeller r) {
for (Particle p: particles) {
PVector force = r.repel(p);        
p.applyForce(force);
}
}

void run() {
beginShape(POINTS);
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
//particles.remove(i);
p.reset();
}
}
endShape();
}
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Particles + Forces
// A very basic Repeller class
class Repeller {

// Gravitational Constant
float G = 1000;
// position
PVector position;
float r = 10;
Repeller(float x, float y)  {
position = new PVector(x,y);
}
void display() {
stroke(0);
strokeWeight(2);
fill(175);
ellipse(position.x,position.y,48,48);
}
// Calculate a force to push particle away from repeller
PVector repel(Particle p) {
PVector dir = PVector.sub(position,p.position);      // Calculate direction of force
float d = dir.mag();                       // Distance between objects
dir.normalize();                           // Normalize vector (distance doesn't matter here, we just want this vector for direction)
d = constrain(d,5,100);                    // Keep distance within a reasonable range
float force = -1 * G / (d * d);            // Repelling force is inversely proportional to distance
dir.mult(force);                           // Get force vector --> magnitude * direction
return dir;
}  
}

注意粒子褪色(基于Particle的寿命(,然后重置

(这让我想起了十年前我的一个朋友在JS中编码的一个效果:http://js1k.com/2011-trail/demo/908。它使用了普通的JS,但在概念上仍然使用类的等价物来表示每个粒子,这些粒子具有控制速度和位置的属性(。

最新更新