Могу ли я создать облако точек из изображения глубины и rgb?

Я новичок в 3js, у меня есть 2 изображения, то есть изображение RGB и изображение глубины. Могу ли я создать облако точек, объединив эти два, используя 3js? если да, то как?

Добро пожаловать в Stackoverflow! Пожалуйста, прочтите про Как спросить и минимальный воспроизводимый пример.

prisoner849 31.10.2018 13:23

извините, если вы скажете, что непонятно, я попробую отредактировать вопрос @ Prisoner849

Renjith Raju 31.10.2018 14:20

Что ты пробовал? Пока вы спрашиваете вместо «Я пробовал то, то и то, вот мой код. Не могли бы вы мне помочь?» звучит так: «У меня есть кое-что, и мне нужно добиться этого результата. Я не знаю, как это сделать, так что скажите мне, или лучше сделайте всю работу за меня».

prisoner849 31.10.2018 14:35

Короткий ответ - «да, это возможно». И есть несколько способов добиться желаемого результата. Взгляните на этот ветка форума

prisoner849 31.10.2018 15:55

Извините, я не могу найти ничего, что ищу @ Prisoner849

Renjith Raju 31.10.2018 17:55

Привет, Ренджит. Pailhead уже указал вам на разделы справки, поэтому я не буду их повторно связывать. Ожидается, что те, кто задает вопросы, приложили определенные усилия для решения своих проблем, что они могут продемонстрировать с помощью кода и сообщений об ошибках. Вопросы, требующие ручных инструкций или руководств, выходят за рамки Stack Overflow. Пожалуйста, взгляните на документы и Примеры, узнайте немного о three.js, а затем пытаться, чтобы реализовать то, что вы хотите. Если у вас возникнут проблемы, вернитесь и задайте вопросы, которые мы можем вам помочь.

TheJim01 01.11.2018 03:54
5
6
2 109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы решить эту проблему, я пошел по Примеры three.js и поискал "точку". Я проверил каждый соответствующий образец на предмет того, который имел разные цвета для каждой частицы. Затем я нажал кнопку «просмотреть исходный код», чтобы проверить код. В итоге я начал с этот пример и посмотрел на источник. Он довольно ясно дал понять, как сделать набор точек разного цвета.

Итак, после этого мне просто нужно было загрузить 2 изображения, RGB и Depth, создать сетку точек, для каждой точки установить положение Z на глубину, а цвет - на цвет изображения.

Я использовал свой телефон, чтобы сделать эти изображения RGB и глубины с помощью это приложение

ImgurImgur

Чтобы получить данные, я рисую изображение на холсте, а затем вызываю getImageData. Это дает мне данные в значениях от 0 до 255 для каждого канала: красный, зеленый, синий, альфа.

Затем я написал функцию, чтобы получить один пиксель и вернуть цвета в диапазоне от 0 до 1. На всякий случай проверяет границы.

// return the pixel at UV coordinates (0 to 1) in 0 to 1 values
function getPixel(imageData, u, v) {
  const x = u * (imageData.width  - 1) | 0;
  const y = v * (imageData.height - 1) | 0;
  if (x < 0 || x >= imageData.width || y < 0 || y >= imageData.height) {
    return [0, 0, 0, 0];
  } else {
    const offset = (y * imageData.width + x) * 4;
    return Array.from(imageData.data.slice(offset, offset + 4)).map(v => v / 255);
  }
}

результат

'use strict';

/* global THREE */

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = "anonymous";
    img.onload = (e) => { resolve(img); };
    img.onerror = reject;
    img.src = url;
  });
}

function getImageData(img) {  
  const ctx = document.createElement("canvas").getContext("2d");
  ctx.canvas.width = img.width;
  ctx.canvas.height = img.height;
  ctx.drawImage(img, 0, 0);
  return ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
}

// return the pixel at UV coordinates (0 to 1) in 0 to 1 values
function getPixel(imageData, u, v) {
  const x = u * (imageData.width  - 1) | 0;
  const y = v * (imageData.height - 1) | 0;
  if (x < 0 || x >= imageData.width || y < 0 || y >= imageData.height) {
    return [0, 0, 0, 0];
  } else {
    const offset = (y * imageData.width + x) * 4;
    return Array.from(imageData.data.slice(offset, offset + 4)).map(v => v / 255);
  }
}

async function main() {
  const images = await Promise.all([
    loadImage("https://i.imgur.com/UKBsvV0.jpg"),  // RGB
    loadImage("https://i.imgur.com/arPMCZl.jpg"),  // Depth
  ]);
  const data = images.map(getImageData);
  
  const canvas = document.querySelector('canvas');
  const renderer = new THREE.WebGLRenderer({canvas: canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 1;
  const far = 4000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2000;

  const controls = new THREE.OrbitControls(camera, canvas);
  controls.target.set(0, 0, 0);
  controls.update();

  const scene = new THREE.Scene();

  const rgbData = data[0];
  const depthData = data[1];
  
  const skip = 20;
  const across = Math.ceil(rgbData.width / skip);
  const down = Math.ceil(rgbData.height / skip);
  
  const positions = [];
  const colors = [];
  const color = new THREE.Color();
  const spread = 1000;
  const depthSpread = 1000;
  const imageAspect = rgbData.width / rgbData.height;
  
  for (let y = 0; y < down; ++y) {
    const v = y / (down - 1);
    for (let x = 0; x < across; ++x) {
      const u = x / (across - 1);
      const rgb = getPixel(rgbData, u, v);
      const depth = 1 - getPixel(depthData, u, v)[0];
      
      positions.push( 
         (u *  2 - 1) * spread * imageAspect, 
         (v * -2 + 1) * spread, 
         depth * depthSpread,
      );
      colors.push( ...rgb.slice(0,3) );
    }
  }
  
  const geometry = new THREE.BufferGeometry();
  geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
  geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
  geometry.computeBoundingSphere();
  const material = new THREE.PointsMaterial( { size: 15, vertexColors: THREE.VertexColors } );
	const points = new THREE.Points( geometry, material );
  scene.add( points );

  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();
    }

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
body {
  margin: 0;
}
canvas {
  width: 100vw;
  height: 100vh;
  display: block;
}
<canvas></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r94/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r94/js/controls/OrbitControls.js"></script>

Можно ли также использовать собственный шейдер для смещения пикселей вместо получения / установки каждого пикселя?

Rene Schulte 01.11.2018 12:48

Да, вы можете сделать get внутри вершинного шейдера, передав их как текстуры. Вы можете увидеть пример здесь. Вы можете просмотреть текстуру, которую он использует для высоты, нажав на «помощь» и выбрав «текстура».

gman 01.11.2018 15:41

Другие вопросы по теме