【问题标题】:three.js n-body simulation三.js n体模拟
【发布时间】:2015-08-18 18:51:57
【问题描述】:

我正在尝试这样做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>

【问题讨论】:

  • 不要猜测,调试。如果您发现代码无法按预期工作,请向我们展示该代码并告诉我们问题所在,那么我们可能会为您提供帮助。
  • 感谢您的建议。我添加了代码

标签: javascript three.js simulation


【解决方案1】:

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

未捕获的安全错误:无法在“WebGLRenderingContext”上执行“texImage2D”:可能无法加载 http://mendow.github.io/projects/n-body/assets/textures/ps_smoke.png 上的跨域图像。

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

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

然后最后更新你的 html

注释掉:

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

不错的新位置:

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

一旦我这样做了,您的代码就会执行得很好。

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

THREE.ImageUtils.crossOrigin = '';

【讨论】:

  • 我删除了纹理,它工作正常,谢谢,但这不是主要问题。主要问题:我想移动粒子计算影响它的所有力,为此创建两个循环并通过数组让粒子开始新循环通过同一个数组并计算速度和加速度矢量。但它似乎围绕一个粒子旋转,我通过代码并没有找到这个粒子
【解决方案2】:

Matvey,你需要用旧值计算所有粒子位置和速度的变化,然后再添加它们以获得新值。否则,您会根据不准确的位置和速度的变化来计算一些变化。

我已经编辑了你的渲染循环:

<!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>

根据http://www.scholarpedia.org/article/N-body_simulations_(gravitational),对力分母的修改有助于在粒子近距离接触期间保持能量相对恒定

【讨论】:

    猜你喜欢
    • 2020-04-10
    • 2018-08-08
    • 2015-04-13
    • 2015-02-13
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多