【问题标题】:Animate point's position based on array of positions with shaders in THREE.js基于位置数组在 THREE.js 中使用着色器为点的位置设置动画
【发布时间】:2017-11-27 13:39:39
【问题描述】:

我在 THREE.js 中有数千个点的动画,它们会及时改变它们的位置。我想使用着色器使动画更快。由于我对着色器完全陌生,我想从只为一个点设置动画开始。在每个时间步骤中,我想分配保存在向量数组(positions)中的点预定义位置。所以如果time = 1,点的位置就等于positions [1]

我尝试将 positions 保存为统一并将其传递给顶点着色器,但它不起作用。

我应该做些什么不同的事情?这是正确的做法吗?

点声明

//example array with only three vectors but I would like to use arrays which thousands of vectors
var positions = [
    new THREE.Vector3(1.6, 2.5, 4.0),
    new THREE.Vector3(1.8, 2.5, 3.8),
    new THREE.Vector3(1.2, 2.0, 3.0)
]

var geometry = new THREE.BufferGeometry();    
geometry.addAttribute("position", new THREE.Float32BufferAttribute([1.6, 2.5, 4.0],3))

var material = new THREE.ShaderMaterial({
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
    uniforms: {
        time: { type: 'f', value: 0 },
        positionArray: {type: "v3v", value: positions} 
    }
})
var point = new THREE.Points(geometry, material);
scene.add(point)

动画

function animate() {
    requestAnimationFrame(animate);

    time = time + 1
    material.uniforms.time.value = time;

    controls.update();
    renderer.render(scene, camera);
    stats.update();
}

顶点着色器

uniform vec3 positionArray[3];      
uniform float time;

void main () {

    vec3 newPosition;
    newPosition= positionArray[time];
    gl_PointSize = 10.0;

    gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
    }

【问题讨论】:

  • 我在我的代码中发现了问题,在制服定义中我应该将时间设置为 int 而不是 float time: { type: 'i', value: 0 } 无论如何这种方法并不能解决动画缓慢的问题......
  • 你能创建一个工作代码 sn-p 或 jsfiddle 吗?

标签: three.js glsl webgl vertex-shader


【解决方案1】:

可以不用着色器。

想法:你有一个 Float32Array() 数组

var data = [
  new Float32Array([...]),
  new Float32Array([...]),
  //and so on
];

,并且每个类型化数组都包含几何图形中每个点在给定时间键的数据;然后,例如,当时间为1 时,您只需将data 数组的元素1 中的数据分配给geometry.attributes.position.array。

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 2, 25);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

scene.add(new THREE.GridHelper(100, 100, "white", "white"));

var data = []; // arry of Float32Array
for (let i = 0; i < 10; i++){
  let arr = [];
  for(let x = -50; x <= 50; x++){
    for(let y = -50; y <=50; y++){
       arr.push(x, i * 2, y);
    }
  }
  data.push(new Float32Array(arr));
}

var geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array(data[0].slice()), 3 ) );

var material = new THREE.PointsMaterial({
  size: .25,
  color: "red"
});

var plane = new THREE.Points(geometry, material);
scene.add(plane);

var clock = new THREE.Clock();
var time = 0;
var floorTime = 0;
var oldTime = -1;
var delta = 0;

render();

function render() {
  delta = clock.getDelta();
  time += delta;
  requestAnimationFrame(render);
  if (time >= 10) time = 0;
  floorTime = Math.floor(time);
  if (floorTime != oldTime) { // a very rough approach of managing the time keys
    geometry.attributes.position.array.set(data[floorTime]); // set the data of points
    geometry.attributes.position.needsUpdate = true;
    oldTime = floorTime;
  }
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

PS 也许这样的做法不是很正确。这只是一个想法。

【讨论】:

  • 是的,当然,你可以在没有着色器的情况下做到这一点。我只是想尝试使用着色器来了解它们的工作原理。
猜你喜欢
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-01
  • 2019-12-01
相关资源
最近更新 更多