用 ThreeJS 替换空间中的平面

问题描述

我想将 ThreeJS 中的平面替换为特定的 Z 值。

我创建了一个 shapeBufferGeometry,其形状包含包含 x y 和 z 值的 Vector3s。

这是我的代码和我得到的。我希望白色平面与浅绿色线的位置相匹配。

下面的代码允许我用我的平面渲染场景中的不同点和它周围的顶点。

我知道我可以使用 translate 来移动飞机,但我不知道如何正确使用它。以及我如何知道应该根据我的矢量值在哪个轴上平移我的几何体。

<!DOCTYPE html>
    <html>
        <head>
            <Meta charset="utf-8">
            <title>My first three.js app</title>
            
            <style>
                body { margin: 0; }
            </style>
        </head>
        <body>
            <canvas id="c" width="800" height="500"></canvas>
            <script>
            </script>
            <script type="module">
                import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
                import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';
                import {GUI} from 'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js';
                import { ConvexGeometry } from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/geometries/ConvexGeometry.js'
                
                var scene = new THREE.Scene();
                var camera = new THREE.PerspectiveCamera(60,window.innerWidth / window.innerHeight,1,2000);
                camera.position.set(0,20,40);
                camera.lookAt(scene.position);
                var renderer = new THREE.Webglrenderer({
                antialias: true
                });
                renderer.setSize(window.innerWidth,window.innerHeight);
                document.body.appendChild(renderer.domElement);
    
                var controls = new OrbitControls(camera,renderer.domElement);
                controls.target = new THREE.Vector3(10,10);
                controls.update();
    
                var grid = new THREE.GridHelper(50,50,0x808080,0x202020); // xy-grid
                grid.geometry.rotateX(Math.PI * 0.5);
                scene.add(grid);
    
                var points = [ // all of them are on the xz-plane
                //  new THREE.Vector3(5,5),// new THREE.Vector3(25,15),// new THREE.Vector3(15,25),// new THREE.Vector3(5,5)
    
                new THREE.Vector3(199.2353333,7.6714966,32),new THREE.Vector3(199.0974316,276.6667291,new THREE.Vector3(75.2343077,276.6715748,232.6714966,new THREE.Vector3(101.1792999,194.6807462,194.6714966,new THREE.Vector3(199.2353333,32)
                ]
    
                var geom = new THREE.BufferGeometry().setFromPoints(points);
                var pointsObj = new THREE.Points(geom,new THREE.PointsMaterial({
                color: "red"
                }));
                scene.add(pointsObj);
    
                var line = new THREE.LineLoop(geom,new THREE.LineBasicMaterial({
                color: "aqua"
                }));
                scene.add(line);
    
                // normals 
                var normal = new THREE.Vector3(0,1); // I already kNow the normal of xz-plane ;)
                scene.add(new THREE.ArrowHelper(normal,new THREE.Vector3(10,10),5,0xffff00)); //yellow
    
                var normalZ = new THREE.Vector3(0,1); // base normal of xy-plane
                scene.add(new THREE.ArrowHelper(normalZ,scene.position,'#FF001F' )); // aqua
    
                // 1 quaternions
                var quaternion = new THREE.Quaternion().setFromunitVectors(normal,normalZ);
                var quaternionBack = new THREE.Quaternion().setFromunitVectors(normalZ,normal);
    
                // 2 make it parallel to xy-plane
                points.forEach(p => {
                p.applyQuaternion(quaternion)
                });
    
                // 3 create shape and shapeGeometry
                var shape = new THREE.Shape(points);
                var shapeGeom = new THREE.ShapeBufferGeometry(shape);
                shapeGeom.computeFacenormals();
                shapeGeom.computeVertexnormals();
    
                // 4 put our points back to their origins
                points.forEach(p => {
                p.applyQuaternion(quaternionBack)
                });
    
                // 5 assign points to .vertices
                shapeGeom.vertices = points;
    
                var shapeMesh = new THREE.Mesh(shapeGeom,new THREE.MeshBasicMaterial({
                color: '#FF001F ',side: THREE.DoubleSide
                }));
    
                
                scene.add(shapeMesh);
    
    
                // scene.add( new THREE.FacenormalsHelper( shapeMesh ) );
    
    
    
                render();
    
                function render() {
                requestAnimationFrame(render);
                renderer.render(scene,camera);
                }
            </script>
        </body>
    </html> 

我得到的结果:

the result I have

解决方法

不需要添加最后一个点来闭合轮廓。

并且您的步骤 // 5 assign points to .vertices 需要通过 points 检查 ShapeUtils 的 CCW。将 Vector3 数组分配给缓冲区几何的 .vertices 是无用的,因为该类型的几何没有该属性,因此您正在使用缓冲区属性。调用 shapeGeom.computeFaceNormals(); 也是没用的。

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';
import {GUI} from 'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js';
import { ConvexGeometry } from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/geometries/ConvexGeometry.js'

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60,window.innerWidth / window.innerHeight,1,2000);
camera.position.set(0,20,40).setLength(500).add(new THREE.Vector3(150,150,0));
camera.lookAt(150,0);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new OrbitControls(camera,renderer.domElement);
controls.target = new THREE.Vector3(10,10);
controls.update();

var grid = new THREE.GridHelper(50,50,0x808080,0x202020); // xy-grid
grid.geometry.rotateX(Math.PI * 0.5);
scene.add(grid);

var points = [ // all of them are on the xz-plane
//  new THREE.Vector3(5,5),// new THREE.Vector3(25,15),// new THREE.Vector3(15,25),// new THREE.Vector3(5,5)

new THREE.Vector3(199.2353333,7.6714966,32),new THREE.Vector3(199.0974316,276.6667291,new THREE.Vector3(75.2343077,276.6715748,232.6714966,new THREE.Vector3(101.1792999,194.6807462,194.6714966,32)/*,new THREE.Vector3(199.2353333,32)*/
]

var geom = new THREE.BufferGeometry().setFromPoints(points);
var pointsObj = new THREE.Points(geom,new THREE.PointsMaterial({
color: "red"
}));
scene.add(pointsObj);

var line = new THREE.LineLoop(geom,new THREE.LineBasicMaterial({
color: "aqua"
}));
scene.add(line);

// normals 
var normal = new THREE.Vector3(0,1); // I already know the normal of xz-plane ;)
scene.add(new THREE.ArrowHelper(normal,new THREE.Vector3(10,10),5,0xffff00)); //yellow

var normalZ = new THREE.Vector3(0,1); // base normal of xy-plane
scene.add(new THREE.ArrowHelper(normalZ,scene.position,'#FF001F' )); // aqua

// 1 quaternions
var quaternion = new THREE.Quaternion().setFromUnitVectors(normal,normalZ);
var quaternionBack = new THREE.Quaternion().setFromUnitVectors(normalZ,normal);

// 2 make it parallel to xy-plane
points.forEach(p => {
p.applyQuaternion(quaternion)
});

// 3 create shape and shapeGeometry
var shape = new THREE.Shape(points);
var shapeGeom = new THREE.ShapeBufferGeometry(shape);
shapeGeom.computeFaceNormals();
shapeGeom.computeVertexNormals();

// 4 put our points back to their origins
points.forEach(p => {
p.applyQuaternion(quaternionBack)
});

// 5 assign points to .vertices
if (!THREE.ShapeUtils.isClockWise(points)) points.reverse(); // CCW order
points.forEach((p,idx) => {
  shapeGeom.attributes.position.setXYZ(idx,p.x,p.y,p.z);
});

console.log(points.length,shapeGeom.attributes.position.count);

var shapeMesh = new THREE.Mesh(shapeGeom,new THREE.MeshBasicMaterial({
color: "#FF001F",//side: THREE.DoubleSide
}));




scene.add(shapeMesh);


// scene.add( new THREE.FaceNormalsHelper( shapeMesh ) );



render();

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