Three开发笔记(一)

本文详细介绍了如何使用Three.js创建首个3D场景,包括添加坐标轴、平面、摄像机和渲染器。通过实例展示了添加立方体、球体、点光源、材质和动画。同时,探讨了如何使用datGUI进行交互控制,实现对象的旋转、弹跳以及场景自适应浏览器。此外,文章还涵盖了环境光、雾化效果、几何体和材质的创建,以及摄像机的透视和正交投影。
摘要由CSDN通过智能技术生成

1. 使用Three.js创建你的第一个三维场景

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./libs/three.js"></script>
  </head>
  <body>
    <div id="WebGL-output"> </div>
      <script></script>
       
          
 </body>
</html>

首先我们要定义场景

var scene = new THREE.Scene();

坐标轴

// 创建坐标轴并添加到场景中
var axies = new THREE.AxisHelper(20);
scene.add(axies);      

添加平面

// 定义平面 宽60,高20
var planeGeomentry = new THREE.PlaneGeomentry(60,20);
// 材质
var planeMaterial = new THREE.MeshBasicMaterial({color:0xcccccc})
// 合并网格对象
var plane = new THREE.Mesh(planeGeomentry,planeMaterial)
//绕X轴旋转90度
plane.rotation.x = -0.5 * Math.PI
//场景中的位置
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
//将平面对象添加到场景中
scene.add(plane)

摄像机

// 定义摄像机
var = camera = new THREE.PerspectiveCamera(45,window.innerwidth / window.innerheight, 0.1,1000)
//设置摄像机的位置
camera.position.x = -30
camera.position.y = 40
camera.position.z = 30
//摄像机指向场景中心默认是(0,0,0)
camera.lookAt(scene.position)

渲染器

// 定义渲染器
var renderer = new THREE.WebGLRenderer()
render.setClearColorHex()
// 设置场景的背景颜色
render.setClearColor(new THREE.Color(0Xeeeeee))
//设置场景的大小
render.setSize(window.innerWidth,window.innerHeight)
// 输出元素对应的HTML元素中
document.getElementById("WebGL-output").appendChild(renderer.domElenment)
//渲染器使用指定的摄像机渲染场景
renderer.render(scene,camera)

添加物体对象

 //长方体
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true});//材质框架wireframe 将几何体渲染为线框。默认值为false(即渲染为平面多边形)
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); 
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
scene.add(cube);

//球体
var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
var sphereMaterial = new THREE.MeshBasicMaterial({color: 0x7777ff, wireframe: true});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = 20;
sphere.position.y = 4;
scene.add(sphere);

点光源

//定义点光源
var spotLight = new THREE.SpotLight(0xffffff);
//点光源位置
spotLight.position.set(-40, 60, -10);
//点光源产生投影
spotLight.castShadow = true;
scene.add(spotLight);

材质

材质MeshBasicMaterial不会对光源有任何反应,指挥使用指定的颜色渲染物体
材质MeshLambertMateriar MeshPhongMaterial 在渲染时会对光源产生反应

//没有设置光源会对象会全黑 
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });

投影

//渲染器开启渲染阴影效果
 renderer.shadowMapEnabled = true;
//平面接收投影
 plane.receiveShadow = true;
//点光源产生投影
spotLight.castShadow = true;
//物体对象产生投影
cube.castShadow = true;

动画

  function renderScene() {
        //保持动画能够持续运行
        requestAnimationFrame(renderScene);
        renderer.render(scene, camera);
      }

帧数统计图形

  <script src="./libs/stats.js"></script>
  <div id="Stats-output"></div>

function initStats() {
        var stats = new Stats();
        stats.setMode(0);
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';
        document.getElementById('Stats-output').appendChild(stats.domElement);
        return stats;
      }

var stats = initStats();
      
      function renderScene() {
        //保持动画能够持续运行
        stats.update();
        requestAnimationFrame(renderScene);
        renderer.render(scene, camera);
      }
      renderScene();

立方体旋转

function renderScene() {
    //保持动画能够持续运行
    stats.update();
    //旋转立方体
    cube.rotation.x += 0.02;
    cube.rotation.y += 0.02;
    cube.rotation.z += 0.02;

    requestAnimationFrame(renderScene);
    renderer.render(scene, camera);
  }

球体弹跳

  var step = 0;
      function renderScene() {
        //保持动画能够持续运行
        stats.update();
    
//球体弹跳
        step += 0.04;
        sphere.position.x = 20 + 10 * Math.cos(step);
        sphere.position.y = 2 + 10 * Math.abs(Math.sin(step));

        requestAnimationFrame(renderScene);
        renderer.render(scene, camera);
      }

datGUI

控制小球弹跳和立方体的旋转的速度
<script src="./libs/dat.gui.js"></script>

//js对象
      var controls = new (function () {
        this.rotationSpeed = 0.02;
        this.bouncingSpeed = 0.03;
      })();

      var gui = new dat.GUI();
      //速度范围在0~0.5
      gui.add(controls, 'rotationSpeed', 0, 0.5);
      gui.add(controls, 'bouncingSpeed', 0, 0.5);


function renderScene() {
        //保持动画能够持续运行
        stats.update();
        //旋转立方体
        let speed = controls.rotationSpeed;
        cube.rotation.x += speed;
        cube.rotation.y += speed;
        cube.rotation.z += speed;

        step += controls.bouncingSpeed;
        sphere.position.x = 20 + 10 * Math.cos(step);
        sphere.position.y = 2 + 10 * Math.abs(Math.sin(step));

        requestAnimationFrame(renderScene);
        renderer.render(scene, camera);
      }

场景自适应浏览器

 function onResize() {
     //屏幕长宽比调整
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
     //渲染器尺寸调整
        renderer.setSize(window.innerWidth, window.innerHeight);
      }
      window.addEventListener('resize', onResize, false);

2.构建Three.js场景的基本组件

环境光

 var ambientLight = new THREE.AmbientLight(0x0c0c0c);
   scene.add(ambientLight);

datGUI控制对象添加

var controls = new function () {
this.rotationSpeed = 0.02;
//场景中的对象个数
this.numberOfObjects = scene.children.length;
//移除最新添加的立方体
this.removeCube = function () {
var allChildren = scene.children;
var lastObject = allChildren[allChildren.length - 1];
if (lastObject instanceof THREE.Mesh) {
    scene.remove(lastObject);
    this.numberOfObjects = scene.children.length;
}
};
//添加随机立方体
this.addCube = function () {

var cubeSize = Math.ceil((Math.random() * 3));
var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
var cubeMaterial = new THREE.MeshLambertMaterial({color: Math.random() * 0xffffff});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
cube.name = "cube-" + scene.children.length;
//立方体随机位置
cube.position.x = -30 + Math.round((Math.random() * planeGeometry.parameters.width));
cube.position.y = Math.round((Math.random() * 5));
cube.position.z = -20 + Math.round((Math.random() * planeGeometry.parameters.height));

scene.add(cube);
this.numberOfObjects = scene.children.length;
};
//输出对象信息
this.outputObjects = function () {
console.log(scene.children);
}
};

var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', 0, 0.5);
gui.add(controls, 'addCube');
gui.add(controls, 'removeCube');
gui.add(controls, 'outputObjects');
gui.add(controls, 'numberOfObjects').listen();


function render() {
stats.update();

//立方体旋转
scene.traverse(function (e) {
    if (e instanceof THREE.Mesh && e != plane) {

        e.rotation.x += controls.rotationSpeed;
        e.rotation.y += controls.rotationSpeed;
        e.rotation.z += controls.rotationSpeed;
    }
});

// render using requestAnimationFrame
requestAnimationFrame(render);
renderer.render(scene, camera);
}

THREE.Scene.Add:向场景中添加对象
THREE.Scene.Remove:移除场景中的对象
THREE.Scene.children:获取场景中的所有的子对象列表
THREE.Scene.getObjectByName:利用name属性,获取场景中特定的对象

给场景添加雾化效果

//0xffffff白色雾化效果 0.015近处的属性值 100远处的属性值 雾的浓度线性增长
scene.fog = new THREE.Fog(0xffffff, 0.015, 100);
//另一种雾化效果,浓度0.01,浓度随距离指数增长
scene.fog=new THREE.FogExp2( 0xffffff, 0.01 );

使用overrideMaterial属性

场景中的所有物体都会使用该属性的材质,即便自身设置了材质

scene.overrideMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});

MeshLambertMaterial创建出不发光但是可以对场景中的光源产生光源的物体

THREE.Scene常用的方法和属性

方法、属性描述
add(object)向场景中添加对象,可创建对象组
children返回场景中所有对象的数组,包括摄像机和光源
getObjectByName(name,recursive)创建对象时可指定唯一标识的name,使用该刚发可以查找特定名字的对象.recursive=false在调用者子元素上查找,recursive=true在调用者的所有后台对象上查找
remove(object)object场景中对象的引用,将对象从场景中移除
traverse(function)children属性可返回场景中的所有物体,用于遍历调用者和调用者所有的后代,被调用者和每一个后代对象调用function方法
fog为场景添加雾化效果,可产生隐藏远处物体的雾化效果
overrideMaterial强制场景中的所有物体使用相同的材质

几何体

//构成几何体的顶点
var vertices = [
    new THREE.Vector3(1, 3, 1),
    new THREE.Vector3(1, 3, -1),
    new THREE.Vector3(1, -1, 1),
    new THREE.Vector3(1, -1, -1),
    new THREE.Vector3(-1, 3, -1),
    new THREE.Vector3(-1, 3, 1),
    new THREE.Vector3(-1, -1, -1),
    new THREE.Vector3(-1, -1, 1)
];
//保存由顶点链接起来创建的三角形面
var faces = [
 //new THREE.Face3(0, 2, 1)使用vertices数组中的点0,2,1创建而成的三角面         
    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),
];
//实例化几何对象
    var geom = new THREE.Geometry();
    geom.vertices = vertices;
    geom.faces = faces;
//three.js会决定每个面的法向量,法向量用于决定不同光源下的颜色
    geom.computeFaceNormals();

注意创建面的顶点时创建顺序,定点顺序决定了某个面是面向摄像机还是背向摄像机的

创建面向摄像机的面,顶点的顺序是顺时针的,反之逆时针

对于渲染器和游戏引擎来说,使用三角形更加容易,三角形渲染起来效率更高

//render动画循环中
function render(){
    //....
mesh.children.forEach(function (e) {
    //几何体网格指向一个更新后的顶点数组
    e.geometry.vertices = vertices;
    //告诉几何对象顶点更新
    e.geometry.verticesNeedUpdate = true;
    //重新计算每个面
    e.geometry.computeFaceNormals();
});
}

多种材质创建网络

var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
];
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);

//子对象都添加阴影
 mesh.children.forEach(function (e) {
    e.castShadow = true            
    });

复制一个对象

this.clone = function () {
var clonedGeometry = mesh.children[0].geometry.clone();
var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
];
//创建要复制的对象的新网格
var mesh2 = THREE.SceneUtils.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);
}

THREE.SceneUtils.createMultiMaterialObject为几何体添加线框
THREE.WireframeHelper()也可以添加线框

//为网格mesh添加线框,线框颜色0x000000
var helper=new THREE.WireframeHelper(mesh,0x000000);
scene.add(helper)

helper实际上THREE.Line对象,可设置线框如何显示,如helper.material.linewidth=2指定线框的宽度

网格对象的属性和方法

方法、属性描述
position对象相对于父对象的位置,通常父对象为THREE.Scene对象或THREE.Object3D对象
rotation设置绕每个轴旋转的旋转弧度,ThreeJs还提供了设置相对特定轴的旋转弧度的方法:rotateX(),rotateY(),rotateZ()
scale沿x,y,z轴缩放对象
translateX(amount)沿x轴将对象平移amount距离
translateY(amount)沿y轴将对象平移amount距离
translateZ(amount)沿z轴将对象平移amount距离
visible该属性为false时,Mesh将不会被渲染到场景中

设置position位置

cube.position.x=10
cube.position.y=3
cube.position.z=1
//一次性设置xyz坐标值
cube.position.set(10,3,1)
cube.positon=new THREE.Vector3(10,3,1)

THREE.SceneUtils.createMultiMaterialObject创建一个多材质对象,返回的是网格组

改变网格组中某个对象的位置,可看到两个不同的THREE.Mesh对象

移动网格组,它们的偏移量是一样的

设置rotation旋转

cube.rotation.x=0.5*Math.PI
cube.rotation.set(0.5*Math.PI,0,0)
cube.rotation=new THREE.Vector3(0.5*Math.PI,0,0)

使用度数(0~360)

var degree=45
var inRadians=degree*(Math.PI/180)

scale缩放

值大于1放大,反之缩小

cube.scale.x=1.5
cube.scale.set(1.5,1,1)
cube.scale=new THREE.Vector3(1.5,1,1)

移动

相当于当前位置的平移距离

cube.translateX(10);
cube.translateY(-10);
cube.translateZ(5);

摄像机

透视投影摄像机,对象距离摄像机越远会被渲染得越小

正交投影摄像机,所有立方体被渲染出来的尺寸都一样,对象相当于摄像机的距离不影响渲染结果

var controls = new function () {
        this.perspective = "Perspective";
    //切换摄像机
        this.switchCamera = function () {
            if (camera instanceof THREE.PerspectiveCamera) {
                //正交投影摄像机
                camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
                camera.position.x = 120;
                camera.position.y = 60;
                camera.position.z = 180;
                camera.lookAt(scene.position);
                this.perspective = "Orthographic";
            } else {
                //透视摄像机
                camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
                camera.position.x = 120;
                camera.position.y = 60;
                camera.position.z = 180;

                camera.lookAt(scene.position);
                this.perspective = "Perspective";
            }
        };
    };

透视摄像机

new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)

参数描述
fovfov表示视场,摄像机中能看到的那部分场景,推荐默认值50
aspect(长宽比)渲染结果的横向尺寸和纵向尺寸的比值,推荐默认值window.innerWidth / window.innerHeight
near(近面距离)从距离摄像机多近的距离开始渲染,通常设置尽量小,从而能够渲染从摄像机位置可看到的所有物体,推荐默认值0.1
far(远面距离)摄像机从它所在的位置能够看到多远,推荐默认值:1000
zoom(变焦)可放缩场景,负数时场景上下颠倒,推荐默认值:1

正交投影摄像机

 new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);

参数描述
left(左边界)可视范围的做屏幕,渲染不放的左边界,负值将不会看到,超过边界不会被看得
right(右边界)可渲染区域的另一个侧面
top(上边界)可渲染区域的最上面
bottom(下边界)可渲染区域的最下面
near(近面距离)基于摄像机所处位置,从这一点开始渲染场景
far(远面距离)基于摄像机所处位置,渲染场景到这一点位置
zoom(变焦)放缩场景

将摄像机聚焦在指定点上

camera.lookAt(new THREE.Vector3(x,y,z))
lookAt可以追随物体,看向特定的网格
camera.lookAt(mesh.position)

目录(共14章) 前言 本书内容 阅读之前的准备 读者对象 致谢 第1章 用Three.js创建你的第一个三维场景 1.1 使用Three.js的前提条件 1.2 获取源代码 1.3 创建HTML页面框架 1.4 渲染并展示三维对象 1.5 添加材质、灯光和阴影 1.6 用动画扩展你的首个场景 1.7 使用dat.GUI库简化试验 1.8 使用ASCII效果 1.9 总结 第2章 使用构建Three.js场景的基本组件 2.1 创建场景 2.2 使用几何和网格对象 2.3 选择合适的相机 2.4 总结 第3章 使用Three.js里的各种光源 3.1 探索Three.js库提供的光源 3.2 学习基础光源 3.3 总结 第4章 使用Three.js的材质 4.1 理解共有属性 4.2 从简单的网格材质(基础、深度和面)开始 4.3 学习高级材质 4.4 线段几何体的材质 4.5 总结 第5章 学习使用几何体 5.1 Three.js提供的基础几何体 5.2 总结 第6章 使用高级几何体和二元操作 6.1 ConvexGeometry 6.2 LatheGeometry 6.3 通过拉伸创建几何体 6.4 创建三维文本 6.5 使用二元操作组合网格 6.6 总结 第7章 粒子和粒子系统 7.1 理解粒子 7.2 粒子、粒子系统和BasicParticleMaterial 7.3 使用HTML5画布格式化粒子 7.4 使用纹理格式化粒子 7.5 从高级几何体中创建粒子系统 7.6 总结 第8章 创建、加载高级网格和几何体 8.1 几何体组合和合并 8.2 从外部资源中加载几何体 8.3 以Three.js的JSON格式保存和加载 8.4 使用Blender 8.5 导入三维格式文件 8.6 总结 第9章 创建动画和移动相机 9.1 基础动画 9.2 使用相机 9.3 变形动画和骨骼动画 9.4 使用外部模型创建动画 9.5 总结 第10章 加载和使用纹理 10.1 在材质中使用纹理 10.2 纹理的高级用途 10.3 总结 第11章 定制着色器和渲染后期处理 11.1 设置后期处理 11.2 后期处理通道 11.3 创建自定义的后期处理着色器 11.4 总结 第12章 用Physijs在场景中添加物理效果 12.1 创建可用Physijs的基本Three.js场景 12.2 材质属性 12.3 基础图形 12.4 使用约束限制对象移动 12.5 总结
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

这个程序猿有点迷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值