p5js WEBGL 中 createGraphics 的分层问题

问题描述 投票:0回答:1

我在将资产和对象放入草图中时遇到了一些困难。目前我遇到的两个问题是植物需要展示在飞机前面,还有一个小问题是我如何清理画布。

对于第一期,我尝试重新排列代码的顺序,但由于某种原因,植物总是在飞机后面,而它应该在飞机前面。

我尝试为第二个问题实施 createGraphics,以便在绘制植物的一次迭代后保留类创建的绘图。但是,我不确定如何实现背景或如何清除它以便始终显示植物。我不想实现 noLoop(),因为植物最终会生长。

任何帮助将不胜感激,谢谢!

let gui;
let ui;

let plantGraphics;

const len = 4;
const ang = 25;

let drawRules;

let word = "X";

let rules = {
  X: [
    // Original rule
    { rule: "F[+X][-X]FX", prob: 0.5 },
    // Fewer limbs
    { rule: "F[-X]FX", prob: 0.05 },
    { rule: "F[+X]FX", prob: 0.05 },
    // Extra rotation
    { rule: "F[++X][-X]FX", prob: 0.1 },
    { rule: "F[+X][--X]FX", prob: 0.1 },
    // Berries/fruits
    { rule: "F[+X][-X]FA", prob: 0.1 },
    { rule: "F[+X][-X]FB", prob: 0.1 },
  ],
  F: [
    // Original rule
    { rule: "FF", prob: 0.85 },
    // Extra growth
    { rule: "FFF", prob: 0.05 },
    // Stunted growth
    { rule: "F", prob: 0.1 },
  ],
};

const planeWidth = 200;
const planeHeight = 200;
let platformRotation = 0;

let sapling;
let saplingPlanted = false;

function setup() {
  createCanvas(400, 400, WEBGL);
  background(220);
  
  ui = {
  // regrow: function() {
  //   console.log('button clicked')
  //   growPlant();
  // },
  // Camera Settings
    X: 0,
    Y: -150,
    Z: -400,
    centerX: 0,
    centerY: 0,
    centerZ: 0,
    upX: 0,
    upY: 1,
    upZ: 0,
  };
  
  gui = new dat.GUI();
  
  // gui.add(ui, 'regrow').name('Click Me!');

  let cameraFolder = gui.addFolder('Camera Settings');
  cameraFolder.add(ui, 'X', -2000, 400);
  cameraFolder.add(ui, 'Y', -2000, 400);
  cameraFolder.add(ui, 'Z', -2000, 400);
  cameraFolder.add(ui, 'centerX', -2000, 400);
  cameraFolder.add(ui, 'centerY', -2000, 400);
  cameraFolder.add(ui, 'centerZ', -2000, 400);
  cameraFolder.add(ui, 'upX', -1, 1);
  cameraFolder.add(ui, 'upY', -1, 1);
  cameraFolder.add(ui, 'upZ', -1, 1);
  
  drawRules = {
    "A": () => {
      // Draw circle at current location
      // noStroke();
      // fill("#E5CEDC");
      stroke("#E5CEDC");
      strokeWeight(5);
      // circle(0, 0, len*2);
      point(0, 0, len*2)
    },  
    "B": () => {
      // Draw circle at current location
      // noStroke();
      // fill("#FCA17D");
      // circle(0, 0, len*2);
      stroke("#FCA17D");
      strokeWeight(2);
      point(0, 0, len*2)
    },
    "F": () => {
      // Draw line forward, then move to end of line
      // const nextY = currentY - len;
      // if (nextY > -maxY) { 
      stroke("#9ea93f");
      line(0, 0, 0, -len);
      // beginShape();
      // vertex(0, 0, 0);
      // vertex(0, 0, -len);
      // endShape();
      translate(0, -len);
      // }
    },
    "+": () => {
      // Rotate right
      rotate(PI/180 * -ang);
    },
    "-": () => {
      // Rotate right
      rotate(PI/180 * ang);
    },
    // Save current location
    "[": push,
    // Restore last location
    "]": pop,
  };
  
  plantGraphics = createGraphics(width, height, WEBGL);
  plantGraphics.sapling = new Plant(0, 0, 0);

}

function draw() {
 
    if (
      mouseIsPressed &&
      mouseX >= 0 &&
      mouseX <= width &&
      mouseY >= 0 &&
      mouseY <= height) {
      
    platformRotation += mouseX - pmouseX;
  }
  
  rotateX(PI / 2);
  rotateZ(radians(platformRotation));
  
  push();
  noStroke();
  fill(255)
  plane(planeWidth, planeHeight);
  pop();
  
  // background(211, 217, 219);

    // sapling.plantSapling();
  plantGraphics.sapling.grow();
  image(plantGraphics, -width/2, -height/2);
  

  // sapling.translate(-width/2, -height/2, 0); // center graphics buffer
  // image(sapling.pg, 0, 0);

  // background(211, 217, 219);

  let cameraZ = ui.Z;
  let cameraX = ui.X;
  let cameraY = ui.Y;
  let centerX = ui.centerX;
  let centerY = ui.centerY;
  let centerZ = ui.centerZ;
  let upX = ui.upX;
  let upY = ui.upY;
  let upZ = ui.upZ;

  camera(cameraX, cameraY, cameraZ, centerX, centerY, centerZ, upX, upY, upZ);
}

class Plant {
  constructor(x, y, z) {
    this.pos = createVector(x, y, z);
    this.vel = createVector();
    this.acc = createVector();
    this.grown = false;
    
    this.len = 3;
    this.angle = 25;
    this.numGens = 6;
    this.word = "X";
    // this.next = ""
    this.next;
    
    this.drawRules = {
      A: () => {
        // Draw circle at current location
        // noStroke();
        // fill("#E5CEDC");
        // circle(0, 0, this.len * 2);
        stroke("#E5CEDC");
        strokeWeight(this.len * 2);
        point(this.pos.x, this.pos.y, this.pos.z);
      },
      B: () => {
        // Draw circle at current location
        // noStroke();
        // fill("#FCA17D");
        // circle(0, 0, this.len * 2);
        stroke("#FCA17D");
        strokeWeight(this.len * 2);
        point(this.pos.x, this.pos.y, this.pos.z);
      },
      F: () => {
        // Draw line forward, then move to end of line
        stroke("#9ea93f");
        // line(0, 0, 0, -this.len);
        // translate(0, -this.len);
        line(this.pos.x, this.pos.y, this.pos.z, this.pos.x, this.pos.y, -this.len);
        translate(this.pos.x, this.pos.y, this.len);
      },
      "+": () => {
        // Rotate right
        rotate((PI / 180) * -this.angle);
      },
      "-": () => {
        // Rotate right
        rotate((PI / 180) * this.angle);
      },
      // Save current location
      "[": push,
      // Restore last location
      "]": pop,
    };
  }
  grow() {
    if (this.grown) return;
    
    let next = "";
    let word = "X";
    for (let i = 0; i < this.numGens; i++) {
      word = this.generateWord(word);
    }
    for (let i = 0; i < word.length; i++) {
      let c = word[i];
      if (c in this.drawRules) {
        this.drawRules[c]();
      }
    }
    this.grown = true;
  }
  generateWord(word) {
    let next = "";
    for (let i = 0; i < word.length; i++) {
      let c = word[i];
      if (c in rules) {
        let rule = rules[c];
        if (Array.isArray(rule)) {
          next += this.chooseOne(rule);
        } else {
          next += rules[c];
        }
      } else {
        next += c;
      }
    }
    return next;
  }
  chooseOne(ruleSet) {
    let n = random(); // Random number between 0-1
    let t = 0;
    for(let i = 0; i < ruleSet.length; i++) {
      t += ruleSet[i].prob; // Keep adding the probability of the options to total
      if(t > n) { // If the total is more than the random value
        return ruleSet[i].rule; // Choose that option
      }
    }
    return "";
  }
}
html, body {
  margin: 0;
  padding: 0;
}
canvas {
  display: block;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/addons/p5.sound.min.js"></script>
    <!-- import dat.gui -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />

  </head>
  <body>
    <main>
    </main>
    <script src="sketch.js"></script>
  </body>
</html>

javascript p5.js l-systems
1个回答
0
投票

您的代码有几个问题:

1。尝试使用 createGraphics

你正试图将你的树苗绘制到一个单独的缓冲区,但你所有的绘图指令都使用全局绘图函数。将

Plant
类的实例分配为
Graphics
实例的属性没有任何效果。如果你真的想把你的树苗画到
Graphics
你需要在从
Graphics
.
 返回的 
createGraphics

对象上使用实例方法

2。耦合 L-System 规则迭代和绘图

第 1 点已经完成,我不认为将你的树苗绘制到单独的缓冲区是一个好的解决方案。您必须尝试这样做的原因是因为绘制树苗的逻辑和迭代 L 系统规则的逻辑在

grow()
函数中混合在一起,该函数只能调用一次。如果将绘图代码移动到单独的函数中,则可以调用一次
grow()
,但每帧为
Plant
调用一次绘图函数。

3。使用
rotate()
功能

在绘制规则函数中,您在 3d 中绘制线条,唯一的变化是沿 Z 轴,然后使用

rotate()
函数进行旋转指令。这是有问题的,因为
rotate()
函数旋转aroundZ轴,所以这对随后绘制的线没有影响。

工作示例

let rules = {
  X: [
    // Original rule
    { rule: "F[+X][-X]FX", prob: 0.5 },
    // Fewer limbs
    { rule: "F[-X]FX", prob: 0.05 },
    { rule: "F[+X]FX", prob: 0.05 },
    // Extra rotation
    { rule: "F[++X][-X]FX", prob: 0.1 },
    { rule: "F[+X][--X]FX", prob: 0.1 },
    // Berries/fruits
    { rule: "F[+X][-X]FA", prob: 0.1 },
    { rule: "F[+X][-X]FB", prob: 0.1 },
  ],
  F: [
    // Original rule
    { rule: "FF", prob: 0.85 },
    // Extra growth
    { rule: "FFF", prob: 0.05 },
    // Stunted growth
    { rule: "F", prob: 0.1 },
  ],
};

const planeWidth = 200;
const planeHeight = 200;

let sapling;

function setup() {
  createCanvas(400, 400, WEBGL);

  sapling = new Plant(0, 0, 0);
  sapling.grow();
  console.log(sapling.word);
}

function draw() {
  background(150);
  orbitControl();

  rotateX(PI / 2);
  noStroke();
  fill(255);
  plane(planeWidth, planeHeight);

  sapling.draw();
}

class Plant {
  constructor(x, y, z) {
    this.pos = createVector(x, y, z);
    this.vel = createVector();
    this.acc = createVector();
    this.grown = false;

    this.len = 3;
    this.angle = 25;
    this.numGens = 6;
    this.word = "X";

    this.drawRules = {
      A: () => {
        // Draw circle at current location
        // noStroke();
        // fill("#E5CEDC");
        // circle(0, 0, this.len * 2);
        stroke("#E5CEDC");
        strokeWeight(this.len * 2);
        point(this.pos.x, this.pos.y, this.pos.z);
      },
      B: () => {
        // Draw circle at current location
        // noStroke();
        // fill("#FCA17D");
        // circle(0, 0, this.len * 2);
        stroke("#FCA17D");
        strokeWeight(this.len * 2);
        point(this.pos.x, this.pos.y, this.pos.z);
      },
      F: () => {
        // Draw line forward, then move to end of line
        stroke("#9ea93f");
        // line(0, 0, 0, -this.len);
        // translate(0, -this.len);
        line(
          this.pos.x,
          this.pos.y,
          this.pos.z,
          this.pos.x,
          this.pos.y,
          -this.len
        );
        translate(this.pos.x, this.pos.y, this.len);
      },
      "+": () => {
        // Rotate right
        rotateY((PI / 180) * -this.angle);
      },
      "-": () => {
        // Rotate right
        rotateY((PI / 180) * this.angle);
      },
      // Save current location
      "[": push,
      // Restore last location
      "]": pop,
    };
  }
  grow() {
    if (this.grown) return;

    let next = "";
    for (let i = 0; i < this.numGens; i++) {
      this.word = this.generateWord(this.word);
    }
    this.grown = true;
  }
  draw() {
    for (let i = 0; i < this.word.length; i++) {
      let c = this.word[i];
      if (c in this.drawRules) {
        this.drawRules[c]();
      }
    }
  }
  generateWord(word) {
    let next = "";
    for (let i = 0; i < word.length; i++) {
      let c = word[i];
      if (c in rules) {
        let rule = rules[c];
        if (Array.isArray(rule)) {
          next += this.chooseOne(rule);
        } else {
          next += rules[c];
        }
      } else {
        next += c;
      }
    }
    return next;
  }
  chooseOne(ruleSet) {
    let n = random(); // Random number between 0-1
    let t = 0;
    for (let i = 0; i < ruleSet.length; i++) {
      t += ruleSet[i].prob; // Keep adding the probability of the options to total
      if (t > n) {
        // If the total is more than the random value
        return ruleSet[i].rule; // Choose that option
      }
    }
    return "";
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.