雪花
注意depthTest: false
否则会出现有transparent无效
const createSnow = () => {
let map = new THREE.TextureLoader().load(snow);
let material = new THREE.SpriteMaterial({
map: map,
transparent: true,
side: THREE.DoubleSide,
color: 0xffffff,
blending: THREE.AdditiveBlending,
fog: true,
depthTest: false
});
return new THREE.Sprite(material);
};
const createEmitter = (camera, renderer) => {
const emitter = new Emitter();
const position = new Position();
position.addZone(new BoxZone(5000, 10, 5000));
return emitter
.setRate(new Rate(new Span(34, 48), new Span(0.2, 0.5)))
.addInitializers([
new Mass(1),
new Radius(new Span(10, 20)),
position,
new Life(5, 10),
new Body(createSnow()),
new RadialVelocity(0, new Vector3D(0, -1, 0), 90),
])
.addBehaviours([
new RandomDrift(10, 1, 10, 0.05),
new Rotate('random', 'random'),
new Gravity(10),
new CrossZone(new ScreenZone(camera, renderer, 20, '234'), 'dead'),
])
.setPosition({ y: 1200 })
.emit();
};
const nebulaRenderer = new SpriteRenderer(scene, THREE);
const system = new ParticleSystem();
nebula = system
.addEmitter(createEmitter(camera, renderer))
.addRenderer(nebulaRenderer)
function animal() {
if (nebula) {
nebula.update();
}
renderer.render(scene, camera)
requestAnimationFrame(animal)
}
重叠显示闪烁
logarithmicDepthBuffer - 是否使用对数深度缓存。如果要在单个场景中处理巨大的比例差异,就有必要使用
解决办法:
renderer = new THREE.WebGLRenderer( { antialias: true, logarithmicDepthBuffer: true
} );
或者
.depthTest
属性值默认true
,设置为false
可以关闭深度测试.
Raycaster intersectObject报错
Cannot read properties undefined(reading ‘side’)
解决方法: 这个报错是因为Mesh有多个材质,可以自己输出Material属性看下,是个数组导致的。我临时的解决办法是 把Material的值由数组改为对象
如何生成中文字体
首先下载思源ttf字体。
http://www.diyiziti.com/download/220/
然然后在转换字体的网页的网站,转换成json字体。
https://gero3.github.io/facetype.js/
天空盒子
1、图片
scene.background = new THREE.CubeTextureLoader()
.setPath( '/imgs/' )
.load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ]);
let textureCube = new THREE.CubeTextureLoader()
.setPath('/sky/')
.load(['Left.jpg', 'Right.jpg', 'Up.jpg', 'Down.jpg', 'Back.jpg', 'Front.jpg']);
scene.background = textureCube;
2、hdr
import {RGBELoader} from 'three/examples/jsm/loaders/RGBELoader';
import {PMREMGenerator} from 'three/src/extras/PMREMGenerator'
var texLoader = new RGBELoader();
const pmremGenerator = new PMREMGenerator(renderer); // 使用hdr作为背景色
pmremGenerator.compileEquirectangularShader();
texLoader.load('/model/model.hdr', function(texture) {
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
pmremGenerator.dispose();
scene.environment = envMap; // 给场景添加环境光效果
scene.background = envMap;
})
添加视频
let video = document.createElement('video');
video.src = "/imgs/1.mp4";
video.autoplay = true
video.loop = true
video.muted=true
video.preload = "auto";
video.play();
let texture = new THREE.VideoTexture(video)
texture.needsUpdate = true;
let geometry = new THREE.PlaneGeometry(250, 180); //矩形平面
let material = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: texture, // 设置纹理贴图
side: THREE.DoubleSide
}); //材质对象Material
let mesh = new THREE.Mesh(geometry, material);
mesh.position.set(2579.405241545493, -181.51372808235914 + 100, 150.91691453263547);
return mesh
let renderer = new THREE.WebGLRenderer({
antialias: true, //开启锯齿
alpha: true,
logarithmicDepthBuffer: true
});
sketchup能够为模型减面
OrbitController参数
// Set to false to disable this control
//鼠标控制是否可用
this.enabled = true;
// "target" sets the location of focus, where the object orbits around
//聚焦坐标
this.target = new THREE.Vector3();
// How far you can dolly in and out ( PerspectiveCamera only )
//最大最小相机移动距离(景深相机)
this.minDistance = 0;
this.maxDistance = Infinity;
// How far you can zoom in and out ( OrthographicCamera only )
//最大最小鼠标缩放大小(正交相机)
this.minZoom = 0;
this.maxZoom = Infinity;
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
//最大仰视角和俯视角
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
// How far you can orbit horizontally, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
//水平方向视角限制
this.minAzimuthAngle = - Infinity; // radians
this.maxAzimuthAngle = Infinity; // radians
// Set to true to enable damping (inertia)
// If damping is enabled, you must call controls.update() in your animation loop
//惯性滑动,滑动大小默认0.25
this.enableDamping = false;
this.dampingFactor = 0.25;
// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
// Set to false to disable zooming
//滚轮是否可控制zoom,zoom速度默认1
this.enableZoom = true;
this.zoomSpeed = 1.0;
// Set to false to disable rotating
//是否可旋转,旋转速度
this.enableRotate = true;
this.rotateSpeed = 1.0;
// Set to false to disable panning
//是否可平移,默认移动速度为7px
this.enablePan = true;
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
// Set to true to automatically rotate around the target
// If auto-rotate is enabled, you must call controls.update() in your animation loop
//是否自动旋转,自动旋转速度。默认每秒30圈
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
// Set to false to disable use of the keys
//是否能使用键盘
this.enableKeys = true;
// The four arrow keys
//默认键盘控制上下左右的键
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// Mouse buttons
//鼠标点击按钮
this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
要素
1、group
2、renderer
3、scene
4、camera
5、controls
threejs性能优化
https://blog.pig1024.me/posts/621a1fea23cc38439fdbc85d
相机居中渲染
let box3 = new THREE.Box3()
box3.expandByObject(this.allModel) // 计算模型包围盒
let size = new THREE.Vector3()
box3.getSize(size) // 计算包围盒尺寸
let center = new THREE.Vector3()
box3.getCenter(center) // 计算一个层级模型对应包围盒的几何体中心坐标
function maxSize(vec3) {
var max;
if (vec3.x > vec3.y) {
max = vec3.x
} else {
max = vec3.y
}
if (max > vec3.z) {} else {
max = vec3.z
}
return max;
}
let camera = new THREE.PerspectiveCamera(30, width / height, 1, 2000)
let max = maxSize(size); //包围盒长宽高中最大的一个值,用来表征模型的尺寸
// 1.控制渲染范围,但是不要忘记相机位于模型包围盒之外
camera.position.copy(center.clone().addScalar(max * 0.5));
// 2. 居中渲染:设置相机目标观察点,指向包围盒几何中心
camera.lookAt(center);
// 3.注意near和far尺寸控制
camera.near = max*0.1;//最好和相机位置或者说包围盒关联,别设置0.1 1之类看似小的值
camera.far = max * 3;//根据相机位置和包围大小设置,把包围盒包含进去即可,宁可把偏大,不可偏小
camera.updateProjectionMatrix();//渲染范围改变,注意更新投影矩阵
let controls = new OrbitControls(camera, renderer.domElement)
controls.target.copy(center);
controls.update()
three.js orbitcontrol更改绕x轴与z轴旋转
我们在threejs模型中可以引入orbitcontrol来控制模型交互动作,但orbitcontrol默认是以y轴为正向上轴,即旋转的时候绕x轴和y轴旋转
但我现在想让绕x轴和z轴旋转,方法是
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.z = 2900;
//关键就是设置camera的up为y轴
camera.up = new THREE.Vector3(0, 0, 1);
scene.add(camera);
A WebGL context could not be created. Reason: Web page caused context loss and was blocked
https://support.google.com/chrome/thread/25018979/status-could-not-create-a-webgl-context?hl=en
UV坐标
Canvas画布加载图片
如果作为纹理贴图使用的Canvas画布加载了图片,注意在图片加载完成的时候更新Threejs相关模型的纹理贴图。如果不更新纹理,你会发现canvas画布上的图片无法现在是Threejs模型的纹理上。
var canvas = document.createElement(“canvas”);
…
var ctx = canvas.getContext(‘2d’);
var Image = new Image();
Image.src = “./贴图.jpg”;
Image.onload = function() {
var bg = ctx.createPattern(Image, “no-repeat”);
…
// 注意图片加载完成执行canvas相关方法后,要更新一下纹理
texture.needsUpdate = true;
}
渲染参数
renderer = new THREE.WebGLRenderer({
antialias: true, //开启锯齿,
})
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setClearColor(0x6495ED);
renderer.toneMappingExposure = 0.5;
鱼眼效果
漫游
function createCure2() {
let geometry = new THREE.BufferGeometry(); //创建一个缓冲类型几何体
let line1 = new THREE.LineCurve3(
new THREE.Vector3(175.52462898895072, 16.545, 265.0279404510418),
new THREE.Vector3(45.42388223222965, 16.545, 68.37845995291991));
manyouCure = new THREE.CurvePath();
let line2 = new THREE.LineCurve3(
new THREE.Vector3(45.42388223222965, 16.545, 68.37845995291991),
new THREE.Vector3(199.35339268360357, 16.545, -94.99382829094)
)
let line3 = new THREE.LineCurve3(
new THREE.Vector3(199.35339268360357, 16.545, -94.99382829094),
new THREE.Vector3(83.607, 6.458, 26.067)
)
let line4 = new THREE.LineCurve3(
new THREE.Vector3(83.607, 6.458, 26.067),
new THREE.Vector3(126.538, 4.049, 106.781)
)
let line5 = new THREE.LineCurve3(
new THREE.Vector3(126.538, 4.049, 106.781),
new THREE.Vector3(106.223, 4.049, 102.008)
)
let line6 = new THREE.LineCurve3(
new THREE.Vector3(106.223, 4.049, 102.008),
new THREE.Vector3(68.316, 4.049, 75.350)
)
manyouCure.curves.push(line1, line2, line3, line4, line5, line6);
let personPointArr = manyouCure.getSpacedPoints(1999); //分段数100,返回101个顶点
geometry.setFromPoints(personPointArr);
}
function manyou() {
if (roamValue && manyouCure) {
if (manyouPointPercent >= 0.99) {
manyouPointPercent = 0;
}
manyouPointPercent += 0.0005;
let curePosition = manyouCure.getPointAt(manyouPointPercent);
let dir = manyouCure.getTangentAt(manyouPointPercent);
let newer = new THREE.Vector3(dir.x, 0, dir.z);
let target2 = curePosition.clone();
target2.y = target2.y;
target2.sub(newer.clone().multiplyScalar(10));
let target3 = curePosition.clone();
target3.y = target3.y;
target3.add(newer.clone().multiplyScalar(0.01));
camera.position.copy(target2)
camera.lookAt(target3);
}
}
双击正确姿势
webgl.value.addEventListener('dblclick', (event) => {
let Sx = event.offsetX; //鼠标单击位置横坐标
let Sy = event.offsetY; //鼠标单击位置纵坐标
//屏幕坐标转WebGL标准设备坐标
let x = (Sx / renderer.domElement.clientWidth) * 2 - 1; //WebGL标准设备横坐标
let y = -(Sy / renderer.domElement.clientHeight) * 2 + 1; //WebGL标准设备纵坐标
let raster = new THREE.Raycaster();
raster.setFromCamera(new THREE.Vector2(x, y), camera);
let intersects = raster.intersectObjects(scene.children);
if (intersects.length > 0) {// 判断参数[boxMesh]中模型对象是否与射线相交
console.log("选中的对象", intersects[0])
console.log("射线投射器返回的对象 点point", intersects[0].point);
console.log('相机的位置', camera.position)
}
})
function onMouseDbClick(event) {
//声明raycaster和mouse变量
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let map = document.getElementById('map');
//通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1.
// mouse.x = (event.offsetX / map.scrollWidth) * 2 - 1;
// mouse.y = -(event.offsetY / map.scrollHeight) * 2 + 1;
console.log()
mouse.x = ((event.clientX - map.getBoundingClientRect().left) / map.offsetWidth) * 2 - 1
mouse.y = -((event.clientY - map.getBoundingClientRect().top) / map.offsetHeight) * 2 + 1
console.log(mouse)
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
raycaster.setFromCamera(mouse, CAMERA);
// 获取raycaster直线和所有模型相交的数组集合
let intersects = raycaster.intersectObjects(SCENE.children);
console.log(intersects);
if (intersects.length > 0) {// 判断参数[boxMesh]中模型对象是否与射线相交
console.log("选中的对象", intersects[0])
console.log("射线投射器返回的对象 点point", intersects[0].point);
console.log('相机的位置', CAMERA.position)
}
}
Three.js使用OrbitControls后修改相机旋转方向无效
设置透明无效
RENDERER = new THREE.WebGLRenderer({
antialias: true, //抗锯齿
precision:'highp'
});
RENDERER.sortObjects = false, 就是这个导致的
选点工具
https://l7editor.antv.antgroup.com/