文章只是个人的一个记录,水天一色小岛制作所需要的几个步骤
先创建三维场景scene,其次创建相机并设置好相机位置,之后创建渲染器,之后添加拖动相机效果
相机参数,第一个值为角度,第二个值为画布宽高比,第三是近端面,第四是远端面。
相机角度越大肯定看到的范围越大,近端面如图,默认值为0.1,通写为1,主要还是看远端面,可以理解为明星做活动拍照签字的后面那个签名墙,照相机肯定是对准签名墙的明星拍照的啊,签名墙后面的画面肯定是看不到的,所以远端面越大,离相机越远,相机看到的东西越多
相机位置为xyz
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 创建一个三维场景scene
const scene = new THREE.Scene();
// 透视相机
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.set(200, 250, 350);
//添加相机到场景中
scene.add(camera)
// 创建渲染器把相机拍出来的物体放在浏览器渲染
// 渲染器的渲染方法,才能在浏览器中看到render()可以生成一个canvas画布,并把三维场景scene呈现在canvas画布上面,可以理解为相机拍照工作“咔
const renderer = new THREE.WebGLRenderer({
// 抗锯齿,普通正方体上面就有锯齿,这个打开就没有了
antialias: true,
// 对数深度缓冲区,因为模型在加载的时候有很多的面所以有可能在转动的时候不知道渲染哪个面,
//所以需要加载渲染着色器,也就是logarithmicDepthBuffer
logarithmicDepthBuffer:true
});
// 设置渲染器的更好的颜色比例,更接近目标颜色
renderer.outputEncoding = THREE.sRGBEncoding;
//设置画布的大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 物体渲染出来了但是要显示在哪呢,如下
// 渲染器WebGLRenderer通过属性.domElement可以获得渲染方法.render()生成的canvas画布,.domElement本质就是一个html元素
// 把渲染结果canvas画布添加到网页body中
document.body.appendChild(renderer.domElement)
const controls = new OrbitControls(camera, renderer.domElement)
// 渲染场景,渲染循环
function render () {
renderer.render(scene, camera); //第一个是场景第二个是相机
//请求动画帧,理想状态每秒60次也就是每次都会操作都会重新更新画布
requestAnimationFrame(render);
}
render()
有相机有场景了,肯定缺少相机拍摄对象啊,添加对象到场景中
添加物体(物体很多啊圆的正的扭曲的这个随便你自己设置),在这里我是添加了球体作为天空的画布
添加物体样式
把物体和样式一起添加到场景中
但是如果添加模型的话,是没有颜色的,因为不支持,需要到时候添加个hdr的图片就行,hdr图片随便,反正显示的天空背景还是这个
let texture=new THREE.TextureLoader().load("./textures/textures/sky.jpg");
// 创建一个巨大的天空球体
// 添加球体,半径1,参数2、3分别代表宽、高度两个方向上的细分数,
const skyGeometry = new THREE.SphereGeometry(1000, 60, 60)
const skyMateral = new THREE.MeshBasicMaterial({
color: 0xffffff,
map:texture
});
skyGeometry.scale(1,1,-1)
const sky =new THREE.Mesh(skyGeometry,skyMateral)
scene.add(sky)
设置动态天空
其实就是设置了个video,在特定时间播放天空视频
// 动态天空
const video=document.createElement("video")
video.src="./textures/textures/sky.mp4"
//视频循环播放
video.loop=true;
window.addEventListener("click",(e)=>{
// 判断视频是否处于播放状态
if(video.pause){
video.play()
let textureVideo=new THREE.VideoTexture(video)
//播放的时候把天空图片替换为视频播放
skyMateral.map= textureVideo
//needsUpdate设为true它会实时的检测贴图是否更新,并更新贴图。
//人话就是因为是视频,需要实时更新显示
skyMateral.map.needsUpdate=true;
}
})
天空有了,开始创建水面
水面需要导入water,还有俩个水波纹图片,不然水面就是平的,没有动态的效果
// 导入水面
import { Water } from "three/examples/jsm/objects/Water2";
//创建纹理加载器
const textureLoad=new THREE.TextureLoader()
// 创建水面,水面范围300和细分数64
const waterGeometry = new THREE.CircleGeometry(300, 64)
const water=new Water(waterGeometry,{
textureHeight:1024,// 水浑浊程度,密度
textureWidth:1024,
color:'#bbbbff',//水面颜色
flowDirection:new THREE.Vector2(1,1),//设置水面向量
scale:1,//缩放值
normalMap0:textureLoad.load("./assets/water/Water_1_M_Normal.jpg"),//添加水波图片
normalMap1:textureLoad.load("./assets/water/Water_2_M_Normal.jpg")
});
water.position.y=5
//水面旋转至水平
water.rotation.x=-Math.PI/2
scene.add(water)
水面天空都有了,加载模型,用到俩个控件GLTFLoader,DRACOLoader
// 导入gltf库,模型库
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// 导入解压库,模型较大解压用
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
// ----解压过程,会自动去寻找依赖包,最后引入压缩模型
// ------但是模型加载完成后是黑色的,需要设置环境映射,普通的图片效果没出来,加载hdr的图片设置映射就能显示颜色了
// 添加小岛模型
const gltfLoader=new GLTFLoader()
// 实例化draco载入库
const dracoLoader = new DRACOLoader();
// 解压的文件路径,该路径就是解压文件所在的位置
dracoLoader.setDecoderPath("./draco/");
// 设置dracoLoader解压gltfLoader
gltfLoader.setDRACOLoader(dracoLoader)
// 加载模型,模型已经出来了
gltfLoader.load("./model/island2.glb", function (gltf) {
// 第一个参数是模型,第二个参数是回调函数
scene.add(gltf.scene)
})
模型加载出来是黑色的,因为没有映射,普通图片不行,需要用到hdr,如果hdr图片找不到你想要的效果,就别删之前代码的天空jpg图片,天空图片会覆盖hdr的图片
// 导入hdr图控件
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
// 载入hdr环境纹理
const hdrLoader=new RGBELoader();
// 异步加载loadAsync,.then回调函数
hdrLoader.loadAsync("./assets/050.hdr").then((texture)=>{
// 设置天空球面的纹理映射,也就是设置了这个小岛模型才能显示出颜色
// 三等距柱状投影反射映射告诉渲染器环境映射采用等距柱状投影格式。由于着色器仅支持非 PBR 的立方体贴图格式和 PBR 材质的立方体 UV 格式,因此必须转换等距柱状投影纹理才能进行渲染。这是由渲染器自动完成的。
texture.mapping=THREE.EquirectangularReflectionMapping;
scene.background=texture;
// 场景环境纹理
scene.environment=texture
})
最后设置下浏览器缩放自适应
window.addEventListener("resize", () => {
// 设置相机宽高比例
camera.aspect = window.innerWidth / window.innerHeight;
// 更新投影矩阵
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight)
})
效果如下
文章到此结束,希望对你有所帮助