6.threejs的透视投影摄像机与正交投影摄像机(摄像机lookat方法、dat.GUI对象的listen()方法、)
<!DOCTYPE html>
<html>
<head>
<title>threejs-008</title>
<meta charset="UTF-8" />
<!-- <script type="module" charset="UTF-8" src="../../libs/three.js/Three.js"></script> -->
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<!--我们将把threejs渲染的效果显示在这个div中-->
<div id="webgl-output">
</div>
<div id="myStats"></div>
<script type="module">
import {
Scene, PerspectiveCamera, OrthographicCamera, WebGLRenderer, BoxGeometry,
MeshBasicMaterial, Mesh, PlaneGeometry, MeshLambertMaterial,
AmbientLight, SpotLight, Vector2, AxesHelper, Color, Fog, FogExp2,
TorusGeometry, CylinderGeometry, BufferGeometry, BufferAttribute,
DoubleSide, WireframeGeometry, LineSegments
} from "../../libs/three.js/three.js"
import {
dat } from "../../libs/dat.gui/dat.gui.js"
var scene = new Scene();
//这节课了解一下threejs中的俩种相机,常用的相机是透视投影摄像机,这个相机的特点是能将场景中的物体进行近大远小效果的渲染,这种效果也更加真实,所以我们也常常使用该相机
var camera = new PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);
//第一个参数表示这个摄像机中能够看到的那部分场景,可以理解为我们能看到的视角,越大则能够看到的范围越大;第二个参数表示渲染的长宽比,长宽比变小则场景变扁,变大则变高;
//第三个参数表示距离摄像机多近的位置开始渲染,靠近摄像机的那部分不会被渲染;第四个部分表示相机从它所处位置能够看的多远,也就是场景渲染最远位置
//下面OrthographicCamera是正交投影摄像机,其不具备将物体渲染成近大远小的效果.该相机共6个参数,第一个参数左边界,可以理解为渲染部分的左边界;第二个右边界,第三个上边界,第四个参数下边界,
//第五个参数近端距离,可以理解为相机所处位置从改点开始渲染,调整该参数可以发现场景中靠近相机的部分场景未渲染;第六个参数远端距离,可以理解为相机所处的位置从该点停止渲染
//var camera = new OrthographicCamera(window.innerWidth / -8, window.innerWidth / 8, window.innerHeight / 8, window.innerHeight / -8, 50, 100);
var render = new WebGLRenderer();
render.setClearColor(new Color(0x000000));
render.setSize(window.innerWidth, window.innerHeight);
render.shadowMap.enabled = true;
document.getElementById("webgl-output").appendChild(render.domElement);
var axes = new AxesHelper(50);
scene.add(axes);
var planeGeometry = new PlaneGeometry(100, 100);
var planeMaterial = new MeshLambertMaterial({
color: 0xAAAAAA });
var plane = new Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(15, 0, 0);
plane.receiveShadow = true;
scene.add(plane);
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
var spotLight = new SpotLight(0xFFFFFF);
spotLight.position.set(-60, 40, -65);
spotLight.castShadow = true;
spotLight.shadow.mapSize = new Vector2(1024, 1024);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
scene.add(camera);
scene.add(spotLight);
var ambienLight = new AmbientLight(0xcccccc);
scene.add(ambienLight);
//通过一个案例来观察特点,现在需要将地板plane铺上一层小方块,通过循环的方式进行,我们将这个地板分成一个个5*5的方格
for (var i = 0; i < (planeGeometry.parameters.height / 5); i++) {
for (var j = 0; j < (planeGeometry.parameters.width / 5); j++) {
var cubeGeo = new BoxGeometry(4, 4, 4);//然后创建一个4*4*4的正方体
var cubeMaterial = new MeshLambertMaterial();
cubeMaterial.color = new Color(0, Math.random() * 0.25 + 0.5, 0);//对该材质的颜色进行随机
var cube = new Mesh(cubeGeo, cubeMaterial);
cube.position.x = -(planeGeometry.parameters.width / 2) + 15 + (i * 5);
cube.position.y = 2;
cube.position.z = -(planeGeometry.parameters.height / 2) + 5 + (j * 5);
scene.add(cube);
}
}//正交投影摄像机看到的每个正方体都是一样大小的,而透视投影摄像机是近大远小
var ctrlObj = new function () {
//为了更加方便的查看俩种摄像机的表现效果,我们通过辅助库dat.GUI来进行
this.showText = "透视投影摄像机";//我们先创建一个保存相机类型的属性
this.changeCamera = function () {
//再封装一个切换相机的方法
if (camera instanceof PerspectiveCamera)//我们先对摄像机的类型进行判断
{
//若是透视投影摄像机,则我们将摄像机类型修改为正交投影摄像机
camera = new OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
camera.position.x = -30;//对相机的位置和视角进行调整并修改相机类型文本
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
this.showText = "正交投影摄像机";
}
else//否则我们将相机类型切换为透视投影摄像机
{
camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = -30;//对相机的位置和视角进行调整并修改相机类型文本
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
this.showText = "透视投影摄像机";
}
}
}
var ctrl = new dat.GUI();//然后通过辅助库将属性功能显示到浏览器中
ctrl.add(ctrlObj, "showText").listen();//这里新的方法listen,该方法可以在我们修改文本后显示出对应的文本
ctrl.add(ctrlObj, "changeCamera");
//接下来看一下相机的lookAt方法,该方法表示摄像机所指向的位置,我们先创建一个想要指向的正方体
var geometry = new BoxGeometry(8, 8, 8);
var material = new MeshLambertMaterial({
color: 0xff2288 });
var cube = new Mesh(geometry, material);
cube.position.x = 0;
cube.position.y = 8;
cube.position.z = 0;
scene.add(cube);
renderScene();
var pos = 0;//接着我们声明一个位置对象,用于保存位置的变化量
function renderScene() {
pos += 0.01;//再修改变化量值
cube.position.x = 10 + (100 * (Math.sin(pos)));//通过正弦函数使得该正方体能够在x轴方向上来回移动
camera.lookAt(cube.position);//接着我们调用相机的lookAt方法使得相机能够指向该正反体
requestAnimationFrame(renderScene);
render.render(scene, camera);
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>
渲染效果图:
7.threejs的AmbientLight光源和SpotLight聚光灯光源(dat.GUI的addFolder方法创造控制菜单分组、dat.GUI对象add的onChange方法、聚光灯光源的辅助线库和通用光源辅助线库)
<!DOCTYPE html>
<html>
<head>
<title>threejs-009</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<!--我们将把threejs渲染的效果显示在这个div中-->
<div id="webgl-output">
</div>
<div id="myStats"></div>
<script type="module">
//拿出我们之前的案例,我们在场景中添加了俩个光源,光源是渲染场景中不可或缺的一部分,threejs中有许多不同类型的光源,每种光源都有不同行为和用法
//本节课重点介绍之前用过的AmbientLight基本光源和SpotLight聚光灯光源
//我们将聚光灯光源从场景中去除,发现基本光源会均匀的照亮场景中所有物体,同时原本带有阴影效果的正方体此时的阴影也没有了,说明基本光源不会生成阴影
//通常我们不会将AmbientLight光源作为场景中唯一的光源,其通常用于柔话生硬的颜色和阴影,AmbientLight一共有俩个构造参数,第一个构造参数是光源的颜色,第二个构造参数是光照强度,默认是1
//聚光灯光源是最常用的光源之一,是一种具有锥形效果的光源,和手电筒类似,可以配置它随着距离的增大而逐渐变弱,并且可以生成阴影,聚光灯源SpotLight有6个构造参数,第一个参数是光照颜色,第二个是光照强度,第三个
//参数是光源发出光的最大距离,第四个是光线散射角度,第五个是聚光锥的半影衰减百分比,第六个是沿着光照距离的衰减量
import {
Scene, PerspectiveCamera, OrthographicCamera, WebGLRenderer, BoxGeometry,
MeshBasicMaterial, Mesh, PlaneGeometry, MeshLambertMaterial,
AmbientLight, SpotLight, Vector2, AxesHelper, Color, Fog, FogExp2,
TorusGeometry, CylinderGeometry, BufferGeometry, BufferAttribute,
DoubleSide, WireframeGeometry, LineSegments,
SpotLightHelper, CameraHelper
} from "../../libs/three.js/three.js"
import {
dat } from "../../libs/dat.gui/dat.gui.js"
var scene = new Scene();
var camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var render = new WebGLRenderer();
render.setClearColor(new Color(0x000000));
render.setSize(window.innerWidth, window.innerHeight);
render.shadowMap.enabled = true;
document.getElementById("webgl-output").appendChild(render.domElement);
var axes = new AxesHelper(50);
scene.add(axes);
var planeGeometry = new PlaneGeometry(100, 100);
var planeMaterial = new MeshLambertMaterial({
color: 0xAAAAAA });
var plane = new Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(15, 0, 0);
plane.receiveShadow = true;
scene.add(plane);
camera.position.x = -30;//为了更清晰显示效果,将相机位置修改
camera.position.y = 140;
camera.position.z = 30;
camera.lookAt(scene.position);
var spotLight = new SpotLight(0xFFFFFF);
spotLight.position.set(-60, 30, -65);//再修改聚光灯位置
spotLight.castShadow = true;
spotLight.shadow.mapSize = new Vector2(1024, 1024);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
scene.add(camera);
scene.add(spotLight);
//为了能够对后面的属性有更加详细的理解,我们需要添加俩个辅助类
var lightHelper = new SpotLightHelper(spotLight);//我们先通过聚光灯对象创建一个SpotLightHelper对象
scene.add(lightHelper);//并添加到场景中
var shadowCameraHelper = new CameraHelper(spotLight.shadow.camera);//再通过创建一个CameraHelper对象
scene.add(shadowCameraHelper);//同样添加到场景中,别忘了import这俩个模块
//同时为了能够在修改光源属性后这俩个辅助类型能够做出对应的变化,我们需要在renderScene中对这俩个对象进行刷新
//刷新后我们可以清楚的看到辅助线,这个辅助线可以显示聚光灯的光效最大距离、光线散射角度等属性
var ambienLight = new AmbientLight(0xcccccc);
//scene.add(ambienLight);
//为了更加清晰的演示光源构造函数参数的效果,我们依然可以通过辅助库dat.GUI的方法进行属性的修改
var ctrlObj = {
//AmbientLight
ambienLightintensity: 1,//创建一个对象保存基本光源的光照强度,在下面的renderScene中对属性进行修改
ambienLightColor: 0xcccccc,
//SpotLight
spotLightintensity: 1,//其他属性同理
spotLightColor: 0xFFFFFF,
spotLightDistance: 0,
spotLightAngle: Math.PI / 3,
spotPenumbra: 0,
spotDecay: 0,
}
var ctrl = new dat.GUI();
//为了在dat.GUI控制模块中进行区分AmbienLight和SpotLight,我们可以通过调用addFolder方法,创建俩个基本光源分组,这样页面菜单里就有俩个下拉分组
var ambienLightFolder = ctrl.addFolder("ambienLight");//创造第一个区域分组
ambienLightFolder.add(ctrlObj, "ambienLightintensity", 0, 5);//将原先的俩个属性加入到分组
//这里我们不在使用add方法而是addColor方法,该方法会在控制菜单模块添加一个选项,在这个选项中能够直接传入颜色变量,
//通过onChange方法告诉控制菜单在每次颜色改变的时候调用传入的函数,所以颜色属性我们不用在renderScene中进行更新,用onChange触发修改就行,但是还是要有requestAnimationFrame(renderScene)来捕捉修改动画帧,这点切记
ambienLightFolder.addColor(ctrlObj, "ambienLightColor").onChange(function (clr) {
ambienLight.color = new Color(clr);//在此处我们需要修改的是ambienLight光源的颜色值
});
var spotLightFolder = ctrl.addFolder("spotLight");//创造第二个聚光灯光源折叠区域
spotLightFolder.add(ctrlObj, "spotLightintensity", 0, 5);//同样的方法添加到dat.GUI中
spotLightFolder.addColor(ctrlObj, "spotLightColor").onChange(function (clr) {
spotLight.color = new Color(clr);
});
spotLightFolder.add(ctrlObj, "spotLightDistance", 0, 1000).onChange(function (dis) {
spotLight.distance = dis;//下面的属性同理
});
spotLightFolder.add(ctrlObj, "spotLightAngle", 0, Math.PI * 2).onChange(function (angle) {
spotLight.angle = angle;
});
spotLightFolder.add(ctrlObj, "spotPenumbra", 0, 1).onChange(function (pen) {
spotLight.penumbra = pen;
});
spotLightFolder.add(ctrlObj, "spotDecay", 0, 5).onChange(function (dec) {
spotLight.decay = dec;
});
var geometry = new BoxGeometry(8, 8, 8);
var material = new MeshLambertMaterial({
color: 0xff2288 });
var cube = new Mesh(geometry, material);
cube.castShadow = true;
cube.position.x = 0;
cube.position.y = 8;
cube.position.z = 0;
scene.add(cube);
renderScene();
function renderScene() {
lightHelper.update();
shadowCameraHelper.update();//辅助线的更新
ambienLight.intensity = ctrlObj.ambienLightintensity;
spotLight.intensity = ctrlObj.spotLightintensity;
requestAnimationFrame(renderScene);
render.render(scene, camera);
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>
渲染效果图:
8.threejs的PointLight点光源和DirectionalLight平行光源(import的挂载方法、OrbitControls轨道控制器使得我们可以用鼠标查看场景)
<!DOCTYPE html>
<html>
<head>
<title>threejs-010</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="webgl-output">
</div>
<div id="myStats"></div>
<script type="module">
// import {Scene,PerspectiveCamera,OrthographicCamera,WebGLRenderer,BoxGeometry,
// MeshBasicMaterial,Mesh,PlaneGeometry,MeshLambertMaterial,
// AmbientLight,SpotLight,Vector2,AxesHelper,Color,Fog,FogExp2,
// TorusGeometry,CylinderGeometry,BufferGeometry,BufferAttribute,
// DoubleSide,WireframeGeometry,LineSegments,
// SpotLightHelper,CameraHelper} from "../../libs/three.js/three.js"
//本节课继续介绍2种光源,PointLight点光源和DirectionalLight平行光源,先修改一下我们之前的代码书写方式
//我们发现在每次使用新的类型都需要手动导入该类的模块,这种方式过于繁琐,所以本节课开始我们将直接使用threejs已经构建好的模块库
//并且将库中所有导出模块都挂载到THREE对象上,然后我们将所有使用到threejs库中的类的地方从THRRE中导出使用
import * as THREE from "../../libs/build/three.module.js"
import {
dat } from "../../libs/dat.gui/dat.gui.js"
//为更好学习俩个光源,我们引入一些模型和库 下面是一个器皿库
import {
GLTFLoader } from "../../libs/three.js/jsm/loaders/GLTFLoader.js"//GLTFLoader是另一个库提供的 所以我们需要将该库引入
//我们将下载的threejs源码文件中的jsmm文件放置在我们的threejs文件库中 这样才能保正常使用该库
//假设模型很小看不清楚,我们可以调整摄像机位置来看清,但是这种方法很麻烦,那有没有其他方法可以让我们看清楚模型呢,接下来我们要使用OrbitControls轨道控制器
//这个库可以使得相机围绕目标机型轨道运动
import {
OrbitControls } from "../../libs/three.js/jsm/controls/OrbitControls.js"
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var render = new THREE.WebGLRenderer();
render.setClearColor(new THREE.Color(0x000000));
render.setSize(window.innerWidth, window.innerHeight);
render.shadowMap.enabled = true;
document.getElementById("webgl-output").appendChild(render.domElement);
var axes = new THREE.AxesHelper(50);
scene.add(axes);
loadModel();//在一个合适的地方调用下面声明的loadModel加入器皿到场景中
var planeGeometry = new THREE.PlaneGeometry(100, 100);
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0xAAAAAA });
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);
camera.position.x = -5;
camera.position.y = 5;
camera.position.z = 5;
camera.lookAt(scene.position);
scene.add(camera);
var spotLight = new THREE.SpotLight(0xFFFFFF);
spotLight.position.set(-60, 30, -65);
spotLight.castShadow = true;
spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
// scene.add(spotLight); 为更好理解俩个光源,先将之前所有光源去掉
var ambienLight = new THREE.AmbientLight(0xcccccc);
// scene.add(ambienLight);
//PointLight点光源是一种单点发光、照射所有方向的光源,照明弹就是一个很好的点光源例子,不能被用来创建阴影
const pointLight = new THREE.PointLight(0xffffff, 6, 60);//pointLight有四个构造参数,第一个是光照颜色默认是白色,第二个是光照强度默认是1
//第三个表示从光源到光照强度为0的位置,默认值是0,第四个表示沿着光照距离的衰退量,默认值是1
pointLight.position.set(0, 0, 2);//设置一下点光源的位置
scene.add(pointLight);//将点光源放入场景
//为了能够更清楚的了解点光源的位置,我们可以往场景中添加一个球体
var sphereGeo = new THREE.SphereGeometry(0.1);
var sphereMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000 });
var sphereMesh = new THREE.Mesh(sphereGeo, sphereMaterial);
sphereMesh.castShadow = true;
sphereMesh.position.copy(pointLight.position);//并通过copy方法将点光源的位置设置为小球的位置,以此来表示点光源
scene.add(sphereMesh);//将小球添加到场景中
var ctrlObj = {
//稳了更好的了解点光源的属性,我们依然和之前一样通过dat.GUI来进行属性的控制
pointColor: 0xffffff,//我们还是创建一个对象来保存点光源的属性
pointIntensity: 6,
pointDistance: 60,
pointdecay: 1,
dirColor: 0xffffff,//平行光源的属性也是
dirIntensity: 4,
pointLightVisible: true,
dirLightVisible: true,
}
var ctrl = new dat.GUI();//创建dat.GUI对象
var pointLightFolder = ctrl.addFolder("pointLight");//通过该对象创建一个点光源分组
pointLightFolder.addColor(ctrlObj, "pointColor").onChange(function (e) {
//然后将属性放到分组中
pointLight.color = new THREE.Color(e);
});
pointLightFolder.add(ctrlObj, "pointIntensity", 0, 10).onChange(function (e) {
pointLight.intensity = e;
});
pointLightFolder.add(ctrlObj, "pointDistance", 0, 1000).onChange(function (e) {
pointLight.distance = e;
});
pointLightFolder.add(ctrlObj, "pointdecay", 0, 100).onChange(function (e) {
pointLight.decay = e;
});
pointLightFolder.add(ctrlObj, "pointLightVisible").onChange(function (e) {
pointLight.visible = e;
sphereMesh.visible = e;
});
//接下来我们一起学习一下DirectionalLight平行光源,这种类型的光可以看作是距离很远的光,它所发出的所有光线都是相互平行的.且可以产生阴影,太阳光就是个很好的例子,
//其光强不会随着与配置的目标对象距离增大而减弱
const directionalLight = new THREE.DirectionalLight(0xffffff, 4);//其有俩个构造参数,第一个是光的颜色默认为白色;第二个是光照强度默认为1
directionalLight.castShadow = true;//设置让DirectionalLight光源产生阴影
directionalLight.shadow.mapSize.width = 2048;//再通过shadow设置一下阴影效果
directionalLight.shadow.mapSize.height = 2048;
directionalLight.position.set(20, 20, 20);//调整一下位置以便看到阴影,平射肯定到不到阴影。。
scene.add(directionalLight);
//为了帮我们看到平行光源,我们可以通过DirectionalLightHelper这个类型构造平行光源辅助线
const helper = new THREE.DirectionalLightHelper(directionalLight, 5);
//scene.add(helper);//拉远场景,我们通过辅助线可以看到平行光源的位置
//我们再来看一下DirectionalLight平行光源中的target属性,该属性表示平行光的方向目标位置,默认的目标位置为原点(0,0,0)
//为了帮助我们理解该属性,我们要用到CameraHelper这个类,上节课程已经使用过不多介绍,添加完成后我们可以看到平行光源的照射影响范围
var dirCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
//scene.add(dirCameraHelper);
var controls = new OrbitControls(camera, render.domElement);//创建OrbitControls轨道控制器对象,该类有俩个构造参数,一个是相机对象,一个是用于事件监听的HTML元素
controls.update();//然后update该对象,同时我们也需要在renderScene中实时update
var dirLightFolder = ctrl.addFolder("directionalLight");//给平行光源建立控制菜单分组
dirLightFolder.addColor(ctrlObj, "dirColor").onChange(function (e) {
directionalLight.color = new THREE.Color(e);
});
dirLightFolder.add(ctrlObj, "dirIntensity", 0, 10).onChange(function (e) {
directionalLight.intensity = e;
});
dirLightFolder.add(ctrlObj, "dirLightVisible").onChange(function (e) {
directionalLight.visible = e;
});
//接下来再往场景中添加一个正方体
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
color: 0xff2288 });
var cube = new THREE.Mesh(geometry, material);
cube.castShadow = true;//且可以产生阴影
cube.position.set(-20, 2, 0);
scene.add(cube);
// directionalLight.target = cube;//此时我们使用DirectionalLight平行光源中的target属性,让光源对准正反体,此时才可以看到正方体的阴影,同时器皿模型阴影消失了,因为没有照到它
renderScene();
var pos = 0;//现在我们希望通过点光源能够从局部观察到这个器皿模型
function renderScene() {
pos += 0.1;//我们可以让点光源动起来,可以回忆一下动画的那节课此处不过多介绍
pointLight.position.y = Math.abs(Math.sin(pos) * 2);
sphereMesh.position.copy(pointLight.position);//我们可以看到点光源也就是场景中的小球正在沿着y轴上下移动,同时模型也更加清楚的显现出了
controls.update();//实时更新OrbitControls轨道控制器,我们发现可以通过鼠标对场景进行不同角度的查看
requestAnimationFrame(renderScene);
render.render(scene, camera);
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render.setSize(window.innerWidth, window.innerHeight);
}
function loadModel() {
//我们场景中添加一个模型,我们可以封装一个loadModel方法来加载模型,在方法中我们使用一个新的类GLTFLoader,这个类可以用来加载gltf类型的模型
new GLTFLoader().setPath("model/")//设置该模型所在路径
.load("untitled.glb", function (gltf) {
//通过模型名称来将我们所需要的模型进行加载
gltf.scene.scale.set(0.01, 0.01, 0.01);//加载结束后通过回调函数设置该模型的比例大小
gltf.scene.traverse(function (object) {
//directionalLight光源是可以产生阴影的,我们先设置一下场景模型的属性
if (object.isMesh)//此处需要注意,我们需要遍历模型的所有对象
object.castShadow = true;//并且需要对其中的网格对象进行阴影设置
});
scene.add(gltf.scene);//然后将该模型添加到场景中
})
}
</script>
</body>
</html>
渲染效果图:
9.threejs的半球光光源
<!DOCTYPE html>
<html>
<head>
<title>threejs-010</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="webgl-output">
</div>
<div id="myStats"></div>
<script type="module">
//本节课介绍HemisphereLight半球光光源,其可以为室外场景创建更加自然的光照,它考虑到了天空和地面的反射
import * as THREE from "../../libs/build/three.module.js"
import {
dat } from "../../libs/dat.gui/dat.gui.js"
import {
GLTFLoader } from "../../libs/three.js/jsm/loaders/GLTFLoader.js"
import {
OrbitControls } from "../../libs/three.js/jsm/controls/OrbitControls.js"
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var render = new THREE.WebGLRenderer();
render.setClearColor(new THREE.Color(0x000000));
render.setSize(window.innerWidth, window.innerHeight);
render.shadowMap.enabled = true;
document.getElementById("webgl-output").appendChild(render.domElement);
var axes = new THREE.AxesHelper(50);
scene.add(axes);
loadModel();
var planeGeometry = new THREE.PlaneGeometry(100, 100);
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0xAAAAAA });
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);
camera.position.x = -5;
camera.position.y = 5;
camera.position.z = 5;
camera.lookAt(scene.position);
scene.add(camera);
var spotLight = new THREE.SpotLight(0xFFFFFF);
spotLight.position.set(-60, 30, -65);
spotLight.castShadow = true;
spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
// scene.add(spotLight);
var ambienLight = new THREE.AmbientLight(0xcccccc);
// scene.add(ambienLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.position.set(20, 20, 20);
scene.add(directionalLight);
const helper = new THREE.DirectionalLightHelper(directionalLight, 5);
scene.add(helper);
var dirCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(dirCameraHelper);
var controls = new OrbitControls(camera, render.domElement);
controls.update();
//首先我们将新建一个HemisphereLight半球光光源对象,第一个构造参数表示天空中发出光线的颜色默认白色,第二个表示地面发出光线的颜色默认白色,第三个参数表示光照强度,默认值1
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x00ff00, 1);
scene.add(hemisphereLight);
var ctrlObj = {
hemisphereLightVisible: true,//是否可见
skyColor: 0xffffff,//天空中发出光线颜色的属性
groundColor: 0x00ff00,//地面发出光线颜色的属性
hemisphereLightIntensity: 1,//光照强度
}
var ctrl = new dat.GUI();//通过dat.GUI库来控制半球光光源的显示隐藏,这里不过多介绍
var hemisphereLightFolder = ctrl.addFolder("hemisphereLight");
hemisphereLightFolder.add(ctrlObj, "hemisphereLightVisible").onChange(function (e) {
hemisphereLight.visible = e;
});//通过控制半球光光源的显示隐藏,观察有无其的俩种情况,发现加入半球光光源场景显示更加自然,效果也更加好了
hemisphereLightFolder.addColor(ctrlObj, "skyColor").onChange(function (e) {
hemisphereLight.color = new THREE.Color(e);
});//修改颜色可发现模型和阴影蒙上了一层对应的颜色
hemisphereLightFolder.addColor(ctrlObj, "groundColor").onChange(function (e) {
hemisphereLight.groundColor = new THREE.Color(e);
});//修改颜色可发现只有阴影颜色变化,模型上变化不明显
hemisphereLightFolder.add(ctrlObj, "hemisphereLightIntensity", 0, 10).onChange(function (e) {
hemisphereLight.intensity = e;
});//拉满关照强度,发现模型对应颜色会根据地面颜色变化
renderScene();
function renderScene() {
controls.update();
requestAnimationFrame(renderScene);
render.render(scene, camera);
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render.setSize(window.innerWidth, window.innerHeight);
}
function loadModel() {
new GLTFLoader().setPath("model/")
.load("untitled.glb", function (gltf) {
gltf.scene.scale.set(0.01, 0.01, 0.01);
gltf.scene.traverse(function (object) {
if (object.isMesh)
object.castShadow = true;
});
scene.add(gltf.scene);
})
}
</script>
</body>
</html>
渲染效果图相较上一节无明显变化 略
10.threejs的平面光光源
//本节课介绍RectAreaLight平面光光源,其从一个矩形平面上均匀地发射光线,这种光源的主要应用场景是模拟明亮的窗户或者条状灯光光源,实际在开发家具建模项目中有广泛应用
//使用它有三个注意事项,不支持阴影,只支持MeshStandardMaterial和MeshPhysicalMaterial俩种材质,必须在场景中加入RectAreaLightUniformsLib,并调用init()
import * as THREE from "../../libs/build/three.module.js"
import {
dat } from "../../libs/dat.gui/dat.gui.js"
import {
GLTFLoader } from "../../libs/three.js/jsm/loaders/GLTFLoader.js"
import {
OrbitControls } from "../../libs/three.js/jsm/controls/OrbitControls.js"
import {
RectAreaLightUniformsLib } from "../../libs/three.js/jsm/lights/RectAreaLightUniformsLib.js"
import {
RectAreaLightHelper } from "../../libs/three.js/jsm/helpers/RectAreaLightHelper.js"
//首先加入RectAreaLightUniformsLib,并调用init(),还需要导入它所在的库
RectAreaLightUniformsLib.init();
//现在我们新建一个平面光光源,他有四个构造参数,第一个表示颜色默认白色,第二个表示亮度默认为1,第三个表示宽度,默认为10,第四个表示高度,默认也为10
const rectLight = new THREE.RectAreaLight(0xff0000, 5, 4, 10);
rectLight.position.set(0, 0, 0);//设置一下位置并添加
scene.add(rectLight);
//在场景中新建一个地面用于接受光源发的光,注意平面光只支持MeshStandardMaterial和MeshPhysicalMaterial
var geoFloor = new THREE.BoxGeometry(2000, 0.1, 2000);//这里我们选择前一种材质,它多了几个属性,以后深入讲解
var matStdFloor = new THREE.MeshStandardMaterial({
color: 0xffffff, roughness: 0.2, metal: 0 });
var mshStdFloor = new THREE.Mesh(geoFloor, matStdFloor);
scene.add(mshStdFloor);//加入之后可以看到平面光,但是还是看不到光源
//为了看到光源,我们使用RectAreaLightHelper
var rectLightHelper = new RectAreaLightHelper(rectLight);
scene.add(rectLightHelper);
//可以用dat.GUI深入了解一下各个属性的效果,这里不过多介绍
渲染效果图: