Three.js实战项目 烘培-云上城市

  • 概述
  • 创建场景
  • 创建天空
  • 创建水面
  • 创建模型
  • 开启模型动画
  • 栅栏动画

概述

如有不明白的可以加QQ:2781128388
源码获取: https://mbd.pub/o/bread/Y5uck5hq

开发了一个Three.js 使用烘培模型的demo,先看视频效果,整体的效果有水面,太阳,倒影,模型动画,围栏特效,相机动画

three.js 云上城市

创建场景

创建渲染器,灯光,相机,控制器和以前的智慧城市项目一样,从那边照抄过来即可,调用方式如下

     app = new ZThree("screen");app.initThree();// app.initHelper();app.initOrbitControls();light = app.initLight();// stats = app.initStatus();selectObj = app.initRaycaster();window.app = app;camera = app.camera;// bloomComposer = app.bloomComposer();camera.position.set(...this.cameraPosition);scene = app.scene;renderer = app.renderer;renderer.logarithmicDepthBuffer = true;renderer.autoClear = false;controls = app.controls;controls.target.set(...this.target);controls.maxDistance = 2000;controls.maxPolarAngle = Math.PI / 2.2;clock = new THREE.Clock();

创建天空

export function loaderSky(app, water) {return new Promise(resolve => {let sky = new Sky();sky.scale.setScalar(10000);app.scene.add(sky);let skyUniforms = sky.material.uniforms;skyUniforms['turbidity'].value = 1;skyUniforms['rayleigh'].value = 3;skyUniforms['mieCoefficient'].value = 0.005;skyUniforms['mieDirectionalG'].value = 0.8;let parameters = {inclination: 0.49,azimuth: 0.205};let pmremGenerator = new THREE.PMREMGenerator(app.renderer);let sun = new THREE.Vector3();let theta = Math.PI * (parameters.inclination - 0.5);let phi = 2 * Math.PI * (parameters.azimuth - 0.5);sun.x = Math.cos(phi);sun.y = Math.sin(phi) * Math.sin(theta);sun.z = Math.sin(phi) * Math.cos(theta);sky.material.uniforms['sunPosition'].value.copy(sun);water.material.uniforms['sunDirection'].value.copy(sun).normalize();app.scene.environment = pmremGenerator.fromScene(sky).texture;resolve(sky);})
}

创建水面

创建一个平面然后加上调用水面的材质就好,很简单

export function loaderWater(app) {return new Promise(resolve => {let waterGeometry = new THREE.PlaneGeometry(10000, 10000);let water = new Water(waterGeometry, {textureWidth: 512,textureHeight: 512,waterNormals: new THREE.TextureLoader().load('texture/waternormals.jpg', function (texture) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;}),alpha: 1.0,sunDirection: new THREE.Vector3(),sunColor: 0xffffff,waterColor: 0x001e0f,distortionScale: 3.7,fog: app.scene.fog !== undefined});water.rotation.x = -Math.PI / 2;app.scene.add(water);resolve(water);})
}

此时我们看到的效果是

创建模型

export async function loaderShop(app) {return new Promise(async resolve => {let gltf = await app.loaderGltfDracoModel('model/', 'yun.glb');let model = gltf.scene;model.getObjectByName('cloud').visible = false;const s = 0.1;model.scale.set(s, s, s);model.position.set(0, -80, 0);let allModel = [];let mixer = new THREE.AnimationMixer( model );mixer.clipAction( gltf.animations[ 0 ] ).play();let clickTextObj = [model.getObjectByName('全息店铺标签'), model.getObjectByName('全息城市标签'), model.getObjectByName('云展标签')];// loaderRipple();app.scene.add(model);resolve({model,allModel,clickTextObj,mixer});})
}

开启模型动画

loaderModel.js 文件代码:

let mixer = new THREE.AnimationMixer( model );
mixer.clipAction( gltf.animations[ 0 ] ).play();

渲染模块代码:

const delta = clock.getDelta();
if (model.mixer) {model.mixer.update( delta );}

此时我们就可以看到模型的动画了。

栅栏动画

生成栅栏的mesh

let ripple;
export function loaderRipple(pos) {if (ripple) {app.scene.remove(ripple);ripple.geometry.dispose();ripple.material.dispose();ripple = null;}let vector3s = [];for (let i = 0; i < pos.length; i++) {vector3s.push(new THREE.Vector3(...pos[i]));}// 围栏let rippleGeometry = getRippleGeometry(vector3s, 60);let rippleMaterial = new THREE.ShaderMaterial({vertexShader: rippleShader.vs,fragmentShader: rippleShader.fs,uniforms: rippleShader.uniform,side: THREE.DoubleSide,transparent: true,depthWrite: false})ripple = new THREE.Mesh(rippleGeometry, rippleMaterial);app.scene.add(ripple);
}

生成栅栏的geometry

function getRippleGeometry(points = [], height = 10) {let positions = []let uvs = []for (let i = 0, j = positions.length, t = uvs.length; i < points.length - 1; i++) {let vUvyMax = 1let left = points[i]let right = points[i + 1]positions[j++] = left.xpositions[j++] = 0positions[j++] = left.yuvs[t++] = 0uvs[t++] = 0positions[j++] = right.xpositions[j++] = 0positions[j++] = right.yuvs[t++] = 1uvs[t++] = 0positions[j++] = left.xpositions[j++] = heightpositions[j++] = left.yuvs[t++] = 0uvs[t++] = vUvyMaxpositions[j++] = left.xpositions[j++] = heightpositions[j++] = left.yuvs[t++] = 0uvs[t++] = vUvyMaxpositions[j++] = right.xpositions[j++] = 0positions[j++] = right.yuvs[t++] = 1uvs[t++] = 0positions[j++] = right.xpositions[j++] = heightpositions[j++] = right.yuvs[t++] = 1uvs[t++] = vUvyMax}let geometry = new THREE.BufferGeometry()geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3))geometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2))return geometry;
}

使用的shader:

export const rippleShader = {vs:"\n  precision lowp float;\n  precision lowp int;\n  ".concat(THREE.ShaderChunk.fog_pars_vertex, "\n  varying vec2 vUv;\n  void main() {\n    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n    vUv = uv;\n    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n    ").concat(THREE.ShaderChunk.fog_vertex, "\n  }\n"),fs: "\n  precision lowp float;\n  precision lowp int;\n  uniform float time;\n  uniform float opacity;\n  uniform vec3 color;\n  uniform float num;\n  uniform float hiz;\n\n  varying vec2 vUv;\n\n  void main() {\n    vec4 fragColor = vec4(0.);\n    float sin = sin((vUv.y - time * hiz) * 10. * num);\n    float high = 0.92;\n    float medium = 0.4;\n    if (sin > high) {\n      fragColor = vec4(mix(vec3(.8, 1., 1.), color, (1. - sin) / (1. - high)), 1.);\n    } else if(sin > medium) {\n      fragColor = vec4(color, mix(1., 0., 1.-(sin - medium) / (high - medium)));\n    } else {\n      fragColor = vec4(color, 0.);\n    }\n\n    vec3 fade = mix(color, vec3(0., 0., 0.), vUv.y);\n    fragColor = mix(fragColor, vec4(fade, 1.), 0.85);\n    gl_FragColor = vec4(fragColor.rgb, fragColor.a * opacity * (1. - vUv.y));\n  }\n",uniform:{time: {type: "pv2",value: 0},color: {type: "uvs",value: new THREE.Color('#1E90FF')},opacity: {type: "pv2",value: 0.8},num: {type: "pv2",value: 8},hiz: {type: "pv2",value: 0.15}}
}

此时在调用相机的飞行函数,此函数在智慧城市项目中也有详细介绍,在调用相机的飞行函数后执行生成栅栏的函数即可

app.initRaycaster('click', (selectObj) => {if (selectObj) {console.log(selectObj);// return;let object = selectObj.object;app.flyTo({position: textPos[object.name].position})loaderRipple(textPos[object.name].rippleVec)}}, model.clickTextObj);

最后我们就可以看到,在点击了店铺标签后生成一个个栅栏了

Three.js实战项目 烘培-云上城市相关推荐

  1. Three.js实战项目 商场漫游

    Three.js实战项目 商场漫游 概述 创建场景 创建天空 创建水面 创建模型 室内漫游 概述 如有不明白的可以加QQ:2781128388 源码获取: https://mbd.pub/o/brea ...

  2. Three.js实战项目-智慧楼宇

    Three.js实战项目-智慧楼宇 概述 初始化场景 加载建筑数据和道路数据 扩散波 概述 如有不明白的可以加QQ:2781128388 源码获取:https://mbd.pub/o/bread/Y5 ...

  3. 2018最新vue.js实战项目:美团外卖平台

    vue.js实战项目:美团外卖平台 第1章 课程简介 1-1 课程简介 1-2 课程安排 第2章 Vue.js介绍 2-1 Vuejs介绍-近年来前端开发趋势 2-2 Vuejs介绍-MVVM框架 2 ...

  4. 美团外卖平台vue.js实战项目(完整)

    vue.js实战项目:美团外卖平台 第1章 课程简介 1-1 课程简介 1-2 课程安排 第2章 Vue.js介绍 2-1 Vuejs介绍-近年来前端开发趋势 2-2 Vuejs介绍-MVVM框架 2 ...

  5. 把项目放到码云上,通过git 进行项目管理

    1.在码云上新建一个项目 把使用 Readme文件初始化这个项目这个勾选去掉  项目生成后会看到 码云的git 简易的命令行入门教程: Git 全局设置: git config --global us ...

  6. php中的项目在华为云上显示,php 显示

    可以直接在PuTTY内输入命令. 请输入MySQL或PHP等软件安装命令,此处以安装PHP为例: yum install -y httpd php php-fpm php-server php-mys ...

  7. Vue3+node.js网易云音乐实战项目(三)

    页面 一.头部导航栏布局 二.轮播图的实现 三.请求网易的banner图 四 链接 一.头部导航栏布局 首先我们看最上面这里的布局,大致可分为三个模块,顶部左边,顶部中间,顶部右边 那么我们在comp ...

  8. Vue3+node.js网易云音乐实战项目(五)

    推荐歌单详细页面顶部 1.推荐歌单详细页面 1.1.导航条和背景 1.2.头像和简介 1.3.头部完整代码 1.4.链接 实现效果 1.推荐歌单详细页面 1.1.导航条和背景 推荐歌单页面做好后,我们 ...

  9. 【IDEA】IDEA中使用git将项目上传到码云上

    前言 该篇文章记录了使用IDEA上传项目到码云上. 前提是你在 IDEA中集成了git ,并且会 git的简单使用 . 一.IDEA上传项目到码云上 1.将项目变成Git能管理的仓库 选中菜单栏 VC ...

最新文章

  1. R语言生存分析模型简介及survival包实现实战:基于survival包lung数据集
  2. Cloudify — 系统架构
  3. 皮一皮:这是为什么呢???
  4. python语言有什么用-python语言的优势是什么
  5. 聊聊这两年我用到的面试套路和收获
  6. Job for network.service failed because the control process exited with error code问题
  7. 什么是Django?
  8. java webengine_如何以Java实现网页截图技术
  9. P1423 小玉在游泳(python3实现)
  10. 解决远程服务器ssh登陆慢等问题
  11. Redis学习笔记~关于空间换时间的查询案例
  12. 《C++ Primer Plus(第6版)中文版》——1.2 C++简史
  13. UG NX 12 重复命令
  14. sql数据库置疑解决办法
  15. 耳穴减肥自身感受细节描述0422
  16. 元宇宙掀起新浪潮,觅伊打造沉浸式社交场景
  17. 【Git】Git入门
  18. (五)DDR协议命令波形时序二——(Precharge、Refresh、Self Refresh、Power Down)
  19. 特征工程-什么是特征工程(Kaggle微课)
  20. 探究APP换肤机制的设计与实现

热门文章

  1. Kindle Fire平板电脑为什么是7英寸?
  2. 遗传算法在走迷宫游戏中的应用
  3. Vue中Html2canvas生成网页局部截图
  4. 我的世界服务器显示Could,我的世界服务器启动怎么没有反应
  5. Sunnyvale诊所使用RTLS系统,大幅提升患者满意度
  6. python超详细零基础 bs4解析之爬取唯美图片
  7. 如何把游戏屏幕改成计算机,如何通过双显示设置全屏游戏在哪个屏幕上
  8. Web自动化处理“滑动验证码”
  9. 是什么技术激活了在线教育“直播+”战略
  10. CString——Left、Right、Find、ReverseFind