前言
上一节实现了颜色渐变效果和扩散扫光效果,这一节来添加背景天空盒、扩散墙、扩散圆。
添加天空盒思路
three
添加天空盒有两种格式,一种是需要上下左右前后六张图来组成天空盒,一种是创建一个足够大的球,把这个球表面贴上一张图 场景在球里面组成天空球。
- 六张图:这种方式是通关
three
的THREE.CubeTextureLoader().load
方法,吧六张图地址数据添加到该对象里面去然后把场景的背景设置为这个对象。原理图如下所示 - 一张图:因为
three
没有加载hdr
天空盒的方式,可以模仿加载六张图的方式,因为加载六张图相当于创建了一个正方体,每个面贴了一张图片材质,相机在正方体内形成天空盒。那么hdr
单张图就可以通过创建一个球体,球体表面贴图,相机在球体里面来实现(这种方式是我同事提出来的脑洞😂)。 这里推荐一个网址可以下载HDR材质(这个材质既可以当天空盒来用,也可以当环境贴图来用)polyhaven.com/hdris 。
天空盒实现
我这里天空盒实现选的是第一种方式(因为数据是六张图的),代码如下
const textureCube = new THREE.CubeTextureLoader().load(['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg', '6.jpg'],);
scene.background = textureCube; // 作为背景贴图
数据如下
效果
通过THREE.RingGeometry
创建一个圆,然后给这个圆添加想要实现效果的贴图,然后再render循环里面每一帧都改变这个圆的大小。
扩散圆实现
通过创建THREE.TextureLoader()
来进行读取图片纹理数据其中this.img
为图片地址,创建THREE.RingGeometry
模型,把读出来的纹理赋给THREE.MeshBasicMaterial
材质,然后再render
循环里面改变这个模型的缩放比例来进行扩散效果模拟。 代码如下
/* eslint-disable */
import * as THREE from 'three';
/**
* 波纹散射图层
* @param options.img 照片地址
* @param options.speed 流动速度
* @param options.scene three场景
* @param options.radius 圆的半径
* @param options.thing 圆的位置
* @param options.meshrings 存储圆形数据
* @example
*/
class RunRing {
constructor(option) {
this.img = option.img || '';
this.speed = option.speed / 100 || 0.01;
this.scene = option.scene;
this.radius = option.radius || 100;
this.position = option.position || [0, 0, 0];
this.meshrings = [];
this.CreatRing();
}
CreatRing() {
//创建对象读取照片纹理
const textureLoader = new THREE.TextureLoader();
textureLoader.load(this.img, (texture) => {
//创建圆圈结构
const geometry = new THREE.RingGeometry(0, this.radius, 500);
//创建材质 把读取到的图片赋给材质
const material2 = new THREE.MeshBasicMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
depthTest: true,
blending: THREE.AdditiveBlending,
map: texture,
});
//传入的多点的话生成多个模型
for (let i = 0; i < this.position.length; i += 1) {
//组合生成模型
this.meshring = new THREE.Mesh(geometry, material2);
//设置模型的X轴偏移量,让模型平铺再X面上
this.meshring.rotateX(Math.PI / 2);
//设置初始状态模型缩放比例
this.meshring.scale.set(0.1, 0.1, 0.1);
//设置模型位置
this.meshring.position.set(this.position[i][0], this.position[i][1], this.position[i][2]);
//储存模型对象,用于render改变属性和销毁对象
this.meshrings.push(this.meshring)
//添加到场景里面
this.scene.add(this.meshrings[i]);
}
});
//创建render,每一帧进行模型改变
this.thing = setInterval(() => {
//循环所有创建的模型,进行改变
for (let i = 0; i < this.position.length; i += 1) {
//如果模型已经创建
if (this.meshrings[i]) {
//当模型缩放比例小于1的时候,模型进行放大
if (this.meshrings[i].scale.x < 1) {
this.meshrings[i].scale.set(
this.meshrings[i].scale.x + 0.01,
this.meshrings[i].scale.x + 0.01,
this.meshrings[i].scale.x + 0.01,
);
} else {
//当模型比例大于1的时候,模型重置
this.meshrings[i].scale.set(0.1, 0.1, 0.1);
}
}
}
}, 50);
}
delete() {
//删除scene中对应的模型
for (let i = 0; i < this.position.length; i += 1) {
if (this.meshrings[i]) {
this.scene.remove(this.meshrings[i]);
}
}
if (this.thing) {
//清除render事件
clearInterval(this.thing);
}
}
}
export default RunRing;
数据格式
{
img: "clice.png",
scene: scene,
speed: 1,
radius: 400,
position: [
[400, 30, 400],
[100, 30, 1200],
],
}
效果图
扩散墙实现思路
扩散墙和上一节一样 是通过ShaderMaterial
来实现的,要实现的效果是墙面随着高度增加透明度也增加,所以模型点位的透明度和高度呈反比。模型的扩散效果是把模型点位的位置通过mod函数来进行取余运算(%),把计算结果限制再0-1之间。
扩散墙实现
/* eslint-disable */
import * as THREE from "three";
/**
* 波动墙
* @param options.scene three场景
* @param options.radius 中心
* @param options.height 墙高度
* @param options.opacity 墙透明度
* @param options.color 墙颜色
* @example
*/
class Wall {
constructor(option) {
this.scene = option.scene;
this.radius = option.radius || 420;
this.height = option.height || 120;
this.opacity = option.opacity || 0.5;
this.color = option.color || "#efad35";
this.speed = option.speed || 0.5;
this.mesh = ""; //生成的模型数据
this.CreatRing();
}
CreatRing() {
const vertexShader = `
uniform vec3 u_color;
uniform float time;
uniform float u_height;
varying float v_opacity;
void main() {
//模型点位置乘以一个0.0-1.0的系数,来模拟扩散效果。
vec3 vPosition = position * mod(time/20.0, 1.0);
//模型的透明度和模型的高度呈反比
v_opacity =1.0- position.y / u_height;
gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1.0);
}
`;
const fragmentShader = `
uniform vec3 u_color;
uniform float u_opacity;
varying float v_opacity;
void main() {
//u_color是颜色 v_opacity * u_opacity是高度所产生的透明效果和模型传入的透明度的乘积。
gl_FragColor = vec4(u_color, v_opacity * u_opacity);
}
`;
//获取参数
const { radius, height, opacity, color, speed, renderOrder } = this;
//生成模型结构
const geometry = new THREE.CylinderGeometry(
radius,
radius,
height,
32,
1,
true
);
//模型位置设置
geometry.translate(0, height / 2, 0);
//自定义模型材质
const material = new THREE.ShaderMaterial({
uniforms: {
u_height: {
value: height,
},
u_opacity: {
value: opacity,
},
u_color: {
value: new THREE.Color(color),
},
time: {
value: 0,
},
},
transparent: true,
depthWrite: false,
depthTest: false,
side: THREE.DoubleSide,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
});
//组合材质和结构生成对象
const mesh = new THREE.Mesh(geometry, material);
//设置模型遮挡,把这个模型放到最前面防止遮挡
mesh.renderOrder = renderOrder || 1;
this.mesh = mesh;
}
}
export default Wall;
效果图
完整项目源码获取:关注公众号「码农园区」,回复 【智慧城市】,即可获取完整项目源
附送250套精选项目源码
源码截图
源码获取:关注公众号「码农园区」,回复 【源码】,即可获取全套源码下载链接