You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在p5.js中对3D空间内的向量进行旋转以实现3D面向对象分形树?

3D分形树的向量旋转解决方案

嘿,作为编程新手就敢尝试把2D分形树升级成3D,这想法超棒!我来帮你搞定这个p5.js里3D向量旋转的问题~

问题根源

你说得没错,p5.js的p5.Vector.rotate()方法确实只支持2D向量(它默认绕Z轴旋转平面向量),没法直接用来做3D空间的旋转。要实现3D分支的方向变换,我们需要用旋转矩阵来处理3D向量,p5.js已经内置了生成旋转矩阵的函数,直接用就好啦!

具体解决方案

我们可以用createRotationX()、createRotationY()、createRotationZ()这三个函数生成对应轴的旋转矩阵,然后通过p5.Vector.applyMatrix()方法让方向向量应用这个旋转,这样就能实现3D空间的方向偏转了。

另外,我还帮你修正了原代码里的一些小问题(比如finished和finishedGrowing命名不一致的bug),同时优化了叶子的3D显示效果,让它们始终面向相机。

修改后的完整代码

var tree = []; 
var leaves = []; 
var count = 0; 

function setup() { 
  createCanvas(windowWidth, windowHeight, WEBGL); 
  angleMode(DEGREES);
  var a = createVector(0, 0, 0); 
  var b = createVector(0, -100, 0); 
  var root = new Branch(a, b); 
  tree[0] = root; 
} 

function mousePressed() { 
  for (var i = tree.length - 1; i >= 0; i--) { 
    if (!tree[i].finished) { 
      tree.push(tree[i].branchA());
      tree.push(tree[i].branchB());
    } 
    tree[i].finished = true; 
  } 
  count++;
  if (count === 8) { 
    for (var i = 0; i < tree.length; i++) { 
      if (!tree[i].finished) { 
        var leaf = tree[i].end.copy(); 
        leaves.push(leaf); 
      } 
    } 
  } 
} 

function draw() { 
  background(51); 
  orbitControl(); // 打开这个可以用鼠标拖拽旋转视角,方便看3D效果
  rotateY(frameCount); 
  translate(0, 200, 0); 
  
  for (var i = 0; i < tree.length; i++) { 
    tree[i].show(); 
  } 
  
  // 绘制3D叶子
  for (var i = 0; i < leaves.length; i++) { 
    push();
    translate(leaves[i].x, leaves[i].y, leaves[i].z);
    // 让叶子始终面向相机,抵消全局旋转的影响
    rotateY(-frameCount);
    fill(255, 0, 100); 
    noStroke(); 
    ellipse(0, 0, 8, 8); 
    pop();
  } 
} 

function Branch(begin, end) { 
  this.begin = begin; 
  this.end = end; 
  this.finished = false; // 统一命名,修复原代码的逻辑bug

  this.show = function() { 
    stroke(255); 
    line(this.begin.x, this.begin.y, this.begin.z, this.end.x, this.end.y, this.end.z); 
  } 

  this.branchA = function() { 
    var direction = p5.Vector.sub(this.end, this.begin); 
    // 绕Y轴旋转45度(可以换成随机值让树更自然)
    let rotY = createRotationY(45);
    direction.applyMatrix(rotY);
    // 可以叠加其他轴的旋转,比如绕X轴转15度
    // let rotX = createRotationX(15);
    // direction.applyMatrix(rotX);
    direction.mult(0.67); 
    var newEnd = p5.Vector.add(this.end, direction); 
    var b = new Branch(this.end, newEnd); 
    return b; 
  } 

  this.branchB = function() { 
    var direction = p5.Vector.sub(this.end, this.begin);
    // 绕Y轴反向旋转15度,也可以换成随机范围,比如random(-30, 30)
    let rotY = createRotationY(-15);
    direction.applyMatrix(rotY);
    direction.mult(0.67); 
    var newEnd = p5.Vector.add(this.end, direction); 
    var b = new Branch(this.end, newEnd); 
    return b; 
  } 
} 

额外优化建议

  • 打开orbitControl()后,你可以按住鼠标左键拖拽旋转整个3D场景,滚轮缩放,方便查看树的各个角度
  • 如果想让树看起来更自然,可以把固定的旋转角度换成随机值,比如createRotationY(random(-30, 30)),这样每个分支的偏转方向都不一样
  • 可以尝试给不同层级的分支设置不同的粗细,让树的结构更真实

内容的提问来源于stack exchange,提问作者tommyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:39:08