如何在处理中从中心连接球体?

How to Connect Spheres from center in Processing?

目前我正在尝试连接在设定距离内接近的球体。我尝试使用 line(x1,y1,z1,x2,y2,z2) 函数,但这会创建一些随机线。然后我尝试使用贝塞尔曲线,但我仍然得到奇怪的结果。

目前的代码如下:

import peasy.*;

ArrayList<Position> positions;
int count=0;
int distanceToDrawLines = 20;
PeasyCam camera;

void setup() {
  size(1280, 720, P3D);
  stroke(255);
  positions = new ArrayList<Position>();
  smooth(8);
  lights();
}

void draw() {  
  float randomX, randomY, randomZ;
  //camera(mouseX, height/2, (height/2) / tan(PI/6), width/2, height/2, 0, 0, 1, 0);
  //camera = new PeasyCam(this, 0, 0, 0, 0);
  randomX = random(0, width);
  randomY = random(0, height);
  randomZ = random(0, 40);

  Position newPosition = new Position(new PVector(randomX, randomY, randomZ), 20);
  positions.add(newPosition);
  fill(255, 0, 0, 75);
  stroke(0);
  newPosition.Draw();


  for (int i=0; i<positions.size(); i++) {
    Position position = positions.get(i);
    noFill();
    beginShape();
    vertex(position.vector.x,position.vector.y,position.vector.z);
    if (position!=newPosition) {
      float d = dist(position.vector.x, position.vector.y, position.vector.z, newPosition.vector.x, newPosition.vector.y, newPosition.vector.z);

      if (d<=distanceToDrawLines && d!=0) {
        println(d, positions.size(), position.vector, newPosition.vector);
        bezierVertex(position.vector.x, position.vector.y, position.vector.z, newPosition.vector.x, newPosition.vector.y, newPosition.vector.z);
      }
    }
    endShape();
  }

}

Position class:

public class Position {
  public PVector vector;
  private boolean drawn;
  public float radius;

  public Position(PVector vector, float radius) {
    this.vector = vector;
    this.radius = radius;
  }

  public void DrawSphere() {
    if (!drawn) {
      fill(255, 0, 0, 75);
      noStroke();
      translate(vector.x, vector.y, vector.z);
      sphere(radius);
      fill(0);
      stroke(0);
      drawn = true;
    }
  }

  public void DrawEllipse() {
    if (!drawn) {
      fill(random(0,255), random(0,255), random(0,255), 75);
      noStroke();
      ellipse(vector.x, vector.y, radius, radius);
      point(vector.x, vector.y);
      fill(0);
      drawn = true;
    }
  }
}

如有任何帮助,我们将不胜感激。

谢谢!

您还没有发布职位 class 所以我假设它大致如下所示:

class Position{
  PVector vector;
  float radius;

  Position(PVector pos,float rad){
    vector = pos;
    radius = rad; 
  }

  void Draw(){
    pushMatrix();
    translate(vector.x,vector.y,vector.z);
    sphere(radius);
    popMatrix();
  }

}

有些事情似乎没有反映您的意图:

  1. 您在绘制新框架时没有清除背景。由于未清除帧缓冲区,这可能会导致在旋转相机时到处都是线条。
  2. 相机目前已被注释掉,可能应该在 setup() 中初始化一次,而不是在 draw()
  3. 中每帧初始化多次
  4. 每秒多次生成球体可能会导致渲染成本高昂,而且在理解上有点混乱:我建议限制最初生成的球体数量。也许那是您 count 变量的意图?
  5. 这部分:

spheres that are close within a set distance

听起来有点不清楚。它看起来不像是设置了距离,因为您在最近的 Position 实例中比较的距离之一是随机位置。 (除非你真的想比较最近的 sphere/Position 实例的距离)

除此之外,我还有一些简化此设置的提示:

  1. 对随机值使用正负范围将有助于'centre'球体分布(因为只有正值才会使组向右移动)
  2. 利用 PVector's dist()

    做同样的事情

    dist(position.vector.x, position.vector.y, position.vector.z, newPosition.vector.x, newPosition.vector.y, newPosition.vector.z); 但保持语法更简洁:position.vector.dist(newPosition.vector);

您可以在基于您的代码的修订和注释版本中尝试这些建议(使用 up/down 键更改距离阈值):

in-processing
import peasy.*;

ArrayList<Position> positions;
int count=0;

//increase the distance threshold value: with a wider range of random values there will be less chances of spheres being so close to each other
int distanceToDrawLines = 200;
PeasyCam camera;

//keep a reference to the most recent Position instance
Position newPosition = null;

void setup() {
  size(1280, 720, P3D);
  stroke(255);
  positions = new ArrayList<Position>();
  smooth(8);
  lights();

  //use simplified spheres (will look blockier, but will render faster)
  sphereDetail(5);
  //setup PeasyCam once in setup
  camera = new PeasyCam(this, 100);
  camera.setMinimumDistance(50);
  camera.setMaximumDistance(500);
}

void draw() {  
  background(127);

  //generate a limited amount of spheres
  if(count < 100){

    float randomX, randomY, randomZ;
    randomX = random(-width, width);
    randomY = random(-height, height);
    randomZ = random(-40, 40);

    newPosition = new Position(new PVector(randomX, randomY, randomZ), 20);
    positions.add(newPosition);

    count++;
  }


  for (int i=0; i<positions.size(); i++) {
    Position position = positions.get(i);

    noFill();

    if (position != newPosition) {

      float d = position.vector.dist(newPosition.vector);

      if (d<=distanceToDrawLines && d!=0) {
        println(d, positions.size(), position.vector, newPosition.vector);
        line(position.vector.x, position.vector.y, position.vector.z, newPosition.vector.x, newPosition.vector.y, newPosition.vector.z);
      }
    }else{
      //hightlight newest Position instance in transparent red
      fill(255, 0, 0, 75);
    }
    //render every Position instance (after the noFill() / fill() have been set
    position.Draw();

  }

}
//test - play with UP/DOWN arrows to tinker with distance
void keyPressed(){
  if(keyCode == UP) distanceToDrawLines += 10;
  if(keyCode == DOWN) distanceToDrawLines -= 10;
  distanceToDrawLines = constrain(distanceToDrawLines,20,2000);
  println("distanceToDrawLines: " + distanceToDrawLines);
}

class Position{
  PVector vector;
  float radius;

  Position(PVector pos,float rad){
    vector = pos;
    radius = rad; 
  }

  void Draw(){
    pushMatrix();
    translate(vector.x,vector.y,vector.z);
    sphere(radius);
    popMatrix();
  }

}

这里更新的是一个示例,强调了评论中提到的一些优化概念。理想情况下,一些代码将移至着色器,但值得使用 jvisualvm 来追踪当前哪些调用花费了大部分时间来执行并开始在那里进行优化。

import peasy.*;

ArrayList<Position> positions;
Position newPosition;
int count=0;
int distanceToDrawLines = 500;
PeasyCam cam;

PShape nodes;

int fcount, lastm;
float frate;
int fint = 3;

void setup() {
  size(1280, 720, P3D);
  positions = new ArrayList<Position>();
  smooth(8);
  lights();

  //use simplified spheres (will look blockier, but will render faster)
  sphereDetail(0);//5
  frameRate(60);
  cam = new PeasyCam(this, 100);
  cam.setMinimumDistance(50);
  cam.setMaximumDistance(500);

  nodes = createShape(GROUP);

  while (count < 300) {
    float randomX, randomY, randomZ, randomRadius;
    randomX = random(-width*2, width*2);
    randomY = random(-height*2, height*2);
    randomZ = random(-1000*2, 1000*2);
    randomRadius = random(10, 40);
    newPosition = new Position(new PVector(randomX, randomY, randomZ), randomRadius);
    positions.add(newPosition);
    count++;
  }
  println("positions initialized");

  //calculate distances once, rather than multiple times per seconds
  //similarly instantiate geometries, which will simply be rendered in draw() 
  float distanceToDrawLinesSq = distanceToDrawLines * distanceToDrawLines;
  int numPositions = positions.size();
  for (int i=0; i<numPositions-1; i++) {
    for (int j=i+1; j<positions.size(); j++) {
      Position iPosition = positions.get(i);
      //iPosition.DrawSphere();
      nodes.addChild(getSphere(iPosition));
      Position jPosition = positions.get(j);
      //jPosition.DrawSphere();
      nodes.addChild(getSphere(jPosition));
      //cam.lookAt(iPosition.vector.x, iPosition.vector.y, iPosition.vector.z, 5);
//      float d = iPosition.vector.dist(jPosition.vector);
//      if (d <= distanceToDrawLines) {
      //using distance squared (more useful in draw() than setup though
      float dSq = PVector.sub(iPosition.vector,jPosition.vector).magSq();
      if (dSq <= distanceToDrawLinesSq) {

        PShape line = createShape(LINE,iPosition.vector.x, iPosition.vector.y, iPosition.vector.z, jPosition.vector.x, jPosition.vector.y, jPosition.vector.z);
        line.setStroke(color(255));
        line.setFill(false);
        nodes.addChild(line);

        //stroke(255);
        //line(iPosition.vector.x, iPosition.vector.y, iPosition.vector.z, jPosition.vector.x, jPosition.vector.y, jPosition.vector.z);
      }
    }
  }
  println("geometries initialized");

}
PShape getSphere(Position p){
    PShape sphere = createShape(SPHERE, 1.0);
    sphere.setStroke(false);
    sphere.setFill(p.fillColor);
    sphere.translate(p.vector.x,p.vector.y,p.vector.z);
    sphere.scale(p.radius);
    return sphere;
}
void draw() {  
  background(0);

  hint(DISABLE_DEPTH_TEST);

  pushMatrix();
  translate(width/2, height/2, -500);
  rotateY(frameCount * 0.01);
  rotateX(frameCount * 0.01);

  shape(nodes);
  popMatrix();

  hint(ENABLE_DEPTH_TEST);

  fcount += 1;
  int m = millis();
  if (m - lastm > 1000 * fint) {
    frate = float(fcount) / fint;
    fcount = 0;
    lastm = m;
    println("fps: " + frate);
  }

  //saveFrame("/output3/sequence####.tga");
  //saveFrame in separate thread
  TImage frame = new TImage(width,height,RGB,sketchPath("frame_"+nf(frameCount,3)+".tga"));
  frame.set(0,0,get());
  frame.saveThreaded();
}

class TImage extends PImage implements Runnable{//separate thread for saving images
  String filename;

  TImage(int w,int h,int format,String filename){
    this.filename = filename;
    init(w,h,format);
  }

  public void saveThreaded(){
    new Thread(this).start();
  }

  public void run(){
    this.save(filename);
  }

}

public class Position {
  private float speed;
  public PVector vector;
  public float radius;
  public int fillColor = color(200, 0, 0, 75);

  public Position(PVector vector, float radius) {
    this.vector = vector;
    this.radius = radius;
    this.speed = 0.05;
  }

  public void DrawSphere() {
    noStroke();
    vector.x+=random(-speed, speed);
    vector.y+=random(-speed, speed);
    vector.z+=random(-speed, speed);
    fill(fillColor);
    pushMatrix();
    translate(vector.x, vector.y, vector.z);

    sphere(radius);
    popMatrix();
  }

  public void DrawEllipse() {
    pushMatrix();
    translate(vector.x, vector.y, vector.z);
    ellipse(vector.x, vector.y, radius, radius);
    popMatrix();
  }
}