本文主要是介绍threejs视频教程学习(5):水天一色小岛,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
内容来源:老陈threejs入门教程
陈老师讲的还是很不错的,贴图材料可以加视频里的qq群,或者用我下载的这个(微云):https://share.weiyun.com/6uA7pnYc
基础内容
<template><div class="container" id="container"></div>
</template><script setup lang="ts">
// 引入threejs
import * as THREE from 'three';
// 导入轨道控制器,模块化开发导入的是jsm不是js
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { onMounted } from 'vue';onMounted(() => {// 创建场景const scene = new THREE.Scene();// 创建透视相机,通过相机来观察const camera = new THREE.PerspectiveCamera(75, // 角度window.innerWidth / window.innerHeight, // 长宽比1, // 近端2000 // 远端);// 设置相机的位置camera.position.set(-50, 50, 130);// 设置摄像机视锥体的长宽比camera.aspect = window.innerWidth / window.innerHeight;// 更新摄像头投影矩阵camera.updateProjectionMatrix();// 将相机添加到场景中scene.add(camera);// 初始化渲染器const renderer = new THREE.WebGLRenderer({antialias: true // 抗锯齿});// 设置渲染的尺寸renderer.setSize(window.innerWidth, window.innerHeight);// 设置渲染的输出编码renderer.outputEncoding = THREE.sRGBEncoding;// 将wbgl渲染的canvas内容添加到dom元素中document.getElementById('container')?.appendChild(renderer.domElement);// 使用渲染器,通过相机将场景渲染进来renderer.render(scene, camera);// 监听平面大小的改变,修改相机的比例、渲染器的宽高window.addEventListener('resize', () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);});// 创建轨道控制器const controls = new OrbitControls(camera, renderer.domElement);// 设置控制器阻尼,让物体拥有惯性,必须在动画循环里调用update()controls.enableDamping = true;// 添加坐标辅助器const axesHelper = new THREE.AxesHelper(10);scene.add(axesHelper);// 创建一个渲染函数,当场景发生变化后重新渲染const render = () => {controls.update();renderer.render(scene, camera);// 使用浏览器自带的请求动画帧函数不断的进行渲染requestAnimationFrame(render);};render();/** ******************创建物体的相关逻辑开始**************************** *//** ********************创建物体的相关逻辑结束********************************/
});</script>
天空
天空是通过创建一个大型的球体,然后添加天空贴图来实现的。
// 创建纹理加载器const textureLoader = new THREE.TextureLoader();// 创建天空球const skyGeometry = new THREE.SphereGeometry(1000, 60, 60);const skyTexture = textureLoader.load('../../../../public/textures/sky.jpg'); // 天空纹理const skyMaterial = new THREE.MeshBasicMaterial({map: skyTexture // 颜色贴图});const sky = new THREE.Mesh(skyGeometry, skyMaterial);scene.add(sky);
将球体反转
将球体进行反转,使其球里面是亮的外面是黑的
// 反转球体,主要是反转z轴
skyGeometry.scale(1, 1, -1);
注: 天空贴图有点问题,不是完全的360度,会出现重合的问题
将天空贴图替换为视频纹理
图片中云是静态的,可以通过替换为视频纹理来解决这个问题。
// 添加视频纹理const skyVideo = document.createElement('video');skyVideo.src = '../../../../public/textures/sky.mp4';skyVideo.loop = true; // 设置视频循环播放// 添加鼠标点击事件,当鼠标点击时开始播放视频window.addEventListener('click', () => {if (skyVideo.paused && skyVideo.readyState === 4) {skyVideo.play();// 更新材质skyMaterial.map = new THREE.VideoTexture(skyVideo);skyMaterial.map.needsUpdate = true;}});
水面和小岛
创建水面
// 导入水面
import { Water } from 'three/examples/jsm/objects/Water2';// 创建水面const waterGeometry = new THREE.CircleGeometry(300, 30);const water = new Water(waterGeometry, {// 材质宽高textureWidth: 1024,textureHeight: 1024,// 水面颜色color: 0xeeeeff,// 水面流动的方向flowDirection: new THREE.Vector2(1, 1),// 波纹大小scale: 1});// 水面旋转至水平water.rotation.x = -Math.PI / 2;// 添加水面scene.add(water);
感觉我这个水面乖乖的
添加小岛
// 导入gltf模型加载库
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// 导入模型解压库
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';// 添加小岛const loader = new GLTFLoader();const dracoLoader = new DRACOLoader();// 设置路径dracoLoader.setDecoderPath('../../../../public/draco/');// 设置加载器loader.setDRACOLoader(dracoLoader);loader.load('../../../../public/island2.glb', gltf => {scene.add(gltf.scene);});
场景是黑色的是因为我们没有设置环境纹理,没有环境反射的光,所以看不见场景。另外我们的天空贴图只是普通的图片,是无法反射光的,还需要导入hdr的环境纹理
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';// 导入hdr环境纹理
const hdrLoader = new RGBELoader();
hdrLoader.loadAsync('../../../../public/050.hdr').then((texture) => {// 设置纹理映射texture.mapping = THREE.EquirectangularReflectionMapping;// 设置环境背景和环境纹理scene.background = texture;scene.environment = texture;});
添加平行光
添加平行光,让模型更亮一点。如果只添加平行光不添加环境光也可以看见模型,但是平行光照射不到的地方,模型依然是黑色的,因此环境光还是很重要的。
// 添加平行光const light = new THREE.DirectionalLight(0xffffff, 1);light.position.set(100, 100, 10);scene.add(light);
最终效果
总感觉怪怪的,好像是电脑渲染的问题吧,显得有点呆😳
完整代码
<template><div class="container" id="container"></div>
</template><script setup lang="ts">
import { onMounted } from 'vue';
// 引入threejs
import * as THREE from 'three';
// 导入轨道控制器,模块化开发导入的是jsm不是js
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 导入水面
import { Water } from 'three/examples/jsm/objects/Water2';
// 导入gltf模型加载库
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// 导入模型解压库
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';onMounted(() => {// 创建场景const scene = new THREE.Scene();// 创建透视相机,通过相机来观察const camera = new THREE.PerspectiveCamera(75, // 角度window.innerWidth / window.innerHeight, // 长宽比1, // 近端2000 // 远端);// 设置相机的位置camera.position.set(-50, 50, 130);// 设置摄像机视锥体的长宽比camera.aspect = window.innerWidth / window.innerHeight;// 更新摄像头投影矩阵camera.updateProjectionMatrix();// 将相机添加到场景中scene.add(camera);// 初始化渲染器const renderer = new THREE.WebGLRenderer({antialias: true, // 抗锯齿logarithmicDepthBuffer: true // 对数深度缓冲区});// 设置渲染的尺寸renderer.setSize(window.innerWidth, window.innerHeight);// 设置渲染的输出编码renderer.outputEncoding = THREE.sRGBEncoding;// 将wbgl渲染的canvas内容添加到dom元素中document.getElementById('container')?.appendChild(renderer.domElement);// 使用渲染器,通过相机将场景渲染进来renderer.render(scene, camera);// 监听平面大小的改变,修改相机的比例、渲染器的宽高window.addEventListener('resize', () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);});// 创建轨道控制器const controls = new OrbitControls(camera, renderer.domElement);// 设置控制器阻尼,让物体拥有惯性,必须在动画循环里调用update()controls.enableDamping = true;// 添加坐标辅助器// const axesHelper = new THREE.AxesHelper(100);// scene.add(axesHelper);// 创建一个渲染函数,当场景发生变化后重新渲染const render = () => {controls.update();renderer.render(scene, camera);// 使用浏览器自带的请求动画帧函数不断的进行渲染requestAnimationFrame(render);};render();/** ******************创建物体的相关逻辑开始**************************** */// 创建纹理加载器const textureLoader = new THREE.TextureLoader();// 创建天空球const skyGeometry = new THREE.SphereGeometry(1000, 60, 60);const skyTexture = textureLoader.load('../../../../public/textures/sky.jpg'); // 天空纹理const skyMaterial = new THREE.MeshBasicMaterial({map: skyTexture // 颜色贴图});// 反转球体,主要是反转z轴skyGeometry.scale(1, 1, -1);const sky = new THREE.Mesh(skyGeometry, skyMaterial);scene.add(sky);// 添加视频纹理const skyVideo = document.createElement('video');skyVideo.src = '../../../../public/textures/sky.mp4';skyVideo.loop = true; // 设置视频循环播放// 添加鼠标点击事件,当鼠标点击时开始播放视频window.addEventListener('click', () => {if (skyVideo.paused && skyVideo.readyState === 4) {skyVideo.play();// 更新材质const texture = new THREE.VideoTexture(skyVideo);skyMaterial.map = texture;skyMaterial.map.needsUpdate = true;}});// 导入hdr环境纹理const hdrLoader = new RGBELoader();hdrLoader.loadAsync('../../../../public/050.hdr').then((texture) => {// 设置纹理映射texture.mapping = THREE.EquirectangularReflectionMapping;// 设置环境背景和环境纹理scene.background = texture;scene.environment = texture;});// 添加平行光const light = new THREE.DirectionalLight(0xffffff, 1);light.position.set(100, 100, 10);scene.add(light);// 创建水面const waterGeometry = new THREE.CircleGeometry(300, 30);const water = new Water(waterGeometry, {// 材质宽高textureWidth: 1024,textureHeight: 1024,// 水面颜色color: 0xeeeeff,// 水面流动的方向flowDirection: new THREE.Vector2(1, 1),// 波纹大小scale: 1});// 水面旋转至水平water.rotation.x = -Math.PI / 2;// 调整水面的位置,使水面能够掩盖一部分模型water.position.y = 3;// 添加水面scene.add(water);// 添加小岛const loader = new GLTFLoader();const dracoLoader = new DRACOLoader();// 设置路径dracoLoader.setDecoderPath('../../../../public/draco/');// 设置加载器loader.setDRACOLoader(dracoLoader);loader.load('../../../../public/island2.glb', gltf => {scene.add(gltf.scene);});/** ********************创建物体的相关逻辑结束********************************/
});
</script>
这篇关于threejs视频教程学习(5):水天一色小岛的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!