【Three.js】三、three.js之几何体与网格

三、【Three.js】three.js之几何体与网格

three.js中的几何体基本上可以看成三维空间中的点集和将这些点连起来的面。如立方体是由八个顶点及其连接这些顶点的六个面组成。

一、定义一个几何体

通过定义顶点和面来自定义创建一个几何体:

	// 定义点
	let verties = [
        new THREE.Vector3(1,4,1),
        new THREE.Vector3(1,4,-1),
        new THREE.Vector3(1,0,1),
        new THREE.Vector3(1,0,-1),
        new THREE.Vector3(-1,4,-1),
        new THREE.Vector3(-1,4,1),
        new THREE.Vector3(-1,0,-1),
        new THREE.Vector3(-1,0,1)
    ];
    // 连接顶点,定义面
    let faces = [
        new THREE.Face3(0,2,1),
        new THREE.Face3(2,3,1),
        new THREE.Face3(4,6,5),
        new THREE.Face3(6,7,5),
        new THREE.Face3(4,5,1),
        new THREE.Face3(5,0,1),
        new THREE.Face3(7,6,2),
        new THREE.Face3(6,3,2),
        new THREE.Face3(5,7,0),
        new THREE.Face3(7,2,0),
        new THREE.Face3(1,3,4),
        new THREE.Face3(3,6,4)
    ];
    let geometry = new THREE.Geometry();
    geometry.vertices = verties;
    geometry.faces = faces;
    geometry.computeFaceNormals();
    // 创建材质
    let materials = [
        new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}),
        new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true})
    ];
    // 根据几何体与材质形成要显示的对象
    let mesh = createMultiMaterialObject(geometry, materials);
    mesh.castShadow = true;
    mesh.children.forEach(item => item.castShadow = true);
    scene.add(mesh);

下面是一个可以更改顶点坐标的动态几何体

import '../../stylus/index.styl'
import * as THREE from 'three';
import * as dat from 'dat.gui';
import {initStats,initTrackballControls, createMultiMaterialObject} from '../../util/util';

function init() {
    let stats = initStats();
    let scene = new THREE.Scene();
    let camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
    let renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth,window.innerHeight);
    renderer.setClearColor(0x000000);
    renderer.shadowMap.enabled = true;
    scene.add(camera);

    let axes = new THREE.AxesHelper(30);
    scene.add(axes);

    let planeGeometry = new THREE.PlaneGeometry(60, 40,1,1);
    let planeMaterial = new THREE.MeshLambertMaterial({
        color: 0xffffff
    });
    let plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.rotation.x = -0.5 * Math.PI;
    plane.receiveShadow = true;
    scene.add(plane);

    let ambientLight = new THREE.AmbientLight(0x494949);
    scene.add(ambientLight);

    let verties = [
        new THREE.Vector3(1,4,1),
        new THREE.Vector3(1,4,-1),
        new THREE.Vector3(1,0,1),
        new THREE.Vector3(1,0,-1),
        new THREE.Vector3(-1,4,-1),
        new THREE.Vector3(-1,4,1),
        new THREE.Vector3(-1,0,-1),
        new THREE.Vector3(-1,0,1)
    ];
    let faces = [
        new THREE.Face3(0,2,1),
        new THREE.Face3(2,3,1),
        new THREE.Face3(4,6,5),
        new THREE.Face3(6,7,5),
        new THREE.Face3(4,5,1),
        new THREE.Face3(5,0,1),
        new THREE.Face3(7,6,2),
        new THREE.Face3(6,3,2),
        new THREE.Face3(5,7,0),
        new THREE.Face3(7,2,0),
        new THREE.Face3(1,3,4),
        new THREE.Face3(3,6,4)
    ];
    let geometry = new THREE.Geometry();
    geometry.vertices = verties;
    geometry.faces = faces;
    geometry.computeFaceNormals();
    let materials = [
        new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}),
        new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true})
    ];
    let mesh = createMultiMaterialObject(geometry, materials);
    mesh.castShadow = true;
    mesh.children.forEach(item => item.castShadow = true);
    scene.add(mesh);

    let spotLight = new THREE.SpotLight(0xffffff,1,150,120);
    // 阴影贴图设置,值越大,阴影越清晰,占用资源也越大
    spotLight.shadow.mapSize.height = 2048;
    spotLight.shadow.mapSize.width = 2048;
    spotLight.position.set(-40, 30, 30);
    spotLight.castShadow = true;
    spotLight.lookAt(mesh);
    scene.add(spotLight);

    camera.position.x = -20;
    camera.position.y = 25;
    camera.position.z = 20;
    camera.lookAt(new THREE.Vector3(5, 0, 0));
    document.body.appendChild(renderer.domElement);
    let trackballControls = initTrackballControls(camera, renderer);
    let controlPoints = [];
    controlPoints.push(addControl(3, 5, 3));
    controlPoints.push(addControl(3, 5, 0));
    controlPoints.push(addControl(3, 0, 3));
    controlPoints.push(addControl(3, 0, 0));
    controlPoints.push(addControl(0, 5, 0));
    controlPoints.push(addControl(0, 5, 3));
    controlPoints.push(addControl(0, 0, 0));
    controlPoints.push(addControl(0, 0, 3));
    function render () {
        stats.update();
        trackballControls.update();
        let verties = [];
        controlPoints.forEach(point => {
            verties.push(new THREE.Vector3(point.x, point.y, point.z));
        });
        mesh.children.forEach(function (e) {
            e.geometry.vertices = verties;
            e.geometry.verticesNeedUpdate = true;
            e.geometry.computeFaceNormals();
            delete e.geometry.__directGeometry
        });
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }
    render();
    function addControl(x,y,z){
        return new function(){
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }

    let gui = new dat.GUI();
    gui.add(new function(){
        this.clone = function(){
            let clonedGeometry = mesh.children[0].geometry.clone();
            let materials = [
                new THREE.MeshLambertMaterial({opacity: 0.8, color: 0xff44ff, transparent: true}),
                new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
            ];

            let mesh2 = createMultiMaterialObject(clonedGeometry, materials);
            mesh2.children.forEach(function (e) {
                e.castShadow = true
            });

            mesh2.translateX(5);
            mesh2.translateZ(5);
            mesh2.name = "clone";
            scene.remove(scene.getChildByName("clone"));
            scene.add(mesh2);
        }
    }, 'clone');
    for(let i = 0; i < 8; i++) {
        let folder = gui.addFolder(`顶点${i+1}`);
        folder.add(controlPoints[i], 'x', -10, 10);
        folder.add(controlPoints[i], 'y', -10, 10);
        folder.add(controlPoints[i], 'z', -10, 10);
    }
}

window.onload = init();

在这里插入图片描述
完整示例:https://github.com/MAXLZ1/threejs_demo

二、网格对象

一个网格由一个几何体,以及一个或多个材质组成。例如上面创建的mesh。
网格对象的属性及方法:

属性(方法)说明
position该属性决定该对象相对于父对象的位置,通常父对象是THREE.Scene对象或者是THREE.Object3D对象
rotation通过该属性设置绕每个轴的旋转角度
scale通过该属性设置在x/y/z轴方向的缩放
translateX(amount)沿x轴平移amount距离
translateY(amount)沿y轴平移amount距离
translateZ(amount)沿z轴平移amount距离
visible设置是否可见,false不会被渲染到场景

2.1 属性OR方法示例

import '../../stylus/index.styl'
import * as THREE from 'three';
import * as dat from 'dat.gui';
import {initTrackballControls, initStats} from '../../util/util'

function init(){
    let stats = initStats();
    let scene = new THREE.Scene();
    let camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 100);
    let renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    scene.add(camera);

    let axes = new THREE.AxesHelper(30);
    scene.add(axes);

    let planeGeometry = new THREE.PlaneGeometry(60, 40,1,1);
    let planeMaterial = new THREE.MeshLambertMaterial({
        color: 0xffffff
    });
    let plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.rotation.x = -0.5*Math.PI;
    plane.position.x = 0;
    plane.position.y = 0;
    plane.position.z = 0;
    plane.receiveShadow = true;
    scene.add(plane);

    let cubeGeometry = new THREE.BoxGeometry(5,10,5);
    let cubeMaterial = new THREE.MeshLambertMaterial({
        color: 0x3896fe,
        opacity: .6
    });
    let cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
    cube.position.x = 2.5;
    cube.position.y = 5;
    cube.position.z = 2.5;
    cube.castShadow = true;
    scene.add(cube);

    let spotLight = new THREE.SpotLight(0xffffff,1,150,120);
    spotLight.shadow.mapSize = new THREE.Vector2(2048,2048);
    spotLight.position.set(-40, 40, 30);
    spotLight.castShadow = true;
    scene.add(spotLight);

    let ambientLight = new THREE.AmbientLight(0x494949);
    scene.add(ambientLight);

    camera.position.x = -30;
    camera.position.y = 20;
    camera.position.z = 30;
    camera.lookAt(scene.position);
    document.body.appendChild(renderer.domElement);
    // 添加控制变量
    let controls = new function(){
        this.positionX = 2.5;
        this.positionY = 5;
        this.positionZ = 2.5;
        this.rotationX = 0;
        this.rotationY = 0;
        this.rotationZ = 0;
        this.scaleX = 1;
        this.scaleY = 1;
        this.scaleZ = 1;
        this.translateX = 0;
        this.translateY = 0;
        this.translateZ = 0;
        this.visible = true;
        this.translate = function() {
            cube.translateX(controls.translateX);
            cube.translateY(controls.translateY);
            cube.translateZ(controls.translateZ);
            // 平移之后位置发生变化,重新给位置赋值
            controls.positionX = cube.position.x;
            controls.positionY = cube.position.y;
            controls.positionZ = cube.position.z;
        };
    }
    let gui = new dat.GUI();
    let guiPosition = gui.addFolder('position');
    let posX = guiPosition.add(controls, 'positionX', -10, 10).listen();
    let posY = guiPosition.add(controls, 'positionY', 5, 10).listen();
    let posZ = guiPosition.add(controls, 'positionZ', -10, 10).listen();
    posX.onChange(value => cube.position.x = value);
    posY.onChange(value => cube.position.y = value);
    posZ.onChange(value => cube.position.z = value);
    let guiRotation = gui.addFolder('rotation');
    guiRotation.add(controls, 'rotationX', -4, 4);
    guiRotation.add(controls, 'rotationY', -4, 4);
    guiRotation.add(controls, 'rotationZ', -4, 4);
    let guiScale = gui.addFolder('scale');
    guiScale.add(controls, 'scaleX', 0, 3);
    guiScale.add(controls, 'scaleY', 0, 3);
    guiScale.add(controls, 'scaleZ', 0, 3);
    let guiTranslate = gui.addFolder('translate');
    guiTranslate.add(controls, 'translateX', -10, 10);
    guiTranslate.add(controls, 'translateY', 5, 10);
    guiTranslate.add(controls, 'translateZ', -10, 10);
    guiTranslate.add(controls, 'translate');
    gui.add(controls, 'visible');
    let trackballControls = initTrackballControls(camera, renderer);
    function render(){
        stats.update();
        trackballControls.update();
        cube.rotation.x = controls.rotationX;
        cube.rotation.y = controls.rotationY;
        cube.rotation.z = controls.rotationZ;
        cube.scale.set(controls.scaleX, controls.scaleY, controls.scaleZ);
        cube.visible = controls.visible;
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }
    render();

}

window.onload = init();

在这里插入图片描述
完整示例:https://github.com/MAXLZ1/threejs_demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MAXLZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值