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

查看:142
本文介绍了使用Epicycle和Fourier变换绘制/渲染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条闭合路径)进行动画处理的方法.这样会创建史诗般的动画(旋转的圆圈),它们彼此围绕旋转,并跟随插补点,将路径作为连续的循环/函数进行跟踪.

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

傅里叶变换背景!!!

•Eulers公式使我们可以将复杂平面中的每个点分解为一个角度(指数函数的自变量)和一个振幅(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代码: 可以在 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;

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

And Most Importantly! THE PATH / COORDINATES: (this one is a triangle)

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.

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

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