如何为缓冲区几何中的每个顶点分配不同的颜色? Three.js

问题描述 投票:0回答:1

我是Three.js的新手,我已经找到了有关该主题的一些答案,但没有一个使用过缓冲区几何。我正在React上进行欧洲的3D地形项目,并且希望能够根据某些值来更改水位。为了做到这一点,我必须逐个顶点地进行着色,而不是从图像中添加纹理,如果我更改顶点的值,则着色不会改变。因此,我要根据顶点的“高度”来分配不同的颜色。

这是我的componentDidMount函数:

const SIZE_AMPLIFIER = 15;
var container = document.getElementById("main_map");
var scene, camera, renderer, controls;
var data, plane;

//load map data from bin file

 function loadTerrain(file) {
  var xhr = new XMLHttpRequest();
  xhr.responseType = 'arraybuffer';
  xhr.open('GET', file, true);
  xhr.onload = function (evt) {
    if (xhr.response) {
      data = new Uint16Array(xhr.response)
      init()
    }

  };
  xhr.send(null);
}

loadTerrain('stats.bin');

function init() {

  // initialize camera
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, .1, 100000);
  camera.position.set(10000, 4000, 0);

  // initialize scene
  scene = new THREE.Scene();

  // initialize directional light (sun)
  var sun = new THREE.DirectionalLight(0xFFFFFF, 1.0);
  sun.position.set(300, 400, 300);
  sun.distance = 1000;
  scene.add(sun);

  var frame = new THREE.SpotLightHelper(sun);
  scene.add(frame);

  // initialize renderer
  renderer = new THREE.WebGLRenderer();
  renderer.setClearColor(0x000000);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.append(renderer.domElement);

  //initialize controls

  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 1;
  controls.rotateSpeed = .8;
  controls.maxPolarAngle = Math.PI / 2 - .3;

  // initialize plane
  plane = new THREE.PlaneBufferGeometry(1500 * SIZE_AMPLIFIER, 1500 * SIZE_AMPLIFIER, 999 , 999);
  plane.castShadow = true;
  plane.receiveShadow = true;

  var vertices = plane.attributes.position.array;
  console.log(data)

  // apply height map to vertices of plane
  // assign different color depending on the value??

  for (let i = 0, j = 2; i < data.length; i += 1, j += 3) {
    if(data[i] == 0){
      vertices[j] = 0
    }else {
      vertices[j] = data[i] / 65535 * 325 + 10
    }
  }

  // Add texture image
  var material = new THREE.MeshLambertMaterial({ 
      map:THREE.ImageUtils.loadTexture('stats_color.png')
   })

  var mesh = new THREE.Mesh(plane, material);
  mesh.rotation.x = - Math.PI / 2;
  mesh.matrixAutoUpdate = false;
  mesh.updateMatrix();

  plane.computeFaceNormals();
  plane.computeVertexNormals();

  scene.add(mesh);

  animate();
}

function animate() {
  requestAnimationFrame(animate);

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

此后的结果(它令我满意,但不幸的是,对于该应用程序而言无效):

reactjs colors three.js vertex-shader vertex
1个回答
0
投票

Here is an article on how to use BufferGeometry

要添加颜色,请创建一个Float32Array颜色,并将其添加为称为“颜色”的属性。

  geometry.setAttribute(
      'color',
      new THREE.BufferAttribute(new Float32Array(colors), uvNumComponents));

然后将material.vertexColors设置为true;

  const material = new THREE.MeshPhongMaterial({
    vertexColors: true,
  });

body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 100;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 3;

  const scene = new THREE.Scene();

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }

  // NOT A GOOD EXAMPLE OF HOW TO MAKE A CUBE!
  // Only trying to make it clear most vertices are unique
  const vertices = [
    // front
    { pos: [-1, -1,  1], norm: [ 0,  0,  1], uv: [0, 1], },
    { pos: [ 1, -1,  1], norm: [ 0,  0,  1], uv: [1, 1], },
    { pos: [-1,  1,  1], norm: [ 0,  0,  1], uv: [0, 0], },

    { pos: [-1,  1,  1], norm: [ 0,  0,  1], uv: [0, 0], },
    { pos: [ 1, -1,  1], norm: [ 0,  0,  1], uv: [1, 1], },
    { pos: [ 1,  1,  1], norm: [ 0,  0,  1], uv: [1, 0], },
    // right
    { pos: [ 1, -1,  1], norm: [ 1,  0,  0], uv: [0, 1], },
    { pos: [ 1, -1, -1], norm: [ 1,  0,  0], uv: [1, 1], },
    { pos: [ 1,  1,  1], norm: [ 1,  0,  0], uv: [0, 0], },

    { pos: [ 1,  1,  1], norm: [ 1,  0,  0], uv: [0, 0], },
    { pos: [ 1, -1, -1], norm: [ 1,  0,  0], uv: [1, 1], },
    { pos: [ 1,  1, -1], norm: [ 1,  0,  0], uv: [1, 0], },
    // back
    { pos: [ 1, -1, -1], norm: [ 0,  0, -1], uv: [0, 1], },
    { pos: [-1, -1, -1], norm: [ 0,  0, -1], uv: [1, 1], },
    { pos: [ 1,  1, -1], norm: [ 0,  0, -1], uv: [0, 0], },

    { pos: [ 1,  1, -1], norm: [ 0,  0, -1], uv: [0, 0], },
    { pos: [-1, -1, -1], norm: [ 0,  0, -1], uv: [1, 1], },
    { pos: [-1,  1, -1], norm: [ 0,  0, -1], uv: [1, 0], },
    // left
    { pos: [-1, -1, -1], norm: [-1,  0,  0], uv: [0, 1], },
    { pos: [-1, -1,  1], norm: [-1,  0,  0], uv: [1, 1], },
    { pos: [-1,  1, -1], norm: [-1,  0,  0], uv: [0, 0], },

    { pos: [-1,  1, -1], norm: [-1,  0,  0], uv: [0, 0], },
    { pos: [-1, -1,  1], norm: [-1,  0,  0], uv: [1, 1], },
    { pos: [-1,  1,  1], norm: [-1,  0,  0], uv: [1, 0], },
    // top
    { pos: [ 1,  1, -1], norm: [ 0,  1,  0], uv: [0, 1], },
    { pos: [-1,  1, -1], norm: [ 0,  1,  0], uv: [1, 1], },
    { pos: [ 1,  1,  1], norm: [ 0,  1,  0], uv: [0, 0], },

    { pos: [ 1,  1,  1], norm: [ 0,  1,  0], uv: [0, 0], },
    { pos: [-1,  1, -1], norm: [ 0,  1,  0], uv: [1, 1], },
    { pos: [-1,  1,  1], norm: [ 0,  1,  0], uv: [1, 0], },
    // bottom
    { pos: [ 1, -1,  1], norm: [ 0, -1,  0], uv: [0, 1], },
    { pos: [-1, -1,  1], norm: [ 0, -1,  0], uv: [1, 1], },
    { pos: [ 1, -1, -1], norm: [ 0, -1,  0], uv: [0, 0], },

    { pos: [ 1, -1, -1], norm: [ 0, -1,  0], uv: [0, 0], },
    { pos: [-1, -1,  1], norm: [ 0, -1,  0], uv: [1, 1], },
    { pos: [-1, -1, -1], norm: [ 0, -1,  0], uv: [1, 0], },
  ];
  const positions = [];
  const normals = [];
  const uvs = [];
  const colors = [];
  for (const vertex of vertices) {
    positions.push(...vertex.pos);
    normals.push(...vertex.norm);
    uvs.push(...vertex.uv);
    colors.push(Math.random(), Math.random(), Math.random());
  }

  const geometry = new THREE.BufferGeometry();
  const positionNumComponents = 3;
  const normalNumComponents = 3;
  const uvNumComponents = 2;
  geometry.setAttribute(
      'position',
      new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents));
  geometry.setAttribute(
      'normal',
      new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents));
  geometry.setAttribute(
      'uv',
      new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
  geometry.setAttribute(
      'color',
      new THREE.BufferAttribute(new Float32Array(colors), uvNumComponents));

  const material = new THREE.MeshPhongMaterial({
    vertexColors: true,
  });

  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    cube.rotation.x = time;
    cube.rotation.y = time;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
</script>
© www.soinside.com 2019 - 2024. All rights reserved.