Three.js - 将热图纹理应用于点云
Three.js - Apply heatmap texture to pointcloud
我想做的是将热图纹理应用于点云,这样当点云旋转时,纹理不会旋转。例如,红色需要始终处于 Z 向上,蓝色需要始终处于 Z 向下。
是否可以将纹理添加到 Points 对象并使其“锁定”到位,使其不随几何体旋转?或者我是否需要创建另一个对象,例如具有纹理的立方体,并以某种方式将其与点云混合?
创建着色器或将颜色属性添加到顶点是唯一的选择吗?
非常感谢所有评论和建议!
一个非常粗略的选项,使用修改后的PointsMaterial
和Box3
:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
console.clear();
import * as THREE from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
import { PCDLoader } from 'https://threejs.org/examples/jsm/loaders/PCDLoader.js';
let camera, scene, renderer, clock, pcd;
let box = new THREE.Box3();
let size = new THREE.Vector3();
let uniforms = {
yMin: {value: 0},
yMax: {value: 0}
}
init();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 0.01, 40 );
camera.position.set( 0, 0, 1 );
scene.add( camera );
const controls = new OrbitControls( camera, renderer.domElement );
//controls.addEventListener( 'change', render ); // use if there is no animation loop
controls.minDistance = 0.5;
controls.maxDistance = 10;
//scene.add( new THREE.AxesHelper( 1 ) );
const loader = new PCDLoader();
loader.load( 'https://threejs.org/examples/models/pcd/binary/Zaghetto.pcd', function ( points ) {
points.geometry.center();
points.geometry.rotateX( Math.PI );
points.material.onBeforeCompile = shader => {
shader.uniforms.yMin = uniforms.yMin;
shader.uniforms.yMax = uniforms.yMax;
shader.vertexShader = `
varying vec4 worldPosition;
${shader.vertexShader}
`.replace(
`#include <worldpos_vertex>`,
`
worldPosition = vec4( transformed, 1.0 );
worldPosition = modelMatrix * worldPosition;
`
);
console.log(shader.vertexShader);
shader.fragmentShader = `
uniform float yMin;
uniform float yMax;
varying vec4 worldPosition;
// https://www.shadertoy.com/view/4dsSzr
vec3 ansiGradient(float t) {
return mod(floor(t * vec3(8.0, 4.0, 2.0)), 2.0);
}
${shader.fragmentShader}
`.replace(
`vec4 diffuseColor = vec4( diffuse, opacity );`,
`
float a = (worldPosition.y - yMin) / (yMax - yMin);
vec3 col = ansiGradient(a);
vec4 diffuseColor = vec4( col, opacity );
`
);
console.log(shader.fragmentShader);
}
pcd = points;
console.log(pcd);
scene.add( points );
const helper = new THREE.Box3Helper( box, 0xffff00 );
scene.add( helper );
} );
clock = new THREE.Clock();
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
renderer.setAnimationLoop( _ => {
let t = clock.getElapsedTime();
if (pcd) {
pcd.rotation.x = (Math.sin(t) * 0.5 + 0.5) * THREE.MathUtils.degToRad(-60);
box.setFromObject(pcd);
let yMin = box.min.y;
let yMax = box.max.y;
uniforms.yMin.value = yMin;
uniforms.yMax.value = yMax;
}
renderer.render( scene, camera );
});
</script>
我想做的是将热图纹理应用于点云,这样当点云旋转时,纹理不会旋转。例如,红色需要始终处于 Z 向上,蓝色需要始终处于 Z 向下。
是否可以将纹理添加到 Points 对象并使其“锁定”到位,使其不随几何体旋转?或者我是否需要创建另一个对象,例如具有纹理的立方体,并以某种方式将其与点云混合?
创建着色器或将颜色属性添加到顶点是唯一的选择吗?
非常感谢所有评论和建议!
一个非常粗略的选项,使用修改后的PointsMaterial
和Box3
:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
console.clear();
import * as THREE from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
import { PCDLoader } from 'https://threejs.org/examples/jsm/loaders/PCDLoader.js';
let camera, scene, renderer, clock, pcd;
let box = new THREE.Box3();
let size = new THREE.Vector3();
let uniforms = {
yMin: {value: 0},
yMax: {value: 0}
}
init();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 0.01, 40 );
camera.position.set( 0, 0, 1 );
scene.add( camera );
const controls = new OrbitControls( camera, renderer.domElement );
//controls.addEventListener( 'change', render ); // use if there is no animation loop
controls.minDistance = 0.5;
controls.maxDistance = 10;
//scene.add( new THREE.AxesHelper( 1 ) );
const loader = new PCDLoader();
loader.load( 'https://threejs.org/examples/models/pcd/binary/Zaghetto.pcd', function ( points ) {
points.geometry.center();
points.geometry.rotateX( Math.PI );
points.material.onBeforeCompile = shader => {
shader.uniforms.yMin = uniforms.yMin;
shader.uniforms.yMax = uniforms.yMax;
shader.vertexShader = `
varying vec4 worldPosition;
${shader.vertexShader}
`.replace(
`#include <worldpos_vertex>`,
`
worldPosition = vec4( transformed, 1.0 );
worldPosition = modelMatrix * worldPosition;
`
);
console.log(shader.vertexShader);
shader.fragmentShader = `
uniform float yMin;
uniform float yMax;
varying vec4 worldPosition;
// https://www.shadertoy.com/view/4dsSzr
vec3 ansiGradient(float t) {
return mod(floor(t * vec3(8.0, 4.0, 2.0)), 2.0);
}
${shader.fragmentShader}
`.replace(
`vec4 diffuseColor = vec4( diffuse, opacity );`,
`
float a = (worldPosition.y - yMin) / (yMax - yMin);
vec3 col = ansiGradient(a);
vec4 diffuseColor = vec4( col, opacity );
`
);
console.log(shader.fragmentShader);
}
pcd = points;
console.log(pcd);
scene.add( points );
const helper = new THREE.Box3Helper( box, 0xffff00 );
scene.add( helper );
} );
clock = new THREE.Clock();
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
renderer.setAnimationLoop( _ => {
let t = clock.getElapsedTime();
if (pcd) {
pcd.rotation.x = (Math.sin(t) * 0.5 + 0.5) * THREE.MathUtils.degToRad(-60);
box.setFromObject(pcd);
let yMin = box.min.y;
let yMax = box.max.y;
uniforms.yMin.value = yMin;
uniforms.yMax.value = yMax;
}
renderer.render( scene, camera );
});
</script>