Three.js湖边小屋,包含gltf渲染、天空和水纹、光照阴影、运动的点光源、相机位置和文字切屏、粒子效果等

news2024/11/25 7:36:31

前期准备

使用vue3+vite+three.js+gsap 开发

npm install three gsap

代码

<script setup>
// 导入three.js
import * as THREE from 'three';
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// 加载模型
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
// 解压缩库
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
// 引入官方水效果
import { Water } from 'three/examples/jsm/objects/Water2.js';
// 导入补间动画库
import gsap from 'gsap';
import { ref, onMounted } from 'vue';
// 创建场景
const scene = new THREE.Scene();
// 初始化相机
const camera = new THREE.PerspectiveCamera(
    45, // 视角
    window.innerWidth / window.innerHeight, // 宽高比
    0.1, // 近平面
    1000 // 远平面
);
camera.position.set(-3.23,2.98,4.06);
camera.updateProjectionMatrix();
// 初始化渲染器
const renderer = new THREE.WebGLRenderer(
  //设置抗锯齿
  { antialias: true } 
);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 设置色调映射
renderer.outputEncoding = THREE.sRGBEncoding
renderer.toneMapping = THREE.ACESFilmicToneMapping
renderer.toneMappingExposure = 0.5
renderer.shadowMap.enabled = true
// 调节亮度
renderer.toneMappingExposure = 1

// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// 初始化loader
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
// 初始化gltfLoader
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
// 加载环境纹理
let rgbeLoader = new RGBELoader()
rgbeLoader.load('./textures/sky.hdr',(texture)=>{
  texture.mapping = THREE.EquiretangularReflectiionMapping;
  scene.background = texture
  scene.environment = texture
})
gltfLoader.load("./model/scene.glb",(gltf)=>{
  const model = gltf.scene;
  model.traverse((child)=>{
    if(child.name = "Plane"){
     child.visible = false
    }
    if(child.isMesh){
      child.castShadow = true
      child.receiveShadow = true
    }
  })
  scene.add(model)
})

// 添加水效果
const waterGeometry = new THREE.CircleGemoetry(300,32)
const water = new Water(
  waterGeometry,
  {
    // 数值越大效果越明显
    textureWidth: 2048,
    textureHeight: 2048,
    color:0xeeeeff,
    flowDirection: new THREE.Vector2(1,1),
    scale:2,
  }
)
// 设置水的旋转,否则导致房子浸泡在水中
water.rotation.x = -Math.PI / 2
// 设置水的位置
water.position.y = -1
scene.add(water)

// 加载模型
gltfLoader.load(
  'models/scene.gltf',
  (gltf) => {
    scene.add(gltf.scene);
    // 设置模型位置
    gltf.scene.position.set(0,0,0);
    // 设置模型大小
    gltf.scene.scale.set(0.01,0.01,0.01);
    // 设置模型旋转
    gltf.scene.rotation.set(0,0,0);
  },
  (xhr) => {
    console.log((xhr.loaded / xhr.total * 100) + '% loaded');
  },
  (error) => {
    console.log('error!', error);
  }
);

// 添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 50, 0);
scene.add(light);
// 添加点光源
const pointLight = new THREE.PointLight(0xffffff, 100);
pointLight.position.set(0.1,2.4, 0);
pointLight.castShadow = true;
scene.add(pointLight);
// 创建点光源组
const pointLightGroup = new THREE.Group();
pointLightGroup.position.set(-8,2.5,-1.5);
// 球绕圆的半径
let radius = 3;
let pointLightArr = [];
for(let i = 0; i < 3; i++){
  // 创建点光源
  const sphereGeometry = new THREE.SphereGeometry(0.1, 32, 32);
  const sphereMaterial = new THREE.MeshStandardMaterial({
    color: 0xffffff,
    emissive: 0xffffff,
    emissiveIntensity: 10,
    roughness: 0.5,
    metalness: 0.5
  })
  const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
  sphere.position.set(radius * Math.cos(i * 120 * Math.PI / 180), Math.cos((i * 120 * Math.PI) / 180), radius * Math.sin(i * 120 * Math.PI / 180));

  // 添加到点光源组
  pointLightGroup.add(sphere);

  const pointLight = new THREE.PointLight(0xffffff, 1);
  sphere.add(pointLight);
    // 将点光源添加到点光源组
  pointLightGroup.add(sphere);
}
scene.add(pointLightGroup);
function render(){
  requestAnimationFrame(render);
  renderer.render(scene, camera);
  controls.update();
}

// 使用补间动画,从0到2pi,使灯泡旋转
let options = {
  angle:0
}
gsap.to(options,{
  angle:Math.PI * 2,
  duration:10,
  repeat:-1,
  ease:"linear",
  onUpdate:()=>{
    pointLightGroup.rotation.y = options.angle
    pointLightArr.forEach((item,index)=>{
      item.position.set(radius * Math.cos((index * 120) * Math.PI / 180), Math.cos(((index * 120) * Math.PI) / 180), radius * Math.sin((index * 120) * Math.PI / 180));
    })
  }
})
render();

// 使用补间动画,移动相机
let timeLine1 = gsap.timeline();
let timeline2 = gsap.timeline();

// 定义相机移动函数
function translateCamera(position,target){
  timeLine1.to(camera.position,{
    x:position.x,
    y:position.y,
    z:position.z,
    duration:2,
    ease:"power2.inOut"
  })

  timeline2.to(camera.position,{
    x:target.x,
    y:target.y,
    z:target.z,
    duration:2,
    ease:"power2.inOut"
  })
}

let words = [
  {
    text:"Attendre et espérer !",
    callback:()=>{
      new THREE.Vector3(-3.23,2.98,4.06),
      new THREE.Vector3(-8, 2, 0)
    },
  },
  {
    text:"Attendre et espérer !!",
    callback:()=>{
      new THREE.Vector3(7,0,23),
      new THREE.Vector3(0,0,0)
    },
  },
  {
    text:"Attendre et espérer !!!",
    callback:()=>{
      new THREE.Vector3(10,3,0),
      new THREE.Vector3(5,2,0)
    },
  },
  {
    text:"Attendre et espérer !!!!",
    callback:()=>{
      new THREE.Vector3(7,0,23),
      new THREE.Vector3(0,0,0)
    },
  },
  {
    text:"Attendre et espérer !!!!!",
    callback:()=>{
      new THREE.Vector3(-20,1.3,6.6),
      new THREE.Vector3(5,2,0)
      // 调用画爱心函数
      makeHeart()
    },
  },
]

let index = ref(0)
let isAnimate = false
// 监听鼠标滚轮事件
window.addEventListener('wheel',(e)=>{
  // 操作节流
  if(isAnimate){
    return
  }
  if(e.deltaY > 0){
    index.value++
    if(index.value > words.length - 1){
      index.value = 0
    }
  }
  words[index.value].callback()
  setTimeout(() => {
    isAnimate = false
  }, 1000);
})

// 实例化星星
let starsInstance = new THREE.InstanceMesh(
  new THREE.SphereGeometry(0.1,32,32),
  new THREE.MeshStandardMaterial({
    color:0xffffff,
    emissive:0xffffff,
    emissiveIntensity:10,
    roughness:0.5,
    metalness:0.5
  }),
  100
);

// 随机分布星星
let starsArr = []
let endArr = []
for(let i = 0; i < 100; i++){
  let x = Math.random() * 100 - 50
  let y = Math.random() * 100 - 50
  let z = Math.random() * 100 - 50
  starsArr.push(new THREE.Vector3(x,y,z))
  // 矩阵修改位移
  let matrix = new THREE.Matrix4()
  matrix.setPosition(x,y,z)
  starsInstance.setMatrixAt(i,matrix)
}
scene.add(starsInstance)

// 使用贝塞尔曲线,实现星星移动
let heartShape = new THREE.Shape()
heartShape.moveTo(25,25)
heartShape.bezierCurveTo(25,25,20,0,0,0)
heartShape.bezierCurveTo(-30,0,-30,35,-30,35)
heartShape.bezierCurveTo(-30,55,-10,77,25,95)
heartShape.bezierCurveTo(60,77,80,55,80,35)
heartShape.bezierCurveTo(80,35,80,0,50,0)
heartShape.bezierCurveTo(35,0,25,25,25,25)

//根据路径获取点
for(let i = 0; i < 100; i++){
  let point = heartShape.getPointAt(i / 100)
  endArr.push(new THREE.Vector3(point.x,point.y,point.z))
}

// 创建动画
function makeHeart(){
  let params = {
    time:0
  }

  gsap.to(params,{
    time:1,
    duration:10,
    ease:"linear",
    onUpdate:()=>{
      for(let i = 0; i < 100; i++){
        let x = THREE.MathUtils.lerp(starsArr[i].x,endArr[i].x,params.time)
        let y = THREE.MathUtils.lerp(starsArr[i].y,endArr[i].y,params.time)
        let z = THREE.MathUtils.lerp(starsArr[i].z,endArr[i].z,params.time)
        let matrix = new THREE.Matrix4()
        matrix.setPosition(x,y,z)
        starsInstance.setMatrixAt(i,matrix)
      }
      starsInstance.instanceMatrix.needsUpdate = true
    }
  })
}
</script>
<template>
<div class="words" style="position:fixed;left: 0;top:0;z-index:10;pointer-events: none;transition: all 1s;" :style="{
    transform:`translate(${index.value * -100}vw,0)`
  }"> 
  <div v-for="item in words" style="width: 100vw;height: 100vh;">
    <h1 style="padding: 100px 50px;font-size:50px;color:#fff">{{item.text}}</h1>
  </div>
</div>
</template>
<style scoped>
*{
  margin:0;
  padding:0;
}
canvas{
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
}
</style>

效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2083192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQLserver中的游标的分类和游标的生命周期

SQLserver中的游标的分类 在 SQL Server 中&#xff0c;游标&#xff08;Cursor&#xff09;是一种数据库对象&#xff0c;用于逐行处理结果集中的数据。游标可以用于复杂的数据处理任务&#xff0c;尤其是那些不能通过简单的 SELECT 语句和 JOIN 操作完成的任务。SQL Server …

网络通信---三次握手

文章目录 概述第一次握手第二次握手第三次握手整体看下 小结 概述 “三次握手”&#xff08;Three-way Handshake&#xff09;是TCP/IP协议中建立一个可靠的连接时使用的一种机制。这个过程确保了两个网络实体&#xff08;通常是两台计算机&#xff09;在开始数据传输之前能够…

std::futrue异步操作结果的三种搭配使用

目录 一、std::future 应用场景 二、使用 std::async关联异步任务 三、使用std::packaged_task和std::future配合 四、std::promise和std::future配合 一、std::future std::future是C11标准库中的⼀个模板类&#xff0c;它表⽰⼀个异步操作的结果。当我们在多线程编程中使…

VBA技术资料MF194:屏蔽右键菜单

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

云计算概述

云计算的产生以及发展 分布式计算&#xff1a;包含了云计算和网格计算 云计算&#xff1a;以数据为中心进行的计算 网格计算&#xff1a;以计算为中心进行的计算 诞生-1999 初期的发展-2007-2008 加速发展-2009-2014 日渐成熟阶段-2015-目前 云计算的种类 公有云-第三方提供…

第74集《大佛顶首楞严经》

请大家打开讲义第一百六十三页。我们讲到丑一&#xff0c;圆破色阴超劫浊。 在整个五阴的对治当中&#xff0c;第一个所要对治的&#xff0c;最粗重的就是色阴&#xff1b;色阴所引生的根结&#xff0c;就是动静两种的结相。当我们开始在闻的功能当中&#xff0c;不再攀缘外在…

@ohos.systemParameterEnhance系统参数接口调用:控制设备硬件(执行shell命令方式)

本文介绍如何使用应用ohos.systemParameterEnhance (系统参数)(系统接口)来控制设备硬件&#xff0c;可以通过它在系统中执行一段shell命令&#xff0c;从而实现控制设备的效果。接下来以一个实际的样例来演示如何通过它来控制设备以太网接口 开源地址&#xff1a;https://git…

售后更新出现问题分析-幂等和防重

2024-08-27 早上测试提交BUG,说售后单状态流转不对&#xff0c;吓得我一激灵&#xff0c;赶紧打开IDEA 查看代码&#xff0c;发现售后这块代码没有动过呀&#xff0c;咋回事&#xff1f; 流程是这样的&#xff1a; 测试模拟用户下单&#xff0c;提交订单后付款&#xff0c;然后…

[MOCO v2] Improved Baselines with Momentum Contrastive Learning

1、目的 结合SimCLR和MoCo&#xff0c;实现SoTA 2、方法 ​​​​​​​ ​​​​​​​ 将SimCLR的两点设计融入MoCo中&#xff1a; 1&#xff09;MLP projection head 2-layer, hidden layer 2048-d, with ReLU 2&#xff09;more data augmentation blur a…

【专项刷题】— 链表

1、2两数相加 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 只要有任意一个链表还没有为空的时候就继续加&#xff0c;当链表为空的时候但是t不尾0&#xff0c;还是进入循环进行操作 代码&#xff1a; public ListNode addTwoNumbers(ListNode l1, ListNode l2) {…

【HuggingFace Transformers】LlamaModel源码解析

LlamaModel源码解析 1. LlamaModel 介绍2. LlamaModel类 源码解析3. 4维因果注意力掩码生成 1. LlamaModel 介绍 LlamaModel 是一个基于 Transformer 架构的解码器模型&#xff0c;用于自然语言处理任务。它是 Meta 的 LLaMA (Large Language Model Meta AI) 系列的一部分&…

Spatial Structure Constraints for Weakly SupervisedSemantic Segmentation

摘要 由于易于获得&#xff0c;图像级标签在弱监督语义分割任务中很受欢迎。 由于图像级标签只能指示特定类别对象的存在或不存在&#xff0c;因此基于可视化的技术已被广泛采用来提供对象位置线索。由于类激活图(class activation map, CAMs)只能定位目标中最具辨识性的部分…

API测试基础知识(基本概念、测试方法、测试工具)

在进行API测试之前&#xff0c;我们先了解一下 什么是API&#xff1f; API&#xff08;全称Application Programming Interface&#xff09;是两个单独的软件系统之间的通信和数据交换。实现API的软件系统包含可以由另一个软件系统执行的功能/子例程。 什么是API测试 API测…

ATL宁德新能源25届校招社招:Verify测评及四色测评考什么?真题分析

ATL新能源科技有限公司-Verify测评邀请题型介绍 a. 测评内容包含演绎推理数字推理两部分&#xff0c;大约用时45分钟左右&#xff1b; b. 正式测评后即开始计时&#xff0c;每项测评时限为18分钟。 c. 为确保测评顺利进行&#xff0c;不影响测评结果&#xff0c;请优先使用电…

分享5个专业写论文神器自动生成的软件工具

在当今学术研究和写作领域&#xff0c;AI论文写作工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。以下是五款专业写论文神器自动生成的软件工具&#xff0c;其中特别推荐千笔-AIPasspap…

入职后,我发现工作内容和自己想象中的不太一致。。

2018年6月&#xff0c;大三暑假进行时&#xff0c;实习第二天上班 昨天王工跟我说最好统一开发工具用eclipse&#xff0c;今早我瞄到其实也有同事用idea。 eclipse还得学习&#xff0c;用idea算了&#xff0c;随便上网找个盗版的就好咯&#xff0c;不纠结这么多。 公司被逮到…

驱动:dht11驱动程序

DHT11读写时序详解&#xff08;时序上板实测&#xff09;_mcu 读取thd11 接收数据开始-CSDN博客文章浏览阅读733次&#xff0c;点赞20次&#xff0c;收藏21次。DHT11有两种&#xff0c;一种三线制&#xff0c;一种四线制。其中都包括1个VDD&#xff0c;1个GND&#xff0c;和1个…

常见几种简单的深度学习算法在生物医学数据领域的特点和不足

本团队提供生物医学领域专业的AI&#xff08;机器学习、深度学习&#xff09;技术支持服务。如果您有需求&#xff0c;请扫描文末二维码关注我们。 通过表格的形式&#xff0c;总结了常见几种简单的深度学习算法在生物医学数据领域的特点和不足&#xff08;仅个人理解&#xff…

HarmonyOS NEXT 实战开发:实现日常提醒应用

为什么要开发这个日常提醒应用&#xff1f; 最近鸿蒙热度一直不减&#xff0c;而且前端的就业环境越来越差&#xff0c;所以心里面萌生了换一个赛道的想法。HarmonyOS NEXT 是华为打造的国产之光&#xff0c;而且是纯血版不再是套壳&#xff0c;更加激起了我的好奇心。ArkTS是…

【网络安全】分析cookie实现PII IDOR

未经许可,不得转载。 文章目录 正文正文 目标:公共电子商务类型的网站,每月有大约6万到10万访问者,注册用户大约有5万。 存在一个查询个人资料的端点/GetProfiledetails,以下是完整的请求和响应: 我发现,cookie非常类似于base64编码后的结果,于是我将其进行base64解码…