three.js n-body模拟

时间:2015-08-18 18:51:57

标签: javascript three.js simulation

我正在努力做这个http://mbostock.github.io/protovis/ex/nbody.html和同一个项目。但我的系统不起作用。你能帮我吗这是我http://mendow.github.io/projects/n-body/index.html 我猜我错误地计算每个部分对每个部分的吸引力

问题是粒子有一个质心并围绕它旋转而不是质量中心改变它的位置



<!DOCTYPE html>
<html>

<head>
  <title>n-body</title>
  <script src="http://mendow.github.io/projects/n-body/libs/three.js"></script>
  <script src="http://mendow.github.io/projects/n-body/libs/OrbitControls.js"></script>
  <script src="http://mendow.github.io/projects/n-body/libs/OBJLoader.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }

  </style>
</head>
<script>
  //define global variable
  {
    var renderer;
    var scene;
    var camera;
    var orbit;
    var ps;

    var G = 9.81;
    var dt = 0.0001;
    var count = 1000;
    var cam = 30;
  }

  function init() {
    {
      // create a scene, that will hold all our elements such as objects, cameras and lights.
      scene = new THREE.Scene();

      // create a camera, which defines where we're looking at.
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

      // create a render, sets the background color and the size
      renderer = new THREE.WebGLRenderer();
      renderer.setClearColor(0x000000, 1.0);
      renderer.setSize(window.innerWidth, window.innerHeight);

      // position and point the camera to the center of the scene
      camera.position.x = cam;
      camera.position.y = cam;
      camera.position.z = cam;
      camera.lookAt(scene.position);

      orbit = new THREE.OrbitControls(camera);
    }
    setupParticleSystem(count);


    // add the output of the renderer to the html element
    document.body.appendChild(renderer.domElement);

    // call the render function
    render();
  }

  function setupParticleSystem(y) {



    var geometry = new THREE.Geometry();


    for (var j = 0; j < y; j++) {
      var v = new THREE.Vector3();
      var ran = 30;
      v.x = intRand(ran, -ran);
      v.y = intRand(ran, -ran);
      v.z = intRand(ran, -ran);
      v.vel = new THREE.Vector3(intRand(1, -1), intRand(1, -1), intRand(1, -1));
      v.acc =new THREE.Vector3(intRand(1, -1), intRand(1, -1), intRand(1, -1));
      v.mass = intRand(5, 0);
      geometry.vertices.push(v);
    }

    console.log(geometry.vertices);
    // use a material for some styling
    var psMat = new THREE.PointCloudMaterial();
    psMat.color = new THREE.Color(0x55ff55);
    psMat.transparent = true;
    psMat.size = 1;
    psMat.blending = THREE.AdditiveBlending;

    // Create a new particle system based on the provided geometry
    ps = new THREE.PointCloud(geometry, psMat);
    ps.sizeAttenuation = true;
    ps.sortParticles = true;

    ps.position.y = 100 / cam;
    ps.position.x = 100 / cam;
    ps.position.z = 100 / cam;
    // add the particle system to the scene
    scene.add(ps);

  }


  var step = 0;

  function render() {
    renderer.render(scene, camera);
    requestAnimationFrame(render);

    var r,
      mult;
    var geometry = ps.geometry;
    var temp = ps.geometry;
    for (var i = 0; i < geometry.vertices.length; i++) {

      for (var j = 0; j < geometry.vertices.length; j++) {
        if (i != j) {
          var particle = geometry.vertices[i];
          var cntr = geometry.vertices[j];

          r = particle.length(cntr);

          mult = (-1) * G * (cntr.mass * particle.mass) / Math.pow(r, 3);

          particle.acc.x = mult * particle.x;
          particle.vel.x += particle.acc.x * dt;
          particle.x += particle.vel.x * dt;

          particle.acc.y = mult * particle.y;
          particle.vel.y += particle.acc.y * dt;
          particle.y += particle.vel.y * dt;

          particle.acc.z = mult * particle.z;
          particle.vel.z += particle.acc.z * dt;
          particle.z += particle.vel.z * dt;
        }
      }
    }

    geometry.verticesNeedUpdate = true;
    geometry.colorsNeedUpdate = true;

    orbit.update();
  }

  // calls the init function when the window is done loading.
  window.onload = init;

  function mrand() {
    return Math.random();
  }

  function intRand(min, max) {
    return Math.random() * (max - min) + min;
  }

</script>

<body>
</body>

</html>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

检查浏览器javascript控制台(F12)时,您会看到以下错误:

Uncaught SecurityError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': The cross-origin image at http://mendow.github.io/projects/n-body/assets/textures/ps_smoke.png may not be loaded.

一个解决方案(请参阅下面的替代解决方案)是将资产文件简单地放在与HTML相同的主机上。这是您的主机本地的。以下是步骤(linux cmds,修改为windows):

#include <iostream>
#include <cmath>
#include<iomanip>
using namespace std;

/*
 * 
 */
int distance(double x1,double x2,double y1,double y2){
    double k;
    k=pow((x1-x2),2)+pow((y1-y2),2);
    double distan;
    distan=sqrt(k);
    return distan;  
}
int main() {
    int n,k;

    double dis=0.00;
    cin>>n;
    double points[2][100]={0.0};
    for(int i=0;i<n;i++){
        for(int m=0;m<2;m++){
        cin>>points[m][i];}
    }
    double dis1[100]={0.0};
    int count=0;
    for(int i=0;i<n-1;i++){
        for(int r=1;r<n;r++&&count++)
        dis1[count]=distance(points[0][i],points[0][i+r],points[1][i],points[1][i+r]);

    }

    for(int i=0;i<=count;i++){
        if(dis1[i]>dis){
            dis=dis1[i];
        }
    }
    cout << fixed << setprecision(4) << dis << endl;


    return 0;
}

然后最后更新你的html

评论出来:

cd into same dir as your html
mkdir -p assets/textures # create dir to park your ps_smoke.png
cd assets/textures # get into this new dir

# copy that remote file to your local dir
wget http://mendow.github.io/projects/n-body/assets/textures/ps_smoke.png

良好的新位置:

psMat.map = THREE.ImageUtils.loadTexture("http://mendow.github.io/projects/n-body/assets/textures/ps_smoke.png");

一旦我这样做,你的代码执行得很好。

上述解决方案的替代方法是通过在您正在进行的loadTexture调用之前添加以下代码来覆盖此安全检查:

psMat.map = THREE.ImageUtils.loadTexture("assets/textures/ps_smoke.png");

答案 1 :(得分:0)

Matvey,你需要在添加它们之前用旧值计算所有粒子位置和速度的变化以获得新值。否则,您将根据更改的位置和速度计算某些更改,这是不准确的。

我已经编辑了渲染循环:

&#13;
&#13;
<!DOCTYPE html>
<html>

<head>
  <title>n-body</title>
  <script src="http://mendow.github.io/projects/n-body/libs/three.js"></script>
  <script src="http://mendow.github.io/projects/n-body/libs/OrbitControls.js"></script>
  <script src="http://mendow.github.io/projects/n-body/libs/OBJLoader.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }

  </style>
</head>
<script>
  //define global variable
  {
    var renderer;
    var scene;
    var camera;
    var orbit;
    var ps;

    var G = 9.81;
    var dt = 0.0001;
    var count = 1000;
    var cam = 30;
  }

  function init() {
    {
      // create a scene, that will hold all our elements such as objects, cameras and lights.
      scene = new THREE.Scene();

      // create a camera, which defines where we're looking at.
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

      // create a render, sets the background color and the size
      renderer = new THREE.WebGLRenderer();
      renderer.setClearColor(0x000000, 1.0);
      renderer.setSize(window.innerWidth, window.innerHeight);

      // position and point the camera to the center of the scene
      camera.position.x = cam;
      camera.position.y = cam;
      camera.position.z = cam;
      camera.lookAt(scene.position);

      orbit = new THREE.OrbitControls(camera);
    }
    setupParticleSystem(count);


    // add the output of the renderer to the html element
    document.body.appendChild(renderer.domElement);

    // call the render function
    render();
  }

  function setupParticleSystem(y) {



    var geometry = new THREE.Geometry();


    for (var j = 0; j < y; j++) {
      var v = new THREE.Vector3();
      var ran = 30;
      v.x = intRand(ran, -ran);
      v.y = intRand(ran, -ran);
      v.z = intRand(ran, -ran);
      v.vel = new THREE.Vector3(intRand(1, -1), intRand(1, -1), intRand(1, -1));
      v.acc =new THREE.Vector3(intRand(1, -1), intRand(1, -1), intRand(1, -1));
      v.mass = intRand(5, 0);
      geometry.vertices.push(v);
    }

    console.log(geometry.vertices);
    // use a material for some styling
    var psMat = new THREE.PointCloudMaterial();
    psMat.color = new THREE.Color(0x55ff55);
    psMat.transparent = true;
    psMat.size = 1;
    psMat.blending = THREE.AdditiveBlending;

    // Create a new particle system based on the provided geometry
    ps = new THREE.PointCloud(geometry, psMat);
    ps.sizeAttenuation = true;
    ps.sortParticles = true;

    ps.position.y = 100 / cam;
    ps.position.x = 100 / cam;
    ps.position.z = 100 / cam;
    // add the particle system to the scene
    scene.add(ps);

  }


  var step = 0;

  function render() {
    renderer.render(scene, camera);
    requestAnimationFrame(render);

    var r, mult;
    var geometry = ps.geometry;
    var temp = ps.geometry;

    var dx = [];
    var dv = [];

    for (var i = 0; i < geometry.vertices.length; i++) {

    var v = geometry.vertices[i].vel;
    dx.push( new THREE.Vector3( v.x * dt, v.y * dt, v.z * dt ) );

    var dvx = 0;
    var dvy = 0;
    var dvz = 0;

    for (var j = 0; j < geometry.vertices.length; j++) {

       if (i != j) {

          mult = (-1) * G * geometry.vertices[i].mass * geometry.vertices[j].mass;

         var vi = geometry.vertices[i];
         var vj = geometry.vertices[j];

         // http://www.scholarpedia.org/article/N-body_simulations_%28gravitational%29
         epsilon = .1;

         var r = Math.sqrt( ( vi.x - vj.x ) * ( vi.x - vj.x )
                          + ( vi.y - vj.y ) * ( vi.y - vj.y )
                          + ( vi.z - vj.z ) * ( vi.z - vj.z ) + epsilon )

         dvx += mult * ( vi.x - vj.x ) / Math.pow( r, 3 );
         dvy += mult * ( vi.y - vj.y ) / Math.pow( r, 3 );
         dvz += mult * ( vi.z - vj.z ) / Math.pow( r, 3 );

      }

    }

    dv.push( new THREE.Vector3( dvx * dt, dvy * dt, dvz * dt ) );

  }

  for ( var i=0 ; i < geometry.vertices.length ; i++ ) {

    geometry.vertices[i].add( dx[i] );
    geometry.vertices[i].vel.add( dv[i] );

  }

    geometry.verticesNeedUpdate = true;
    geometry.colorsNeedUpdate = true;

    orbit.update();
  }

  // calls the init function when the window is done loading.
  window.onload = init;

  function mrand() {
    return Math.random();
  }

  function intRand(min, max) {
    return Math.random() * (max - min) + min;
  }

</script>

<body>
</body>


</html>
&#13;
&#13;
&#13;

对力的分母的修改有助于在近距离遇到粒子时保持能量相对恒定http://www.scholarpedia.org/article/N-body_simulations_(gravitational)