本段内容会写在0篇以外所有的,本人所编写的Threejs教程中
对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久
如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>
canvas{
display: block;
}
body {
margin: 0;
overscroll-behavior: none;
}
#btns{
position: absolute;
top:10%;
width: 500px;
height: 100px;
left: 50%;
transform:translateX(-50%);
}
style>
head>
<body>
<div id="btns">
<input type="button" value="关灯" id="openLight">
div>
<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js">script>
<script type="importmap">
{
"imports": {
"three": "../three.js-master/build/three.module.js"
}
}
script>
<script type="module">
import * as THREE from '../three.js-master/build/three.module.js';
import {OrbitControls} from "../three.js-master/examples/jsm/controls/OrbitControls.js";
import {GUI} from "../three.js-master/examples/jsm/libs/lil-gui.module.min.js"
import Stats from "../three.js-master/examples/jsm/libs/stats.module.js"
let scene,renderer,camera,orbitControls;
let stats,gui;
let light;
let mesh;
function init(){
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({
antialias:true
});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
camera.position.set(10,10,10);
orbitControls = new OrbitControls(camera,renderer.domElement);
let helper = new THREE.AxesHelper(5);
scene.add(helper);
light = new THREE.PointLight(0xffffff,1.0);
light.position.y += 5;
scene.add(light);
stats = new Stats({
width:500
});
document.body.appendChild(stats.dom);
gui = new GUI();
}
function addMesh(){
let geometry = new THREE.BoxGeometry(1,1,1);
let material = new THREE.MeshStandardMaterial({
color:"#ff0000"
});
mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
}
function addGUI(){
}
function addEvent(){
let btn = document.getElementById("openLight");
btn.onclick = ()=>{
if(light.intensity === 0){
light.intensity = 1;
btn.value = "关灯";
}else{
light.intensity = 0;
btn.value = "开灯";
}
}
}
function render(){
renderer.render(scene,camera);
requestAnimationFrame(render);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
stats.update();
}
init();
addMesh();
addGUI();
addEvent();
render();
script>
body>
html>
本案例中,我们去掉了渲染器设置的背景透明,使用了默认颜色的背景
在关灯状态下,我们只能看到有一个方块在中心旋转,但是我们无法区分它的颜色
在开灯状态下,我们就能看到这个方块,同时,我们也能看清楚它的棱角了,比起之前的纯色方块来说,这个方块的效果要好一些
多数代码在我的前面几篇文章已经解析完成,本篇仅针对新出现的代码进行解析
let geometry = new THREE.BoxGeometry(1,1,1);
let material = new THREE.MeshStandardMaterial({
color:"#ff0000"
});
mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
前一篇的addMesh()函数中,我们使用的是MeshBasicMaterial,MeshBasicMaterial是一种不受光照影响的材质,关于MeshBasicMaterial的使用技巧和应用范围将在后面单独出一篇教程详细介绍
本篇这里使用的材质为:MeshStandaradMaterial(标准网格材质)
以下为官方解释
https://threejs.org/docs/index.html?q=meshs#api/zh/materials/MeshStandardMaterial
当然,官方的解释不只是这些,这里我们只需要先知道,这种材质会受到光照影响,如果场景中完全没有灯光,或者灯光亮度为0时,我们将什么都看不到,只有一片黑
如果把方块看做演员,MeshBasic材质这种不受光照影响的,可以认为是穿了夜光的衣服,而MeshStandardMaterial是一种更复杂的材料,而初始的状态是需要有光才能看到
现实中亦是如此,在完全黑暗的屋子下,我们什么也看不到
既然我们的演员的衣服不带夜光,那么我们就要给它添加一盏灯
这里我们选用点光源来模拟灯泡效果
light = new THREE.PointLight(0xffffff,1.0);
light.position.y += 5;
scene.add(light);
这里因为我们需要用按钮控制灯光,且单独用一个addEvent()专门添加dom事件,所以这里将灯光写在全局变量中,正常的开发中,如果不涉及灯光的改变效果,灯光可以不放到全局变量
构造器:new PointLight( color:Integer, intensity:Float ,distance:Number,decay:Float);
color:灯光颜色
intensity:灯光亮度
distance : 灯光的辐射范围,以现实中的灯泡来说,灯泡一般都会有一个照亮范围,距离越近越亮,一直到某个地方光完全消失,distance就是用于控制点光源照亮极限的属性,默认为无限大,根据实际情况使用该值即可
decay: 官方解释为:沿着光照距离的衰退量,本案例中并未使用,暂时可以先不用刻意去理解它,感兴趣的同学可以单独开一个案例自己先研究研究
后续会专门有一篇教程来介绍点光源,本篇仅使用color和intensity,下面的两个属性建议现在了解即可
点光源官方文档:https://threejs.org/docs/index.html?q=light#api/zh/lights/PointLight
当你的灯光是白色,且亮度为1时,创建灯光时可以直接这样写:
light = new THREE.PointLight();
默认值其实就是颜色白色,灯光强度为1
然后就是灯泡要放到演员上方,如果放在(0,0,0)点的话,就放在了方块内部,在内部是不可能照亮外部的(StandardMaterial并不是透光材料)
所以这里我们将灯光移动到了(0,5,0)的位置
light.position.y += 5;
最后我们把灯光添加到场景中即可
scene.add(light)
在这篇教程中,笔者添加了一组用于添加按钮的< div >并添加了对应的css,后续的按钮均会添加到这里,按钮事件的绑定与css的部分在这里不做任何讲解,能看到这里的基本上都是有一定经验的前端了,无需多做解释
function addEvent(){
let btn = document.getElementById("openLight");
btn.onclick = ()=>{
if(light.intensity === 0){
light.intensity = 1;
btn.value = "关灯";
}else{
light.intensity = 0;
btn.value = "开灯";
}
}
}
这里我们判断灯光的当前强度,当灯光强度为1时,我们的按钮显示文字为关灯,点击按钮效果设置为让灯光强度设置为0
这里我们可以在创建好灯光后,添加这样一个Helper
let pointLightHelper = new THREE.PointLightHelper( light, 1 );
scene.add( pointLightHelper );
pointlightHelper官方文档
https://threejs.org/docs/index.html?q=light#api/zh/helpers/PointLightHelper
那么我们可以添加一个环境光,同时降低点光源的亮度,使场景亮度保持在1左右
let ambientLight = new THREE.AmbientLight( 0xffffff,0.5);
scene.add(ambientLight)
light = new THREE.PointLight(0xffffff,0.5);
light.position.y += 5;
scene.add(light);
这样既保持了方块的明暗效果,同时也让过暗的地方变的稍微能够看到一些
构造器:new AmbientLight( color, intensity)
color:灯光颜色
intensity:灯光强度
环境光会影响整个场景的亮度,但不包括设置了不受光照影响材质的物体,如MeshBasicMaterial的物体均不会受环境光影响
官方文档
https://threejs.org/docs/index.html?q=light#api/zh/lights/AmbientLight
function addGUI(){
let params = {
pointLightIntensity:light.intensity,
pointLightColor:"#ffffff",
ambientIntensity:ambientLight.intensity,
ambientColor:"#ffffff"
};
gui.add(params,"pointLightIntensity",0,2).step(0.01).name("点光源亮度").onChange((value)=>{
light.intensity = value;
});
gui.add(params,"ambientIntensity",0,2).step(0.01).name("环境光亮度").onChange((value)=>{
ambientLight.intensity = value;
});
gui.addColor(params,'pointLightColor').listen().name('点光源颜色').onChange(function (value){
light.color = new THREE.Color(value);
});
gui.addColor(params,'ambientColor').listen().name('环境光颜色').onChange(function (value){
ambientLight.color = new THREE.Color(value);
});
}
同时,我们把创建Mesh的MeshStandardMaterial修改为白色,使得默认创建一个白色方块
let material = new THREE.MeshStandardMaterial({
color:"#ffffff"
});
接下来就可以享受一下设计们的工作了,调整光源颜色和光照强度
就请各位亲自操作一下,感受一下光,点光源和环境光对物体的影响
函数: gui.addColor(对象,属性名)
这里我们创建了一个单独的params,用于方便处理颜色
函数:gui.addColor().listen() 用于监听事件动态改变颜色
其他用法均与之前介绍的dat.gui的用法一致
我们这里修改颜色使用color = new THREE.Color(),主要目的是语义明确
当我们在调试方块的时候,发现了一个问题,就是,我们的开灯和关灯,设置了灯光强度,但是右上角的LIL.GUI没有跟着变化,此时只需要手动修改一下它的值即可
但是这个功能并不常用,一般情况下,lil.gui是不会应用到实际项目中,这个gui实在太low了,还是老老实实用于调试程序比较好
function addEvent(){
let btn = document.getElementById("openLight");
btn.onclick = ()=>{
if(light.intensity === 0){
light.intensity = 1;
btn.value = "关灯";
gui.children[0].setValue(1);
}else{
light.intensity = 0;
btn.value = "开灯";
gui.children[0].setValue(0);
}
}
}
函数:gui.children[0].setValue() 用于手动更新lil.gui的值
Title