Я новичок в 3js, у меня есть 2 изображения, то есть изображение RGB и изображение глубины. Могу ли я создать облако точек, объединив эти два, используя 3js? если да, то как?
извините, если вы скажете, что непонятно, я попробую отредактировать вопрос @ Prisoner849
Что ты пробовал? Пока вы спрашиваете вместо «Я пробовал то, то и то, вот мой код. Не могли бы вы мне помочь?» звучит так: «У меня есть кое-что, и мне нужно добиться этого результата. Я не знаю, как это сделать, так что скажите мне, или лучше сделайте всю работу за меня».
Короткий ответ - «да, это возможно». И есть несколько способов добиться желаемого результата. Взгляните на этот ветка форума
Извините, я не могу найти ничего, что ищу @ Prisoner849
Привет, Ренджит. Pailhead уже указал вам на разделы справки, поэтому я не буду их повторно связывать. Ожидается, что те, кто задает вопросы, приложили определенные усилия для решения своих проблем, что они могут продемонстрировать с помощью кода и сообщений об ошибках. Вопросы, требующие ручных инструкций или руководств, выходят за рамки Stack Overflow. Пожалуйста, взгляните на документы и Примеры, узнайте немного о three.js, а затем пытаться, чтобы реализовать то, что вы хотите. Если у вас возникнут проблемы, вернитесь и задайте вопросы, которые мы можем вам помочь.
Чтобы решить эту проблему, я пошел по Примеры three.js и поискал "точку". Я проверил каждый соответствующий образец на предмет того, который имел разные цвета для каждой частицы. Затем я нажал кнопку «просмотреть исходный код», чтобы проверить код. В итоге я начал с этот пример и посмотрел на источник. Он довольно ясно дал понять, как сделать набор точек разного цвета.
Итак, после этого мне просто нужно было загрузить 2 изображения, RGB и Depth, создать сетку точек, для каждой точки установить положение Z на глубину, а цвет - на цвет изображения.
Я использовал свой телефон, чтобы сделать эти изображения RGB и глубины с помощью это приложение
Чтобы получить данные, я рисую изображение на холсте, а затем вызываю 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>
Можно ли также использовать собственный шейдер для смещения пикселей вместо получения / установки каждого пикселя?
Да, вы можете сделать get
внутри вершинного шейдера, передав их как текстуры. Вы можете увидеть пример здесь. Вы можете просмотреть текстуру, которую он использует для высоты, нажав на «помощь» и выбрав «текстура».
Добро пожаловать в Stackoverflow! Пожалуйста, прочтите про Как спросить и минимальный воспроизводимый пример.