如何在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
相关产品推荐
相关产品推荐

