《Learn Three.js》学习(1)使用Three.js创建三维场景

前言:

WebGL可以直接使用显卡资源从JS创建三维场景;可用Three.js优化该复杂过程。

"构建骨架"

理论知识:

我们分别需要Three.js和TrackballControls.js两个文件作为支持库。

THREE中需要场景、相机和渲染器来构建三维元素。

scene - 场景是一个容器,用于保存、跟踪所要渲染的物体和使用的光源。

scene是渲染物体的基础。

对于物体对象的基本操作个人概括为:1、创建物体的尺寸  2、添加样式-颜色/透明度/材质  3、将尺寸和样式融合并“覆盖原物体”  4、设置物体的“外方位元素” 5、添加到场景中

camera - 相机将决定哪些东西会被渲染(可视)

renderer - 渲染场景和相机视角,        renderer.render(scene, camera);

最后将渲染挂载到div标签上,告诉渲染器使用指定摄像机渲染场景

接下来我们实现下表中的对象

sphereGeometry方法 

效果:

由于设置了旋转角,默认z轴垂直平面向外。 

代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    /* 确保容器填满整个视口 */
    #webgl-output {
        width: 100%;
        height: 100%;
        display: block;
    }
    </style>
    <script type="text/javascript" charset="UTF-8" src="./libs/three.js"></script>
    <script type="text/javascript" charset="UTF-8" src="./libs/TrackballControls.js"></script>
</head>
<body>
    <!-- 添加一个容器元素 -->
    <div id="webgl-output"></div>
    <script> 
    const init = () =>{
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer();

        // 设置背景颜色
        renderer.setClearColor(new THREE.Color(0xEEEEEE));
        // 设置渲染区域的大小
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 创建坐标轴
        var axes = new THREE.AxisHelper(20);
        scene.add(axes);

        // 创建平面
        var planeGeometry = new THREE.PlaneGeometry(60, 20);
        // 创建材质
        var planeMaterial = new THREE.MeshBasicMaterial({color: 0xcccccc});
        // 组装
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        // 平面旋转
        plane.rotation.x = -0.5 * Math.PI;
        // 平面位置
        plane.position.x = 15;
        // plane.position.set(15, 0, 0);
        // 添加到场景
        scene.add(plane);

        // 创建立方体
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);  
        cube.position.set(-4, 3, 0);
        scene.add(cube)

        // 创建球体
        var sphereGeometry = new THREE.SphereGeometry(4,20,20)
        var sphereMaterial = new THREE.MeshBasicMaterial({color: 0x7777ff, wireframe: true});
        var sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphereMesh.position.set(20, 4, 2);
        scene.add(sphereMesh);

        // 设置相机位置
        camera.position.set(-30, 40, 30);
        camera.lookAt(scene.position);

        // 将渲染器添加到dom
        document.getElementById('webgl-output').appendChild(renderer.domElement);

        // 渲染
        renderer.render(scene, camera);
    }
    init();
    </script>
</body>
</html>

"添加羽毛"

添加材质、光源、阴影效果。

理论知识:

通过castShadow属性设置,THREE.js阴影效果被开启,并使用shadow.mapSize,shadow.camera.far,shadow.camera.near来控制阴影精细化程度。

注意光源的显示必须要合适的材料,效果才能显示,eg:MeshBasicMaterial材料无效果

可以改为MeshLambertMaterial、MeshPhysicalMaterial、MeshStandardMaterial、MeshPhongMaterail(已废弃)

阴影贴图大小仅为512x512,阴影贴图必须是2的幂

告诉渲染器需要阴影效果 renderer.shadowMap.enabled = true;

此时仍然无光影效果,需要明确指定谁投射阴影,谁接受阴影。

注意需要对光源的强度和随距离衰减情况进行修改,否则材质显示为黑色。

plane.recieveShadow = true
cube.castShadow = true
sphere.castShadow = true

定义产生阴影的光源,并不是所有的光源可以产生阴影,通过Three.SpotLight定义的光源能够产生阴影。下述代码渲染阴影。

spotLight.castShadow = true
效果:

代码: 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    /* 确保容器填满整个视口 */
    #webgl-output {
        width: 100%;
        height: 100%;
        display: block;
        overflow: hidden;
    }
    </style>
    <script type="module">
        import * as THREE from '../build/three.module.js';
        window.THREE = THREE;
    </script>
</head>
<body>
    <!-- 添加一个容器元素 -->
    <div id="Stats-output">
        <div id="webgl-output"></div>
    </div>
    <script type="module"> 
    const init = () => {
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
        var renderer = new THREE.WebGLRenderer();

        // 设置背景颜色
        renderer.setClearColor(new THREE.Color(0x000000));
        // 设置渲染区域的大小
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 创建坐标轴
        var axes = new THREE.AxesHelper(20);
        scene.add(axes);

        // 创建平面
        var planeGeometry = new THREE.PlaneGeometry(60, 20);
        // 创建材质
        var planeMaterial = new THREE.MeshBasicMaterial({color: 0xecb514, side: THREE.DoubleSide});
        // 组装-创建格网
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        // 平面旋转
        plane.rotation.x = -0.5 * Math.PI;
        // 平面位置
        plane.position.set(15, 0, 0);
        plane.receiveShadow = true;
        // 添加到场景
        scene.add(plane);

        // 创建立方体
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000, emissive: 0x000000, side: THREE.DoubleSide});
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.position.set(-4, 3, 0);
        cube.castShadow = true;
        scene.add(cube);

        // 创建球体
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff, emissive: 0x000000, side: THREE.DoubleSide});
        var sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphereMesh.position.set(20, 4, 2);
        sphereMesh.castShadow = true;
        scene.add(sphereMesh);

        // 设置相机位置
        camera.position.set(-30, 40, 30);
        camera.lookAt(cube.position); // 改为看向立方体

        // 光照
        // 聚光灯
        const spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.shadow.mapSize.width = 1024;
        spotLight.shadow.mapSize.height = 1024;
        spotLight.shadow.camera.visible = false; // 不显示阴影相机
        spotLight.castShadow = true;
        spotLight.shadow.camera.far = 130;
        spotLight.shadow.camera.near = 40;
        spotLight.shadow.camera.fov = 50; // 设置阴影相机的视场角
        spotLight.intensity = 5; // 聚光灯强度
        spotLight.target = cube; // 设置聚光灯的目标
        spotLight.decay = 0.06; // 衰减
        scene.add(spotLight);

        // 添加阴影效果
        renderer.setClearColor(new THREE.Color(0x000000));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        // 设置更高的阴影贴图分辨率
        renderer.shadowMap.width = 2048; // 减少锯齿效果
        renderer.shadowMap.height = 2048;
        renderer.shadowMap.enabled = true;

        // 将渲染器添加到dom
        document.getElementById('webgl-output').appendChild(renderer.domElement);

    }
    window.onload = init;
    </script>
</body>
</html>

"初试羽翼"

让场景中的物体动起来。

requestAnimationFrame()

稳定而连续的渲染场景

        // 将渲染器添加到dom
        document.getElementById('webgl-output').appendChild(renderer.domElement);

        // 渲染循环
        function renderScene() {
            requestAnimationFrame(renderScene);
            renderer.render(scene, camera);
        }

        renderScene()

添加帧数显示

代码:

    // 添加帧数显示
    function initStates(type){
        var panelType = (typeof type !== 'undefined' && type) && (!isNaN(parseInt(type))) ? parseInt(type) : 0;
        var stats = new Stats();
        stats.showPanel(panelType);
        document.getElementById('Stats-output').appendChild(stats.dom);
        return stats;
    }
旋转立方体

效果:

代码:

// 立方体旋转
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
弹跳球

效果:

代码:

            const step = 0
			// 小球运动
			step += 0.04;
			sphereMesh.position.x = 20 + (10 * (Math.cos(step)));
			sphereMesh.position.y = 2 + (10 * Math.abs(Math.sin(step)));

GUI简化调试流程

代码:

	// 创建待GUI控制的对象
	var controls = new function(){
		this.rotationSpeed = 0.02;
		this.bouncingSpeed = 0.03;
	}

	// 创建控制器
	var gui = new dat.GUI();
	gui.add(controls, 'rotationSpeed', 0, 0.5);
	gui.add(controls, 'bouncingSpeed', 0, 0.5);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值