threejs个人笔记
目录
- 材质选择
- 设置物体旋转方向和位置
- 设置场景背景色
- 添加坐标轴
- 设置材质为线框 wireframe:true
- 开启灯光阴影
- 开始物体阴影
- 开启平面接受阴影
- 开启渲染器阴影
- 控制阴影精细程度
- 窗口自适应
- 遍历
- 强制设置所有材质
- 雾化效果
- 材质设置颜色
- 材质两面可见
- 以顶点颜色为基准色
- 顶点创建面
- 设置颜色
- 高斯帕曲线 Gosper curve
- 计算线段顶点之间的距离
- 创建有多个材质的对象
- applyMatrix
- 获取name属性
- 生成法向量
- 贴图的使用jpg
- 加载贴图
- 加载obj模型
- 加载gltf模型
- 加载fbx模型
- 设置光源
- 画线轨迹
- 画一个面
- 移除模型
- 经纬度转为坐标
- 点击获取模型
- .remove()和·dispose()方法区别
- matrixAutoUpdate、updateMatrix
- 控制器阻尼
- 双击进入全屏和退出全屏
- dat.GUI()
- gamma
- GLTFLoader.parse报错解决办法
- threejs加载html元素
- threejs点击mesh加载弹窗
- 点击mesh元素发光
- THREE.Line在某些角度消失
- 加载scene背景图
- 后期处理
- 拖拽移动模型
- 添加视频
- 联合材质
- 色调映射增加曝光
- 点材质(PointsMaterial)
- 点精灵材质(SpriteMaterial)
- 传输帧数库 Stats.js
- 操作实验库 dat.GUI
- ThreeBSP布尔运算库
- WebGLRenderer
- 获取鼠标点击的三维坐标
材质选择
从左往右依次对应
MeshBasicMaterial(基础材质,不受光照影响)
MeshStandardMaterial(PBR标准材质)
MeshPhongMaterial(高光材质,适用于陶瓷,烤漆类质感)
MeshToonMaterial(卡通材质,俗称三渲二)
MeshStandardMaterial(PBR标准材质模拟金属反射)
设置物体旋转方向和位置
//设置位置
plane.position.x=10;
plane.position.y=10;
plane.position.z=10;plane.position.set(10,10,10)plane.position=new THREE.Vector3(10,10,10)
//旋转
plane.rotation.x = -0.5 * Math.PI;plane.rotation.set(-0.5 * Math.PI,0,0)plane.rotation=new THREE.Vector3(-0.5 * Math.PI,0,0)
//如果想使用度数(0到360)设置旋转。
var degrees=45
var inRadius=degree * (Math.PI/180)
//平移
plane.translateX(4)
设置场景背景色
renderer.setClearColor(new THREE.Color(0x000000));
添加坐标轴
var axes = new THREE.AxesHelper(20);scene.add(axes);
设置材质为线框 wireframe:true
var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xFF0000,wireframe: true});
开启灯光阴影
spotLight.castShadow = true;
// 灯光阴影
// 1、材质要满足能够对光照有反应
// 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
// 3、设置光照投射阴影 directionalLight.castShadow = true;
// 4、设置物体投射阴影 sphere.castShadow = true;
// 5、设置物体接收阴影 plane.receiveShadow = true;
注:接受阴影材质
const material = new THREE.MeshPhongMaterial({ color: 0x808080, side: THREE.DoubleSide });
开始物体阴影
sphere.castShadow = true;
开启平面接受阴影
plane.receiveShadow = true;
开启渲染器阴影
renderer.shadowMap.enabled = true;
控制阴影精细程度
spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
spotLight.shadow.camera.fov = 30;
窗口自适应
window.addEventListener('resize', onWindowResize, false);
function resize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);renderer.setPixelRatio(window.devicePixelRatio);}
遍历
scene.traverse(function (e) {console.log(e) //Scene Mesh AmbientLight SpotLight})
强制设置所有材质
见9.1.1
scene.overrideMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
雾化效果
两种
//颜色 near近处属性值 far远处属性值
scene.fog = new THREE.Fog(0xffffff, 10, 100);
//颜色 浓度
scene.fog = new THREE.FogExp2(0xffffff, 0.015);
材质设置颜色
material.color.setStyle("#9370DB");
材质两面可见
var material = new THREE.MeshBasicMaterial({color: 0x0000ff, //颜色side: THREE.DoubleSide //两面可见
});
以顶点颜色为基准色
var material = new THREE.PointsMaterial({// 使用顶点颜色数据渲染模型,不需要再定义color属性// color: 0xff0000,vertexColors: THREE.VertexColors, //以顶点颜色为准size: 10.0 //点对象像素尺寸
});
顶点创建面
new THREE.Vector3(0, 0, 0) 表示坐标x:0,y:0,z:0
let p1 = new THREE.Vector3(0, 0, 0);
let p2 = new THREE.Vector3(10, 0, 0);
let p3 = new THREE.Vector3(0, 0, 10);
let p4 = new THREE.Vector3(10, 0, 10);
创建Geometry, 并将顶点添加到Geometry的顶点数组vertices中
let geometry = new THREE.Geometry();// 顶点添加到Geometry的顶点数组vertices中
geometry.vertices.push(p1, p2, p3, p4);
创建点模型对象
// 必须使用对应点的材质,size为点的大小let material = new THREE.PointsMaterial( {color: 'red', size:2} );let mesh = new THREE.Points( geometry, material );scene.add( mesh );
new THREE.Face3(0,2,1)
0,2,1:上面geometry.vertices.push(p1, p2, p3, p4)后geometry的下标索引值
let face1 = new THREE.Face3(0, 2, 1, new THREE.Vector3(), new THREE.Color(), 0);
let face2 = new THREE.Face3(1, 2, 3, new THREE.Vector3(), new THREE.Color(), 1);
var material = new THREE.MeshStandardMaterial( { color : 0x00cc00 } );//创建仅有一个三角面片的几何体
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( -50, -50, 0 ) );
geometry.vertices.push( new THREE.Vector3( 50, -50, 0 ) );
geometry.vertices.push( new THREE.Vector3( 50, 50, 0 ) );//利用顶点 0, 1, 2 创建一个面
var normal = new THREE.Vector3( 0, 1, 0 ); //optional
var color = new THREE.Color( 0xffaa00 ); //optional
var materialIndex = 0; //optional
var face = new THREE.Face3( 0, 1, 2, normal, color, materialIndex );//将创建的面添加到几何体的面的队列
geometry.faces.push( face );//如果没有特别指明,面和顶点的法向量可以通过如下代码自动计算
geometry.computeFaceNormals();
geometry.computeVertexNormals(); // 通过平均面法线来计算顶点法线,效果更光滑scene.add( new THREE.Mesh( geometry, material ) );
Face3( a : Integer, b : Integer, c : Integer, normal : Vector3, color : Color, materialIndex : Integer )
a — 顶点 A 的索引。
b — 顶点 B 的索引。
c — 顶点 C 的索引。
normal — (可选) 面的法向量 (Vector3) 或顶点法向量队列。 如果参数传入单一矢量,则用该量设置面的法向量 .normal,如果传入的是包含三个矢量的队列, 则用该量设置 .vertexNormals
color — (可选) 面的颜色值 color 或顶点颜色值的队列。 如果参数传入单一矢量,则用该量设置 .color,如果传入的是包含三个矢量的队列, 则用该量设置 .vertexColors
materialIndex — (可选) 材质队列中与该面对应的材质的索引。
设置颜色
函数名 | 描述 |
---|---|
set(value) | 将当前颜色设置为指定的十六进制值。这个值可以是字符串、数值或是已有的THREE.Color实例 |
setHex(value) | 将当前颜色设置为指定的十六进制值 |
setRGB(r,g,b) | 根据提供的RGB值设置颜色。参数范围从0到1 |
setHSL(h,s,l) | 根据提供的HSL值设定颜色。参数范围从0到1. |
setStyle(style) | 根据css设置颜色的方式来设置颜色。 |
copy(color) | 从提供的颜色对象复制颜色到当前对象 |
copyGammaToLinear(color) | 用THREE.Color提供的实例设置对象的颜色,颜色是由伽马色彩空间转换到线性色彩空间得来的。伽马色彩空间也使用RGB颜色,但是会使用指数系数而不是线性系数。 |
copyLinearToGamma(color) | 用THREE.Color提供的实例设置对象的颜色。颜色是由线性色彩空间转换到伽马色彩空间得来的。 |
convertGammaToLinear() | 将当前颜色从伽马色彩空间转换到线性色彩空间 |
convertLinearToGamma() | 将当前颜色从线性色彩空间转换到伽马色彩空间 |
getHex() | 以十六进制值形式从颜色对象中获取颜色值:435241 |
getHexString() | 以十六进制字符串形式从颜色对象中获取颜色值:“0c0c0c” |
getStyle() | 以css值的形式从颜色对象中获取颜色值:“rgb(112,0,0)” |
getHSL(optionalTarget) | 以HSL值的形式从颜色对象中获取颜色值。如果提供了optionalTarget对象,Three.js将把h、s和l属性设置到该对象 |
offsetHSL(h,s,l) | 将提供的h、s和l值添加到当前颜色的h、s和l上 |
add(color) | 将r,g,b值添加到当前颜色 |
addColors(color1,color2) | 将color1和color2相加,再将得到的值设置到当前颜色上 |
addScalar(s) | 在当前颜色的RGB分量上添加值,谨记内部值范围从0到1 |
multiply(color) | 将当前颜色的RGB值与THREE.color对象上的RGB值相乘 |
multiplyScalar(s) | 将当前颜色RGB值与提供的RGB值相乘。谨记内部值范围从0到1 |
lerp(color,alpha) | 找出介于对象的颜色和提供的颜色之间的颜色,aplha属性定义了当前颜色与提供颜色的差距 |
equals(color) | 如果THREE.color对象实例提供的颜色的RGB值与当前颜色相等,则返回true |
fromArray(array) | 与setRGB方法具有相同的功能,只是RGB值可以通过数字数组的方式作为参数传入 |
toArray | 返回三个元素的数组:[r,g,b] |
clone() | 复制当前颜色 |
高斯帕曲线 Gosper curve
var points = gosper(4, 60);
计算线段顶点之间的距离
//获取gosper曲线的x、y坐标点
var points = gosper(3, 60);//为每个坐标创建一个顶点,并把它们放在lines属性中
var lines = new THREE.Geometry();
//同时每个坐标还会计算一个颜色值,用来设置colors属性
var colors = [];
var i = 0;
points.forEach(function (e) {lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y));colors[i] = new THREE.Color(0xffffff);//这里使用setHSL()方法设置颜色(色调、饱和度、亮度)colors[i].setHSL(e.x / 100 + 0.5, ( e.y * 20 ) / 300, 0.8);i++;
});
lines.colors = colors;//使用虚线材质的话,必须调用 computeLineDistances()方法
lines.computeLineDistances();//创建线段基础材质
var material = new THREE.LineDashedMaterial({vertexColors: true,color: 0xffffff,dashSize: 2,gapSize: 2,scale: 2
});//通过创建的材质结合几何体即可创建一个 THREE.Line网格。
var line = new THREE.Line(lines, material);
line.position.set(25, -30, -60);
scene.add(line);
创建有多个材质的对象
var meshMaterial = new THREE.MeshNormalMaterial();var wireFrameMat = new THREE.MeshBasicMaterial();// create a multimaterialvar plane = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);
applyMatrix
为每个对象创建一个Matrix4,然后我们将矩阵与该矩阵相乘以应用后续操作。
x轴移 -390,y轴移 -174。
geom.applyMatrix(new THREE.Matrix4().makeTranslation(-390, -174, 0));
绕Z轴旋转-180° * 0.25=45°
sphere_matrix.multiply(new THREE.Matrix4().makeRotationZ(-Math.PI * 0.25));
获取name属性
cloud.name = "particles";scene.getObjectByName("particles")
生成法向量
geometry.computeFaceNormals();
geometry.computeVertexNormals();
贴图的使用jpg
var textureGrass = THREE.ImageUtils.loadTexture("../assets/textures/ground/grasslight-big.jpg");//设置纹理的重复模式textureGrass.wrapS = THREE.RepeatWrapping;textureGrass.wrapT = THREE.RepeatWrapping;textureGrass.repeat.set(4, 4);// uv两个方向纹理重复数量var planeGeometry = new THREE.PlaneGeometry(1000, 200, 20, 20);var planeMaterial = new THREE.MeshLambertMaterial({map: textureGrass});var plane = new THREE.Mesh(planeGeometry, planeMaterial);plane.receiveShadow = true;
加载贴图
普通贴图
material.map,替代颜色
法线贴图
material.normalMap,让细节程度较低的表面生成高细节程度的精确光照方向和反射效果
环境光遮蔽贴图
material.aoMap,用来描绘物体和物体相交或靠近的时候遮挡周围漫反射光线的效果
环境反射贴图
material.envMap,用于模拟材质反射周围环境的效果
var textureLoader = new THREE.TextureLoader();var material = new THREE.MeshBasicMaterial({map: textureLoader.load('/assest/dot.png'),transparent: true, //使用背景透明的png贴图,注意开启透明计算// side: THREE.DoubleSide, //双面可见});
加载obj模型
// instantiate a loader
const loader = new OBJLoader();
// load a resource
loader.load(// resource URL'models/monster.obj',// called when resource is loadedfunction ( object ) {scene.add( object );},// called when loading is in progressesfunction ( xhr ) {console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );},// called when loading has errorsfunction ( error ) {console.log( 'An error happened' );}
);
new MTLLoader().load("../models/gltf/QITA.mtl", (mtl) => {mtl.preload();const objLoader = new THREE.OBJLoader();objLoader.setMaterials(mtl);// 加载模型objLoader.load("../models/gltf/QITA.obj", (root) => {root.traverse((child) => {if (child instanceof THREE.Mesh) {child.material.side = THREE.DoubleSide;child.material = new THREE.MeshBasicMaterial({color: new THREE.Color("rgb(12,106,201)"),transparent: true,opacity: 0.2, //设置透明度});}});root.name = "fangzi"scene.add(root);});});
加载gltf模型
var loader = new GLTFLoader();loader.load('/assest/model/little_chestnut/scene.gltf', res => {// 处理网格模型阴影const model = res.scene.children[0];model.traverse((n => {console.log(n);if (n?.isMesh) {n.castShadow = true;n.receiveShadow = true;if (n.material.map) n.material.map.anisotropy = 100// 提高纹理影映各项异型}}))scene.add(res.scene);render();})
如果模型经过DRACO压缩,则
import {DRACOLoader} from '../plugins/Three/module/jsm/loaders/DRACOLoader.js';
const dracoLoader = new DRACOLoader();dracoLoader.setDecoderPath('../data/');const loader = new GLTFLoader();loader.setDRACOLoader(dracoLoader);loader.load(url, function (gltf) {const obj = gltf.sceneobj.scale.set(0.1, 0.1, 0.1)obj.name = name + '-model'obj.position.x = position.x / 10;obj.position.z = position.z / -10;obj.rotation.y = position.rotatescene.add(obj);});
加载fbx模型
var loader = new FBXLoader();loader.load('/assest/model/miku/miku.fbx', object => {object.scale.multiplyScalar(.1);scene.add(object);render();})
设置光源
var spotLight = new THREE.SpotLight(0xffa95c, 4);spotLight.castShadow = true; //开启点光源阴影spotLight.shadow.bias = -0.0001; //减少阴影偏移率spotLight.shadow.mapSize.width = 10000; //提高阴影映射宽高spotLight.shadow.mapSize.height = 10000; //提高阴影映射宽高scene.add(spotLight)
画线轨迹
var lineMaterial = new THREE.LineBasicMaterial({color: 0xffffff});const lineGeometry = new THREE.BufferGeometry()const pointsArray = new Array()pointsArray.push(new THREE.Vector3(x, y, z))//点坐标//用这个api传入顶点数组lineGeometry.setFromPoints(pointsArray)var line = new THREE.Line(lineGeometry, lineMaterial);scene.add(line);
画一个面
var pointsArr = [[0, 0],[0, 50],[50, 50],[50, 0],]var vector2Arr = [];// 转化为Vector2构成的顶点数组 二维向量pointsArr.forEach(elem => {vector2Arr.push(new THREE.Vector2(elem[0], elem[1]))});var shape = new THREE.Shape(vector2Arr);var material = new THREE.MeshBasicMaterial({color: 0x00ffff,side: THREE.DoubleSide, //两面可见}); //材质对象var geometry = new THREE.ShapeBufferGeometry(shape);var mesh = new THREE.Mesh(geometry, material); //网格模型对象scene.add(mesh); //网格模型添加到场景中
画多个面
var pointsArrs = [[[0, 0],[0, 50],[50, 50],[50, 0],],[[60, 60],[250, 30],[200, 150],[20, 150],]]var shapeArr = [];//轮廓形状Shape集合pointsArrs.forEach(pointsArr => {var vector2Arr = [];// 转化为Vector2构成的顶点数组 二维向量pointsArr.forEach(elem => {vector2Arr.push(new THREE.Vector2(elem[0], elem[1]))});var shape = new THREE.Shape(vector2Arr);shapeArr.push(shape);});var material = new THREE.MeshBasicMaterial({color: 0x00ffff,side: THREE.DoubleSide, //两面可见}); //材质对象var geometry = new THREE.ShapeBufferGeometry(shapeArr);var mesh = new THREE.Mesh(geometry, material); //网格模型对象scene.add(mesh); //网格模型添加到场景中
移除模型
scene.remove(scene.getObjectByName("chezi"))
经纬度转为坐标
function getPosition(longitude, latitude, radius) {//经度,纬度,半径var lg = THREE.Math.degToRad(longitude);var lt = THREE.Math.degToRad(latitude);var temp = radius * Math.cos(lt);var x = temp * Math.sin(lg);var y = radius * Math.sin(lt);var z = temp * Math.cos(lg);return {x: x,y: y,z: z}}
function createPosition(lnglat) {let spherical = new THREE.Sphericalspherical.radius = 100;const lng = lnglat[0]const lat = lnglat[1]const theta = (lng + 90) * (Math.PI / 180)const phi = (90 - lat) * (Math.PI / 180)spherical.phi = phi; // phi是方位面(水平面)内的角度,范围0~360度spherical.theta = theta; // theta是俯仰面(竖直面)内的角度,范围0~180度let position = new THREE.Vector3()position.setFromSpherical(spherical)return position}
点击获取模型
只有基础模型可获取
addEventListener('click', onMouseDblclick, false);function onMouseDblclick(event) {// 获取 raycaster 和所有模型相交的数组,其中的元素按照距离排序,越近的越靠前var intersects = getIntersects(event);// 获取选中最近的 Mesh 对象if (intersects.length !== 0 && intersects[0].object instanceof THREE.Mesh) {selectObject = intersects[0].object;//...do something} else {alert("未选中 Mesh!");}}// 获取与射线相交的对象数组function getIntersects(event) {event.preventDefault();// 声明 raycaster 和 mouse 变量var raycaster = new THREE.Raycaster();var mouse = new THREE.Vector2();// 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;//通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置raycaster.setFromCamera(mouse, camera);// 获取与射线相交的对象数组,其中的元素按照距离排序,越近的越靠前var intersects = raycaster.intersectObjects(scene.children);//返回选中的对象return intersects;}
.remove()和·dispose()方法区别
删除场景对象中Scene
一个子对象Group
,并释放组对象Group
中所有网格模型几何体的顶点缓冲区占用内存
// 递归遍历组对象group释放所有后代网格模型绑定几何体占用内存
group.traverse(function(obj) {if (obj.type === 'Mesh') {obj.geometry.dispose();//废弃模型、材质obj.material.dispose();}
})
// 删除场景对象scene的子对象group
scene.remove(group);//删除对象
//终极奥义Threejs内存清除,清的渣都不剩
function disposeChild(mesh) {if (mesh instanceof THREE.Mesh) {if (mesh.geometry?.dispose) {mesh.geometry.dispose(); //删除几何体}if (mesh.material?.dispose) {mesh.material.dispose(); //删除材质}if (mesh.material?.texture?.dispose) {mesh.material.texture.dispose();}}if (mesh instanceof THREE.Group) {mesh.clear();}if (mesh instanceof THREE.Object3D) {mesh.clear();}}
matrixAutoUpdate、updateMatrix
默认情况下,matrixAutoUpdate属性设置为true,并且将自动重新计算矩阵。
如果对象是静态的,或者您希望在重新计算时手动控制,则可以通过将属性设置为false来获得更好的性能:
object.matrixAutoUpdate = false;
//更改任何属性后,手动更新矩阵:
object.updateMatrix();
控制器阻尼
鼠标滑动模型,有缓冲效果
orbitControl.enableDamping = true
双击进入全屏和退出全屏
window.addEventListener("dblclick",()=>{const fullScreenElement=document.fullscreenElement;if(!fullScreenElement){renderer.domElement.requestFullscreen()}else{domElement.exitFullscreen()}
})
dat.GUI()
const gui=new dat.GUI()
gui.add(cube.position,"x").min(0).max(5).step(0.01).name("移动x轴").onChange((value)=>{}).onFinishChange((value)=>{})//修改物体颜色
const params={color:"#ffffff",fn:()=>{gsap.to(cube.position,{x:5,duration:2,yoyo:true,repeat:1})}
}
gui.addColor(params,"color").onChange((value)=>{cube.material.color.set(value)
})
gui.add(cube,"visible").name("是否显示")
gui.add(params,"fn").name("立方体运动")var folder=gui.addFolder("设置文件夹")
folder.add(cube.material,"wireframe")
gamma
渲染计算后的模型仍在 linear 空间, 展示到屏幕时需要通过 gamma 校正, 将 linear 转换回 sRGB 空间, 也就是进行 gamma 校正, threejs 中可通过设置 gammaOutput 和 gammaFactor, 进行 gamma 校正, 校正后的 gamma2.2 颜色空间与 sRGB 相似.
// 定义 gammaOutput 和 gammaFactor
renderer.gammaOutput = true;
renderer.gammaFactor = 2.2; // 电脑显示屏的 gammaFactor 为 2.2
GLTFLoader.parse报错解决办法
GLTFLoader.js:185 SyntaxError: Unexpected token < in JSON at position 0at JSON.parse (<anonymous>)at GLTFLoader.parse (GLTFLoader.js:315:21)at Object.onLoad (GLTFLoader.js:205:11)at three.module.js:39584:38
使用 import Flamingo from ‘./models/Flamingo.glb’ 导入模型
threejs加载html元素
import { CSS2DRenderer, CSS2DObject } from "../jsm/renderers/CSS2DRenderer.js";const earthDiv = document.createElement('div');earthDiv.className = 'label';earthDiv.innerHTML = 'Earth';earthDiv.style.marginTop = '0px';const earthLabel = new CSS2DObject(earthDiv);earthLabel.position.set(0, 1, 0);scene.add(earthLabel)labelRenderer = new CSS2DRenderer();labelRenderer.setSize(window.innerWidth, window.innerHeight);labelRenderer.domElement.style.position = 'absolute';labelRenderer.domElement.style.top = '0px';document.body.appendChild(labelRenderer.domElement);controls = new OrbitControls(camera, labelRenderer.domElement);labelRenderer.render(scene, camera);
threejs点击mesh加载弹窗
<body><div id="container"></div><div id="box" style="width: 200px;height: 200px;background-color: red;">111111111</div>
</body>import { CSS2DRenderer, CSS2DObject } from "../jsm/renderers/CSS2DRenderer.js";
let labelRenderer,labelCSS2DlabelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.body.appendChild(labelRenderer.domElement);
labelCSS2D = new CSS2DObject(document.getElementById('box'));
scene.add(labelCSS2D);
labelCSS2D.visible = falsecontrols = new OrbitControls(camera, labelRenderer.domElement);window.addEventListener('click', onMouseClick, false);var raycaster = new THREE.Raycaster()
var mouse = new THREE.Vector2()function onMouseClick(event) {var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);vector = vector.unproject(camera);var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());var intersects = raycaster.intersectObjects(scene.children);if (intersects.length) {console.log(intersects);const point = intersects[0].point;labelCSS2D.position.set(point.x - 0.01, point.y + 0.01, point.z - 0.03);labelCSS2D.visible = true} else {labelCSS2D.visible = false}}function render() {labelRenderer.render(scene, camera);renderer.render(scene, camera);}
点击mesh元素发光
import {FXAAShader } from './jsm/shaders/FXAAShader.js'
import {EffectComposer } from './jsm/postprocessing/EffectComposer.js'
import {RenderPass } from './jsm/postprocessing/RenderPass.js'
import {ShaderPass } from './jsm/postprocessing/ShaderPass.js'
import {OutlinePass } from './jsm/postprocessing/OutlinePass.js'let composer, renderPass, outlinePass, effectFXAA;window.addEventListener('click', onMouseClick, false);var raycaster = new THREE.Raycaster()
var mouse = new THREE.Vector2()function onMouseClick(event) {var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);vector = vector.unproject(camera);var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());var intersects = raycaster.intersectObjects(scene.children);if (intersects.length) {addColor("0xDC143C", [intersects[0].object])}}const addColor = (color, selectedObjects) => {// 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。composer = new EffectComposer(renderer)// 新建一个场景通道 为了覆盖到原理来的场景上renderPass = new RenderPass(scene, camera)composer.addPass(renderPass)// 物体边缘发光通道outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera)outlinePass.edgeStrength = 10.0 // 边框的亮度outlinePass.edgeGlow = 1 // 光晕[0,1]outlinePass.usePatternTexture = false // 是否使用父级的材质outlinePass.edgeThickness = 1.0 // 边框宽度outlinePass.downSampleRatio = 2 // 边框弯曲度outlinePass.pulsePeriod = 5 // 呼吸闪烁的速度outlinePass.visibleEdgeColor.set(parseInt(color)) // 呼吸显示的颜色outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0) // 呼吸消失的颜色outlinePass.clear = truecomposer.addPass(outlinePass)// 自定义的着色器通道 作为参数effectFXAA = new ShaderPass(FXAAShader)effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight)effectFXAA.renderToScreen = truecomposer.addPass(effectFXAA)outlinePass.selectedObjects = selectedObjectsreturn {composer, // composer在render循环函数中调用outlinePass // 实例化一次后设置 outlinePass.selectedObjects = selectedObjects}}//最后调用function animate() {controls.update()requestAnimationFrame(animate);render();stats.update();if (composer) {composer.render()}}
THREE.Line在某些角度消失
//如果更新线的顶点,则还必须更新线的边界球以进行平截头体剔除才能正常工作.
line.geometry.computeBoundingSphere();
//或者,您可以通过设置来防止对线进行视锥体剔除
line.frustumCulled = false;
加载scene背景图
const scene = new THREE.Scene();
scene.background = new THREE.CubeTextureLoader().setPath( 'textures/cubeMaps/' ).load( ['px.png','nx.png','py.png','ny.png','pz.png','nz.png'] );
后期处理
<!-- <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script> -->
<!-- <script type="text/javascript" src="../libs/shaders/CopyShader.js"></script> -->
<!-- <script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script> -->
<!-- <script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script> -->
<!-- <script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script> -->//创建后期处理组合器
var renderer=new THREE.WebGLRenderer()
var composer=new THREE.EffectComposer(renderer)
composer.setSize(window.innerWidth, window.innerHeight);
//设置渲染场景
const renderPass = new THREE.RenderPass(scene, camera);
composer.addPass(renderPass);
// 特效通道
const effectCopy = new THREE.ShaderPass(THREE.CopyShader);
effectCopy.renderToScreen = true;
composer.addPass(effectCopy);// 渲染场景,更新控制器
const render = () => {// 渲染场景// 启用后期处理后,需要使用 composer.render// renderer.render(scene, camera);composer.render();// 控制器更新control.update();
}// 窗口尺寸变化
const resize = () => {width = window.innerWidth;height = window.innerHeight;camera.aspect = width / height;camera.updateProjectionMatrix();renderer.setSize(width, height);composer.setSize(width, height);
};
拖拽移动模型
//引入插件
import { DragControls } from "./jsm/controls/DragControls.js"; //拖拽控件
import { TransformControls } from "./jsm/controls/TransformControls.js"; //可视化平移控件var objects = [];//需要移动的所有模型const geo = new THREE.BoxGeometry(2, 2, 2);
const mat = new THREE.MeshBasicMaterial({color:0xdddddd});
const mesh = new THREE.Mesh(geo, mat);
mesh.name = "箱子"
objects.push(mesh)//将建立的模型放入需要移动的数组中
scene.add(mesh)const clickList = new DragControls(objects, camera, renderer.domElement);
clickList.addEventListener('drag', render);
clickList.addEventListener('dragstart', function (event) {controls.enabled = false;
});
clickList.addEventListener('dragend', function (event) {controls.enabled = true;
});//也可遍历scene获取需要拖拽的模型scene.traverse((e) => {console.log(e);if (e.name === "箱子") {objects.push(e)}})
// 添加拖拽控件function initDragControls() {// 添加平移控件// var transformControls = new THREE.TransformControls(camera, renderer.domElement);// scene.add(transformControls);// 过滤不是 Mesh 的物体,例如辅助网格var objects = [];for (let i = 0; i < scene.children.length; i++) {if (scene.children[i].isMesh) {objects.push(scene.children[i]);}}// 初始化拖拽控件var dragControls = new THREE.DragControls(objects, camera, renderer.domElement);// 鼠标略过dragControls.addEventListener('hoveron', function (event) {transformControls.attach(event.object);});// 开始拖拽dragControls.addEventListener('dragstart', function (event) {controls.enabled = false;});// 拖拽结束dragControls.addEventListener('dragend', function (event) {controls.enabled = true;});}function init(){initDragControls()
}
添加视频
let video = document.createElement('video');
video.src = "1086x716.mp4"; // 设置视频地址
video.autoplay = "autoplay"; //要设置播放
// video对象作为VideoTexture参数创建纹理对象
var texture = new THREE.VideoTexture(video)
var geometry = new THREE.PlaneGeometry(108, 71); //矩形平面
var material = new THREE.MeshPhongMaterial({map: texture, // 设置纹理贴图
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh);
联合材质
// <script src="../../libs/examples/js/utils/SceneUtils.js"></script>function createMesh(geometry) {let meshMaterial = new THREE.MeshNormalMaterial();meshMaterial.side = THREE.DoubleSide;let wireFrameMaterial = new THREE.MeshBasicMaterial();wireFrameMaterial.wireframe = true;let circle = new THREE.SceneUtils.createMultiMaterialObject(geometry, [meshMaterial, wireFrameMaterial]);return circle;}
色调映射增加曝光
renderer.toneMapping = THREE.ReinhardToneMapping;//色调映射
renderer.toneMappingExposure = 5;//增加曝光
renderer.shadowMap.enabled = true; //启动阴影映射功能
## 6、灯光### 1.0光源的基类(Light)所有其他的光类型都继承了该类描述的属性和方法。Light( color : Integer, intensity : float )color - (可选参数) 16进制表示光的颜色。 缺省值 0xffffff (白色)。
intensity - (可选参数) 光照强度。 缺省值 1。属性```js
.color : Color
光源的颜色。如果构造的时候没有传递,默认会创建一个新的 Color 并设置为白色。.intensity : Float
光照的强度,或者说能量。 在 physically correct 模式下, color 和强度 的乘积被解析为以坎德拉(candela)为单位的发光强度。 默认值 - 1.0
.isLight : Boolean
用来校验这个类或者派生类是不是平行光。默认是 true。
方法
.copy ( source : Light ) : Light
从source复制 color, intensity 的值到当前光源对象中。.toJSON ( meta : String ) : JSON
以JSON格式返回光数据。
点材质(PointsMaterial)
Points使用的默认材质。
PointsMaterial( parameters : Object )
parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
//This will add a starfield to the background of a scene
var starsGeometry = new THREE.Geometry();for ( var i = 0; i < 10000; i ++ ) {var star = new THREE.Vector3();star.x = THREE.Math.randFloatSpread( 2000 );star.y = THREE.Math.randFloatSpread( 2000 );star.z = THREE.Math.randFloatSpread( 2000 );starsGeometry.vertices.push( star );}var starsMaterial = new THREE.PointsMaterial( { color: 0x888888 } );var starField = new THREE.Points( starsGeometry, starsMaterial );scene.add( starField );
属性
.color : Color
材质的颜色(Color),默认值为白色 (0xffffff)。.isPointsMaterial : Boolean
用于检查此类或派生类是否为点材质。默认值为 true。因为其通常用在内部优化,所以不应该更改该属性值。.map : Texture
使用Texture中的数据设置点的颜色。.morphTargets : Boolean
材质是否使用morphTargets。默认值为false。.size : Number
设置点的大小。默认值为1.0。.sizeAttenuation : Boolean
指定点的大小是否因相机深度而衰减。(仅限透视摄像头。)默认为true。
点精灵材质(SpriteMaterial)
一种使用Sprite的材质。
SpriteMaterial( parameters : Object )
parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material 和 ShaderMaterial继承的任何属性)。
属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色), 内部调用Color.set(color)。 SpriteMaterials不会被Material.clippingPlanes裁剪。
var spriteMap = new THREE.TextureLoader().load( 'textures/sprite.png' );var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set(200, 200, 1)scene.add( sprite );
属性
.color : Color
材质的颜色(Color),默认值为白色 (0xffffff)。 .map会和 color 相乘。.fog : boolean
材质是否受场景雾的影响。默认值为false。.lights : Boolean
材质是否受到光照的影响。默认值为 false。.map : Texture
颜色贴图。默认为null。.rotation : Radians
sprite的转动,以弧度为单位。默认值为0。.sizeAttenuation : Boolean
精灵的大小是否会被相机深度衰减。(仅限透视摄像头。)默认为true。
传输帧数库 Stats.js
initStats(type)
type参数:0:fps,1:ms,2:mb,3+:custom
var stats = initStats();stats = new Stats();
container.appendChild(stats.dom);function renderScene() {stats.update();requestAnimationFrame(renderScene);renderer.render(scene, camera);}
操作实验库 dat.GUI
var gui = new dat.GUI();var controls = new function () {this.rotationSpeed = 0.02;this.bouncingSpeed = 0.03;};gui.add(controls, 'rotationSpeed', 0, 0.5);gui.add(controls, 'bouncingSpeed', 0, 0.5);var trackballControls = initTrackballControls(camera, renderer);
var clock = new THREE.Clock();
function render() {// update the stats and the controlstrackballControls.update(clock.getDelta());stats.update();// rotate the cube around its axescube.rotation.x += controls.rotationSpeed;cube.rotation.y += controls.rotationSpeed;cube.rotation.z += controls.rotationSpeed;// bounce the sphere up and downstep += controls.bouncingSpeed;sphere.position.x = 20 + (10 * (Math.cos(step)));sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));// render using requestAnimationFramerequestAnimationFrame(render);renderer.render(scene, camera);}
gui.add(sphere.position, "x").min(-5).max(5).step(0.1);
gui.add(spotLight, "angle").min(0).max(Math.PI / 2).step(0.01);
gui.add(spotLight, "distance").min(0).max(10).step(0.01);
gui.add(spotLight, "penumbra").min(0).max(1).step(0.01);
gui.add(spotLight, "decay").min(0).max(5).step(0.01);
ThreeBSP布尔运算库
three.js本身并没有提供用于几何体布尔运算的构造函数,需要借助一个库ThreeBSP.js实现。几何体的布尔运算可以借助数学中学习的差集、并集、交集概念去理解, 几何体之间的运算本质上就是两个顶点集合的运算,具体运算的算法可以查看计算几何学的理论内容,多数的三维软件基本都有布尔运算的相关命令, 尤其是机械类的三维建模软件,对于计算机辅助设计有兴趣的可以多研究。
//引入js库
//<script src="./ThreeJs/js/ThreeBSP.js"></script>/*** 创建网格模型*/
//几何体对象var cylinder = new THREE.CylinderGeometry(50,50,5,40);//圆柱var box = new THREE.BoxGeometry(40,5,40);//立方体//材质对象var material=new THREE.MeshPhongMaterial({color:0x0000ff});//网格模型对象var cylinderMesh=new THREE.Mesh(cylinder,material);//圆柱var boxMesh=new THREE.Mesh(box,material);//立方体//包装成ThreeBSP对象var cylinderBSP = new ThreeBSP(cylinderMesh);var boxBSP = new ThreeBSP(boxMesh);var result = cylinderBSP.subtract(boxBSP);//ThreeBSP对象转化为网格模型对象var mesh = result.toMesh();scene.add(mesh);//网格模型添加到场景中
方法 | 作用 |
---|---|
intersrct | 交集、重合的部分 |
union | 并集、组合、相加 |
subtract | 差集、相减 |
WebGLRenderer
let renderer = new THREE.WebGLRenderer({antialias: true, // true/false表示是否开启反锯齿alpha: true, // true/false 表示是否可以设置背景色透明precision: 'highp', // highp/mediump/lowp 表示着色精度选择premultipliedAlpha: false, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率)preserveDrawingBuffer: true, // true/false 表示是否保存绘图缓冲maxLights: 3, // 最大灯光数stencil: false // false/true 表示是否使用模板字体或图案});
document.getElementById('threeCanvas').appendChild(renderer.domElement);
renderer.name = 'Renderer';
renderer.setClearColor(0xEEEEEE);
renderer.setSize(width, height);
renderer.toneMappingExposure = 5;//增加曝光
renderer.toneMapping = THREE.ReinhardToneMapping;//色调映射
renderer.shadowMap.enabled = true; //启动阴影映射功能
获取鼠标点击的三维坐标
addEventListener('click', onDocumentMouseDown, false);function onDocumentMouseDown(event) {event.preventDefault();var vector = new THREE.Vector3();//三维坐标对象vector.set((event.clientX / window.innerWidth) * 2 - 1,- (event.clientY / window.innerHeight) * 2 + 1,0.5);vector.unproject(camera);var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());var intersects = raycaster.intersectObjects(scene.children);if (intersects.length > 0) {var selected = intersects[0];//取第一个物体console.log("x坐标:" + selected.point.x);console.log("y坐标:" + selected.point.y);console.log("z坐标:" + selected.point.z);}}
个人收藏,编写不易,给个小心心。
threejs个人笔记相关推荐
- Extjs 4.2 MVC+ThreeJs学习笔记(二)一个简单的ThreeJS场景
ThreeJS基本要素 在我们用ThreeJS创建的3D世界里,会有很多的元素,然而以下四个是最基本的元素,也就是说只要包含了这些元素,就可以渲染出一个场景. 一个Scene(场景) 一个render ...
- Threejs学习笔记
Three.js Three.js 学习笔记,来自: https://gitchat.csdn.net/columnTopic/5b320731bebc3c4bd7e725cb?utm_source= ...
- threejs学习笔记:实现导入的动画gltf模型播放动画
这种方式需要gltf模型本身就带有动画,就是在建模的时候添加了动画,否则是不会生效的 只有一个动作 // 用于收集动画 const clock: THREE.Clock = new THREE.Clo ...
- threejs学习笔记:CSS2DObject 2d文字渲染
import {CSS2DRenderer,CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer.js";/ ...
- Three-js 学习笔记(2)——几何体
1,安装three npm install --s three 2,渲染几何图形 (1)添加vue元素 <template><div class="geometry_01& ...
- threejs 3d
threejs学习笔记 1. 官网 2. 本地搭建官网 3. 新的打包工具(parcel) 官网 使用 4. 使用threejs去渲染第一个场景和物体 5. 添加轨道控制器 6. 坐标辅助器 7. 控 ...
- threejs 物体根据相机位置显示_Threejs学习笔记(一) 基础篇
基本概念 此学习笔记主要记录使用threejs的制作http://sqace.163.com网站中用到的API和相关知识点. 一个完整的3D环境包含以下元素: 1.场景(Scene):是物体.光源等元 ...
- threejs 形状几何体_ThreeJS学习笔记(五)——二维几何体元素及穿梭动画
二维几何体 ThreeJS可以创建三种二维几何体,包括CircleGeometry(圆形),PlaneGeometry(矩形),ShapeGeometry(自定义形状). 创建二维几何体和创建三维几何 ...
- Blender建模笔记 | 大帅老猿threejs特训
写在前面 随着5G的普及网速变得越来快元宇宙的概念应然而生,需要多公司都开始搭建自己的沉浸式应用.搭建元宇宙项目的方案有很多种,比较常见的就是通过Threejs来实现.对于我们程序员由设计人员提供的模 ...
最新文章
- 思维dp ---- K步最短路 D. Explorer Space
- C#事件(event)解析
- 浏览器字体大小设置_全新内核 Edge 浏览器来了,这回或许能成为你的真 · 默认浏览器...
- 【Servlet3.0新特性】第03节_文件上传
- 倒果汁c语言,水果榨汁补维生素C?这些补维生素的错误别再犯了
- 条件编译#ifndef和#endif
- Oracle 分区表中索引失效
- Android MessageQueue与Message详解
- Nginx-代理服务器
- 【驱动详解】如何理解驱动程序
- 【JavaScript:快速入门】
- 初中教资计算机考试知识点,教资考试初中物理电学知识点总结来了
- 大丰银行:银行IPO被否第一家,宣告商业银行IPO的审核标准发生了重大变化
- 马的Hamilton周游路线问题
- 洛谷P2016 战略游戏 - 树形DP
- uni、uview复选框圆角
- FineReport11服务器部署包安装
- VBA之正则表达式(37)-- 去除无意义的零
- java计算机毕业设计仓储ERP系统源码+数据库+系统+lw文档+部署
- 《JUnit实战(第2版)》目录—导读