javascriptthree.jsplanebuffer-geometry

Replace plane in space with ThreeJS


I want to replace a plane in ThreeJS to a specific Z value.

I create a shapeBufferGeometry with shape which contains Vector3s containing the x y and z value.

here is my code and what I obtain. I want the white plane to match the position of aqua lines.

The code bellow allow me to render the scene with my plane the different points in it and the vertices around it.

I know that I can use translate to move the plane but I don't know how to properly use it. And how can I know on which axis should a translate my geometry depending on my vector values.

<!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, 0, 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, 0, 5),
                // new THREE.Vector3(25, 0, 5),
                // new THREE.Vector3(25, 0, 15),
                // new THREE.Vector3(15, 0, 15),
                // new THREE.Vector3(15, 0, 25),
                // new THREE.Vector3(5, 0, 25),
                // new THREE.Vector3(5, 0, 5)
    
                new THREE.Vector3(199.2353333,7.6714966,  32),
                new THREE.Vector3(199.0974316,276.6667291, 32),
                new THREE.Vector3(75.2343077,276.6715748, 32),
                new THREE.Vector3(75.2343077,232.6714966, 32),
                new THREE.Vector3(101.1792999,232.6714966, 32),
                new THREE.Vector3(101.1792999,194.6807462, 32),
                new THREE.Vector3(75.2343077,194.6714966, 32),
                new THREE.Vector3(75.2343077,7.6714966, 32),
                new THREE.Vector3(199.2353333,7.6714966, 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, 0, 1); // I already know the normal of xz-plane ;)
                scene.add(new THREE.ArrowHelper(normal, new THREE.Vector3(10, 0, 10), 5, 0xffff00)); //yellow
    
                var normalZ = new THREE.Vector3(0, 0, 1); // base normal of xy-plane
                scene.add(new THREE.ArrowHelper(normalZ, scene.position, 5,'#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:
the result I have


Solution

  • No need to add the last point to close the contour.

    And your step // 5 assign points to .vertices needs the check for CCW for points via ShapeUtils. Assigning an array of Vector3 to .vertices of a buffer geometry is useless, as that type of geometry doesn't have that property, so you're working with buffer attributes. Calling of shapeGeom.computeFaceNormals(); is also useless.

    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, 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, 0, 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, 0, 5),
    // new THREE.Vector3(25, 0, 5),
    // new THREE.Vector3(25, 0, 15),
    // new THREE.Vector3(15, 0, 15),
    // new THREE.Vector3(15, 0, 25),
    // new THREE.Vector3(5, 0, 25),
    // new THREE.Vector3(5, 0, 5)
    
    new THREE.Vector3(199.2353333,7.6714966,  32),
    new THREE.Vector3(199.0974316,276.6667291, 32),
    new THREE.Vector3(75.2343077,276.6715748, 32),
    new THREE.Vector3(75.2343077,232.6714966, 32),
    new THREE.Vector3(101.1792999,232.6714966, 32),
    new THREE.Vector3(101.1792999,194.6807462, 32),
    new THREE.Vector3(75.2343077,194.6714966, 32),
    new THREE.Vector3(75.2343077,7.6714966, 32)/*,
    new THREE.Vector3(199.2353333,7.6714966, 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, 0, 1); // I already know the normal of xz-plane ;)
    scene.add(new THREE.ArrowHelper(normal, new THREE.Vector3(10, 0, 10), 5, 0xffff00)); //yellow
    
    var normalZ = new THREE.Vector3(0, 0, 1); // base normal of xy-plane
    scene.add(new THREE.ArrowHelper(normalZ, scene.position, 5,'#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>