Превращение изображения в облако точек за три. js - PullRequest
2 голосов
/ 29 апреля 2020

Я хочу превратить изображение в облако точек и сместить z-позицию на основе значения цвета. На данный момент у меня есть:

  1. Загрузил изображение и при загрузке
  2. Построил геометрию и сохранил цвет изображения внутри геометрии
  3. Создайте PointsMaterial и создайте ТРИ .Points
  4. Добавить к сцене

Однако результат не похож на входное изображение. Я что-то упускаю, но не знаю, в чем.

Что мне не хватает в отношении отображения версии изображения в облаке точек?

Пример: https://img2pointcloud.glitch.me/

<html>
  <head>
    <script src="https://threejs.org/build/three.js"></script>
  </head>
  <body style="margin:0">
    <script>
      var container, renderer, points;

      var scene = new THREE.Scene();

      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        10000
      );
      camera.position.set(0, 0, 1000);

      var renderer = new THREE.WebGLRenderer();
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);

      document.body.appendChild(renderer.domElement);

      var imgSrc =
        "https://cdn.glitch.com/c3afecd9-365c-424f-a08e-90fce02a151a%2Fimg.jpeg?v=1588102020636";
      var img = new Image();
      var width = 1920 / 4;
      var height = 1080 / 4;
      img.crossOrigin = "anonymous";
      img.src = imgSrc;

      img.onload = function() {
        var canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;
        var ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        var imageData = ctx.getImageData(0, 0, width, height);
        var data = imageData.data;
        document.body.appendChild(canvas);
        createPointCloud(imageData);
      };

      function createPointCloud(imageData) {

        var geometry = new THREE.BufferGeometry();
        var positions = [];

        for (var x = 0; x < height; x++) {
          for (var z = 0; z < width; z++) {
            positions.push(x, z, x);
          }
        }

        var color = new THREE.Color();
        var colors = [];

        for (let i = 0; i < imageData.data.length; i += 4) {
          const r = imageData.data[i + 0];
          const g = imageData.data[i + 1];
          const b = imageData.data[i + 2];
          const a = imageData.data[i + 3];
          color.setRGB(r, g, b);
          colors.push(color.r, color.b, color.c);
        }

        geometry.setAttribute(
          "position",
          new THREE.Float32BufferAttribute(positions, 3)
        );
        geometry.setAttribute(
          "color",
          new THREE.Float32BufferAttribute(colors, 3)
        );

        geometry.computeBoundingSphere();

        var material = new THREE.PointsMaterial({
          size: 0.1,
          vertexColors: true
        });

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

        animate();
      }

      function animate() {
        requestAnimationFrame(animate);
        render();
      }

      function render() {
        renderer.render(scene, camera);
      }
    </script>
  </body>
</html>


  [1]: https://i.stack.imgur.com/9etFB.png
  [2]: https://i.stack.imgur.com/HKM7m.png

Ответы [ 2 ]

2 голосов
/ 29 апреля 2020

Другой подход заключается в модификации шейдеров THREE.PointsMaterial():

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(-75, 0, 1);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

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

new THREE.TextureLoader().load("https://cdn.glitch.com/c3afecd9-365c-424f-a08e-90fce02a151a%2Fimg.jpeg?v=1588102020636", tex => {

    let img = tex.image;
    console.log(img.width, img.height);

    let g = new THREE.PlaneBufferGeometry(Math.floor(img.width / 4), Math.floor(img.height / 4), img.width, img.height);
    let m = new THREE.PointsMaterial({
      map: tex,
      size: 0.1
    });
    m.onBeforeCompile = shader => {
      shader.vertexShader = `
        varying vec2 vUv;
        ${shader.vertexShader}
      `;
      shader.vertexShader = shader.vertexShader.replace(
        `#include <color_vertex>`,
        `
        vUv = uv;
        #include <color_vertex>`
      );
      shader.fragmentShader = `
        varying vec2 vUv;
        ${shader.fragmentShader}
      `;
      shader.fragmentShader = shader.fragmentShader.replace(
        `#include <map_particle_fragment>`,
        `vec4 mapTexel = texture2D( map, vUv );
	        diffuseColor = mapTexel;
          `
      );
      console.log(shader.vertexShader);

    };
    let p = new THREE.Points(g, m);
    scene.add(p);

});

renderer.setAnimationLoop(() => {
  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>
0 голосов
/ 29 апреля 2020

В моем коде есть большая опечатка, в которой почему-то написано colors.push(color.r, color.b, color.c);, а не colors.push(color.r, color.g, color.b); (обратите внимание на rb c vs rgb).

Отсортировано сейчас, спасибо за комментарий, сделанный я вижу это.

...