使用本轮和傅立叶变换绘制/渲染 3D 对象 [动画] [英] Drawing/Rendering 3D objects with epicycles and fourier transformations [Animation]

查看:24
本文介绍了使用本轮和傅立叶变换绘制/渲染 3D 对象 [动画]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第一个注意:他们不会让我嵌入图像,直到我有更多的声望点(对不起),但所有的链接都是在 imgur 上发布的图像!:) 谢谢

First Note: They wont let me embed images until i have more reputation points (sorry), but all the links are images posted on imgur! :) thanks

我复制了一种使用傅立叶变换为任何单个路径(1 个闭合路径)设置动画的方法.这将创建epicylces(旋转圆)的动画,它们围绕彼此旋转,并跟随插补点,以连续循环/函数的形式跟踪路径.

I have replicated a method to animate any single path (1 closed path) using fourier transforms. This creates an animation of epicylces (rotating circles) which rotate around each other, and follow the imputed points, tracing the path as a continuous loop/function.

我想将此系统用于 3D.我能想到的两种方法是使用球坐标系(两个复平面)或 3 个 本轮 --> 每个轴(x,y,z)一个,带有各自的参数方程.可能是最好的开始方式!!

I would like to adopt this system to 3D. the two methods i can think of to achieve this is to use a Spherical Coordinate system (two complex planes) or 3 Epicycles --> one for each axis (x,y,z) with their individual parametric equations. This is probably the best way to start!!

2 个周期,一个用于 X,一个用于 Y:

2 Cycles, One for X and one for Y:

图片:一个循环 --> 复数 --> 对于 X 和 Y

Picture: One Cycle --> Complex Numbers --> For X and Y

傅立叶变换背景!!!:

• 欧拉公式允许我们将复平面中的每个点分解为角度(指数函数的自变量)和幅度(Cn 系数)

• Eulers formula allows us to decompose each point in the complex plane into an angle (the argument to the exponential function) and an amplitude (Cn coefficients)

• 在这个意义上,将上述无穷级数中的每一项成像为表示半径为 cn 的圆上的一个点,偏移 2πnt/T 弧度

• In this sense, there is a connection to imaging each term in the infinite series above as representing a point on a circle with radius cn, offset by 2πnt/T radians

• 下图显示了如何将相位/幅度方面的复数总和可视化为复平面中的一组串联圆.每条红线是一个向量,表示和序列中的一项:cne2πi(nT)t

• The image below shows how a sum of complex numbers in terms of phases/amplitudes can be visualized as a set of concatenated cirlces in the complex plane. Each red line is a vector representing a term in the sequence of sums: cne2πi(nT)t

• 添加被加数对应于简单地连接复杂空间中的每个红色向量:

• Adding the summands corresponds to simply concatenating each of these red vectors in complex space:

动画旋转圆:

动画绘图的圆圈:

• 如果您在 2D (x-y) 空间中绘制了线条,则可以将此路径数学描述为参数函数.(两个单独的单变量函数,都是一个辅助变量(在本例中为 T):

• If you have a line drawing in 2D (x-y) space, you can describe this path mathematically as a parametric function. (two separate single variable functions, both in terms of an auxiliary variable (T in this case):

• 例如,下面是一匹马的简单线条图,以及通过图像中黑色像素的参数化路径,然后将该路径分为 X 和 Y 分量:

• For example, below is a simple line drawing of a horse, and a parametric path through the black pixels in image, and that path then seperated into its X and Y components:

• 此时,我们需要计算这两条路径的傅立叶近似值,并使用该近似值的系数来确定最终可视化所需的圆的相位和幅度.

• At this point, we need to calculate the Fourier approximations of these two paths, and use coefficients from this approximation to determine the phase and amplitudes of the circles needed for the final visualization.

Python 代码:用于此示例的 Python 代码可以在 guithub

Python Code: The python code used for this example can be found here on guithub

我已经成功地在 2D 中为这个过程制作了动画,但我想将其应用到 3D 中.

以下代码表示 2D 中的动画 --> 我已经在工作:

The Following Code Represents Animations in 2D --> something I already have working:

[使用 JavaScript &P5.js 库]

傅立叶算法 (fourier.js):

//  a + bi
class Complex {
  constructor(a, b) {
    this.re = a;
    this.im = b;
  }

  add(c) {
    this.re += c.re;
    this.im += c.im;
  }

  mult(c) {
    const re = this.re * c.re - this.im * c.im;
    const im = this.re * c.im + this.im * c.re;
    return new Complex(re, im);
  }
}



function dft(x) {
  const X = [];
  const Values = [];
  const N = x.length;
  for (let k = 0; k < N; k++) {
    let sum = new Complex(0, 0);
    for (let n = 0; n < N; n++) {
      const phi = (TWO_PI * k * n) / N;
      const c = new Complex(cos(phi), -sin(phi));
      sum.add(x[n].mult(c));
    }
    sum.re = sum.re / N;
    sum.im = sum.im / N;

    let freq = k;
    let amp = sqrt(sum.re * sum.re + sum.im * sum.im);
    let phase = atan2(sum.im, sum.re);
    X[k] = { re: sum.re, im: sum.im, freq, amp, phase };
Values[k] = {phase};
  console.log(Values[k]);

  }
  return X;
}

草图功能/动画 (Sketch.js):

let x = [];
let fourierX;
let time = 0;
let path = [];

function setup() {
  createCanvas(800, 600);
  const skip = 1;
  for (let i = 0; i < drawing.length; i += skip) {
    const c = new Complex(drawing[i].x, drawing[i].y);
    x.push(c);
  }
  fourierX = dft(x);
  fourierX.sort((a, b) => b.amp - a.amp);
}

function epicycles(x, y, rotation, fourier) {
  for (let i = 0; i < fourier.length; i++) {
    let prevx = x;
    let prevy = y;
    let freq = fourier[i].freq;
    let radius = fourier[i].amp;
    let phase = fourier[i].phase;
    x += radius * cos(freq * time + phase + rotation);
    y += radius * sin(freq * time + phase + rotation);

    stroke(255, 100);
    noFill();
    ellipse(prevx, prevy, radius * 2);
    stroke(255);
    line(prevx, prevy, x, y);
  }
  return createVector(x, y);
}

function draw() {
  background(0);

  let v = epicycles(width / 2, height / 2, 0, fourierX);
  path.unshift(v);

  beginShape();
  noFill();
  for (let i = 0; i < path.length; i++) {
    vertex(path[i].x, path[i].y);
  }
  endShape();

  const dt = TWO_PI / fourierX.length;
  time += dt;

最重要的是!路径/坐标:(这个是三角形)

let drawing = [

  { y:  -8.001009734    , x:    -50 },
  { y:  -7.680969345    , x:    -49 },
  { y:  -7.360928956    , x:    -48 },
  { y:  -7.040888566    , x:    -47 },
  { y:  -6.720848177    , x:    -46 },
  { y:  -6.400807788    , x:    -45 },
  { y:  -6.080767398    , x:    -44 },
  { y:  -5.760727009    , x:    -43 },
  { y:  -5.440686619    , x:    -42 },
  { y:  -5.12064623 , x:    -41 },
  { y:  -4.800605841    , x:    -40 },
...
...

  { y:  -8.001009734    , x:    -47 },
  { y:  -8.001009734    , x:    -48 },
  { y:  -8.001009734    , x:    -49 },


];

推荐答案

这个答案是为了回应:你认为 [three.js] 可以复制我在 2D 中但在 3D 中的内容吗?使用旋转圆圈和其他东西?"

This answer is in response to: "Do you think [three.js] can replicate what i have in 2D but in 3D? with the rotating circles and stuff?"

我不确定您是想从头开始学习 3D 建模(即创建自己的矢量例程库、齐次坐标变换、渲染透视等),还是只是想制作最终产品.对于后者,three.js 是一个强大的基于 webGL 的图形库,据我估计它对于初学者来说足够简单,但有很多深度可以产生非常复杂的 3D 效果.(仔细阅读 https://threejs.org/examples/ 中的示例,您会亲眼看到.)

Am not sure whether you're looking to learn 3D modeling from scratch (ie, creating your own library of vector routines, homogeneous coordinate transformations, rendering perspective, etc) or whether you're simply looking to produce a final product. In the case of the latter, three.js is a powerful graphics library built on webGL that in my estimation is simple enough for a beginner to dabble with, but has a lot of depth to produce very sophisticated 3D effects. (Peruse the examples at https://threejs.org/examples/ and you'll see for yourself.)

我碰巧在做我自己的一个 Three.js 项目,并快速制作了一个周转圈示例作为热身练习.这涉及从以下参考文献中提取零件...

I happen to be working a three.js project of my own, and whipped up a quick example of epicyclic circles as a warm up exercise. This involved pulling pieces and parts from the following references...

https://threejs.org/examples/#misc_controls_orbit

https://threejs.org/examples/#webgl_geometry_shapes(这三个.js 示例是一个很好的资源,展示了可以呈现形状的各种方式.)

https://threejs.org/examples/#webgl_geometry_shapes (This three.js example is a great resource showing a variety of ways that a shape can be rendered.)

结果是一个简单的场景,一个圆圈环绕另一个圆圈,允许鼠标控件围绕场景运行,从不同的角度和距离观看.

The result is a simple scene with one circle running around the other, permitting mouse controls to orbit around the scene, viewing it from different angles and distances.

<html>
  <head>
    <title>Epicyclic Circles</title>
    <style>
      body { margin: 0; }
      canvas { width: 100%; height: 100% }
    </style>
  </head>
  <body>

    <script src="https://rawgit.com/mrdoob/three.js/dev/build/three.js"></script>
    <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>

    <script>

      // Set up the basic scene, camera, and lights.
      
      var scene = new THREE.Scene();
      scene.background = new THREE.Color( 0xf0f0f0 );
      
      var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
      scene.add(camera)
      
      var light = new THREE.PointLight( 0xffffff, 0.8 );
      camera.add( light );
      
      camera.position.z = 50;
        
      var renderer = new THREE.WebGLRenderer();
      renderer.setSize( window.innerWidth, window.innerHeight );
      document.body.appendChild( renderer.domElement );
      
      // Add the orbit controls to permit viewing the scene from different angles via the mouse.
      
      controls = new THREE.OrbitControls( camera, renderer.domElement );
      controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
      controls.dampingFactor = 0.25;
      controls.screenSpacePanning = false;
      controls.minDistance = 0;
      controls.maxDistance = 500;
      
      // Create center and epicyclic circles, extruding them to give them some depth.
      
      var extrudeSettings = { depth: 2, bevelEnabled: true, bevelSegments: 2, steps: 2, bevelSize: .25, bevelThickness: .25 };

      var arcShape1 = new THREE.Shape();
      arcShape1.moveTo( 0, 0 );
      arcShape1.absarc( 0, 0, 15, 0, Math.PI * 2, false );
      var holePath1 = new THREE.Path();
      holePath1.moveTo( 0, 10 );
      holePath1.absarc( 0, 10, 2, 0, Math.PI * 2, true );
      arcShape1.holes.push( holePath1 );
        
      var geometry1 = new THREE.ExtrudeBufferGeometry( arcShape1, extrudeSettings );
      var mesh1 = new THREE.Mesh( geometry1, new THREE.MeshPhongMaterial( { color: 0x804000 } ) );
      scene.add( mesh1 );
      
      var arcShape2 = new THREE.Shape();
      arcShape2.moveTo( 0, 0 );
      arcShape2.absarc( 0, 0, 15, 0, Math.PI * 2, false );
      var holePath2 = new THREE.Path();
      holePath2.moveTo( 0, 10 );
      holePath2.absarc( 0, 10, 2, 0, Math.PI * 2, true );
      arcShape2.holes.push( holePath2 );
          
      var geometry2 = new THREE.ExtrudeGeometry( arcShape2, extrudeSettings );
      var mesh2 = new THREE.Mesh( geometry2, new THREE.MeshPhongMaterial( { color: 0x00ff00 } ) );
      scene.add( mesh2 );

      // Define variables to hold the current epicyclic radius and current angle.
      var mesh2AxisRadius = 30;
      var mesh2AxisAngle = 0;

      var animate = function () {
        requestAnimationFrame( animate );

        // During each animation frame, let's rotate the objects on their center axis,  
        // and also set the position of the epicyclic circle.
        
        mesh1.rotation.z -= 0.02;

        mesh2.rotation.z += 0.02;
        mesh2AxisAngle += 0.01;
        mesh2.position.set ( mesh2AxisRadius * Math.cos(mesh2AxisAngle), mesh2AxisRadius * Math.sin(mesh2AxisAngle), 0 );

        renderer.render( scene, camera );
      };

      animate();
    </script>
  </body>
</html>

请注意,我在 animate 函数中使用了基本的三角函数来围绕中心圆定位行星圆,并捏造了圆的旋转速率(而不是进行精确的数学运算),但可能有更好的three.js"方式通过矩阵或内置函数来做到这一点.鉴于您显然具有很强的数学背景,我认为您在移植到 3D 时使用基本三角学转换多周转圆的 2D 模型不会有任何问题.

Note that I've used basic trigonometry within the animate function to position the epicyclic circle around the center circle, and fudged the rate of rotation for the circles (rather than doing the precise math), but there's probably a better "three.js"-way of doing this via matrices or built in functions. Given that you obviously have a strong math background, I don't think you'll have any issues with translating your 2D model of multi-epicyclic circles using basic trigonometry when porting to 3D.

希望这有助于您决定如何处理 3D 版本的程序.

Hope this helps in your decision making process on how to proceed with a 3D version of your program.

这篇关于使用本轮和傅立叶变换绘制/渲染 3D 对象 [动画]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆