Three.js案例分析系列1--webgl_animation_cloth 草坪上漂浮的白布
案例地址 webgl_animation_cloth--草坪上随风漂浮的白布
github源代码:
效果图:
案件描述介绍:
右上角显示帧数,左上角是一个控制盘,控制一些参数
居中是一片草坪,远处的草坪皆有雾化的效果,逐渐模糊不清,草坪中央有一个单杠,挂着一块白布,随风飘摇.
为什么选中这个案例:
首先这个案例是运用了雾化,动画,材质,而且效果看着也很自然,不管是远处的草坪,还是近处随风飘摇的衣服,都很让人感觉很舒服.
再看代码,在html中只有300行不到. 下面先贴出带有我注释的代码,在来给大家讲一讲其中的精华和重点.
<!DOCTYPE html>
<html lang="en"><head><title>three.js webgl - cloth simulation</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><link type="text/css" rel="stylesheet" href="main.css"><style>body {background-color: #cce0ff;color: #000;}a {color: #080;}</style></head><body><div id="info">Simple Cloth Simulation<br/>Verlet integration with relaxed constraints<br/><a onclick="wind = !wind;">Wind</a> |<a onclick="sphere.visible = !sphere.visible;">Ball</a> |<a onclick="togglePins();">Pins</a></div><!-- 引入three.js库 --><script src="../build/three.js"></script><!--引入一个检查浏览器是否支持webgl的辅助工具--><script src="js/WebGL.js"></script><!--引入一个使用鼠标观察物体的库,可动态观察、缩放和平移--><script src="js/controls/OrbitControls.js"></script><!--引入一个javascript性能检测库--><script src="js/libs/stats.min.js"></script><!--引入一个使用松弛约束解算器进行布料模拟的库--><script src="js/Cloth.js"></script><script>/* testing cloth simulation */var pinsFormation = [];var pins = [ 6 ];pinsFormation.push( pins );pins = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];pinsFormation.push( pins );pins = [ 0 ];pinsFormation.push( pins );pins = []; // cut the rope ;)pinsFormation.push( pins );pins = [ 0, cloth.w ]; // classic 2 pinspinsFormation.push( pins );pins = pinsFormation[ 1 ];function togglePins() {pins = pinsFormation[ ~~ ( Math.random() * pinsFormation.length ) ];}if ( WEBGL.isWebGLAvailable() === false ) {document.body.appendChild( WEBGL.getWebGLErrorMessage() );}var container, stats;var camera, scene, renderer;var clothGeometry;var sphere;var object;init();animate();function init() {container = document.createElement( 'div' );document.body.appendChild( container );// scenescene = new THREE.Scene(); // 创建一个场景scene.background = new THREE.Color( 0xcce0ff ); // 设置场景的背景色// 设置场景的雾化距离(第一次参数是雾的颜色,第二个数值表示雾从哪个距离开始显示默认1,第三个表示雾的结束位置默认1000)scene.fog = new THREE.Fog( 0xcce0ff, 500, 10000 );// camera// 构造一个视锥体垂直视野角度为30,视锥体长宽比为window.innerWidth / window.innerHeight,视锥体近端面为1,远端面为10000的透视摄像机camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 10000 );// 设置摄像机的顶点camera.position.set( 1000, 50, 1500 );// lights// 为场景添加一个环境光,均匀地洒在场景上scene.add( new THREE.AmbientLight( 0x666666 ) );// 创建一个平行光线,可以产生投影,第一个参数表示光线的颜色,16进制默认为白色,第二个表示光的强度,默认1var light = new THREE.DirectionalLight( 0xdfebff, 1 );// 设置光线从(50,200,100) 到 (0,0,0) 沿着这条线照射light.position.set( 50, 200, 100 );// 将光线的向量与所传入的标量1.3进行相乘。 具体用途 TODO?light.position.multiplyScalar( 1.3 );//castShadow 如果设置为 true 该平行光会产生动态阴影。 警告: 这样做的代价比较高而且需要一直调整到阴影看起来正确light.castShadow = true;// 设置阴影贴图的宽度和高度light.shadow.mapSize.width = 1024;light.shadow.mapSize.height = 1024;var d = 300;// 在光的世界里。这用于生成场景的深度图;从光的角度来看,其他物体背后的物体将处于阴影中。light.shadow.camera.left = - d;light.shadow.camera.right = d;light.shadow.camera.top = d;light.shadow.camera.bottom = - d;light.shadow.camera.far = 1000;scene.add( light );// cloth materialvar loader = new THREE.TextureLoader(); // 创建一个texture加载器,内部可以加载图片var clothTexture = loader.load( 'textures/patterns/circuit_pattern.png' ); // 加载衣服图片或者迷宫图// anisotropy 沿着轴,通过具有最高纹素密度的像素的样本数。 默认情况下,这个值为1。设置一个较高的值将会产生比基本的mipmap更清晰的效果,代价是需要使用更多纹理样本clothTexture.anisotropy = 16;// 使用创建的clothTexture创建一种网格材质(一种非光泽表面的材质,没有镜面高光。)// map: 颜色贴图 类型为Texture// side: 定义将要渲染哪一面 - 正面,背面或两者// alpaTest: 透明度 设置运行alphaTest时要使用的alpha值。如果不透明度低于此值,则不会渲染材质。默认值为0。var clothMaterial = new THREE.MeshLambertMaterial( {map: clothTexture,side: THREE.DoubleSide, // 两面都渲染alphaTest: 0.5} );// cloth geometryclothGeometry = new THREE.ParametricBufferGeometry( clothFunction, cloth.w, cloth.h );// cloth meshobject = new THREE.Mesh( clothGeometry, clothMaterial );object.position.set( 0, 0, 0 );object.castShadow = true;scene.add( object );object.customDepthMaterial = new THREE.MeshDepthMaterial( {depthPacking: THREE.RGBADepthPacking,map: clothTexture,alphaTest: 0.5} );// spherevar ballGeo = new THREE.SphereBufferGeometry( ballSize, 32, 16 );var ballMaterial = new THREE.MeshLambertMaterial();sphere = new THREE.Mesh( ballGeo, ballMaterial );sphere.castShadow = true;sphere.receiveShadow = true;scene.add( sphere );// ground// 使用草坪图片制作材质覆盖到场景中var groundTexture = loader.load( 'textures/terrain/grasslight-big.jpg' );groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;groundTexture.repeat.set( 25, 25 );groundTexture.anisotropy = 16;var groundMaterial = new THREE.MeshLambertMaterial( { map: groundTexture } );var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );mesh.position.y = - 250;mesh.rotation.x = - Math.PI / 2;mesh.receiveShadow = true;scene.add( mesh );// poles// 使用poleMat与poleGeo渲染三个杆子到场景中var poleGeo = new THREE.BoxBufferGeometry( 5, 375, 5 );var poleMat = new THREE.MeshLambertMaterial();var mesh = new THREE.Mesh( poleGeo, poleMat );mesh.position.x = - 125;mesh.position.y = - 62;mesh.receiveShadow = true;mesh.castShadow = true;scene.add( mesh );var mesh = new THREE.Mesh( poleGeo, poleMat );mesh.position.x = 125;mesh.position.y = - 62;mesh.receiveShadow = true;mesh.castShadow = true;scene.add( mesh );var mesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 255, 5, 5 ), poleMat );mesh.position.y = - 250 + ( 750 / 2 );mesh.position.x = 0;mesh.receiveShadow = true;mesh.castShadow = true;scene.add( mesh );var gg = new THREE.BoxBufferGeometry( 10, 10, 10 );var mesh = new THREE.Mesh( gg, poleMat );mesh.position.y = - 250;mesh.position.x = 125;mesh.receiveShadow = true;mesh.castShadow = true;scene.add( mesh );var mesh = new THREE.Mesh( gg, poleMat );mesh.position.y = - 250;mesh.position.x = - 125;mesh.receiveShadow = true;mesh.castShadow = true;scene.add( mesh );// rendererrenderer = new THREE.WebGLRenderer( { antialias: true } );renderer.setPixelRatio( window.devicePixelRatio );renderer.setSize( window.innerWidth, window.innerHeight );container.appendChild( renderer.domElement );renderer.gammaInput = true;renderer.gammaOutput = true;renderer.shadowMap.enabled = true;// controls// 使用控制器,鼠标转换视角观看3D物体var controls = new THREE.OrbitControls( camera, renderer.domElement );controls.maxPolarAngle = Math.PI * 0.5;controls.minDistance = 1000;controls.maxDistance = 5000;// performance monitor// 在右上角添加帧数显示stats = new Stats();container.appendChild( stats.dom );//window.addEventListener( 'resize', onWindowResize, false );sphere.visible = ! true;}// 当缩放窗口时触发该函数,重新计算视锥体的宽高,并更新材质function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );}// 设置每一帧运行的函数,右上角的站,场景的渲染,以及 调用cloth的函数进行衣服动画的模拟function animate() {requestAnimationFrame( animate );var time = Date.now();var windStrength = Math.cos( time / 7000 ) * 20 + 40;windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) )windForce.normalize()windForce.multiplyScalar( windStrength );simulate( time );render();stats.update();}function render() {var p = cloth.particles;for ( var i = 0, il = p.length; i < il; i ++ ) {var v = p[ i ].position;clothGeometry.attributes.position.setXYZ( i, v.x, v.y, v.z );}clothGeometry.attributes.position.needsUpdate = true;clothGeometry.computeVertexNormals();sphere.position.copy( ballPosition );renderer.render( scene, camera );}</script></body>
</html>
下面解释一下代码中比较难理解的函数和方法
代码片段1:
function togglePins() {pins = pinsFormation[ ~~ ( Math.random() * pinsFormation.length ) ];
}
代码片段2:
// 设置每一帧运行的函数,右上角的站,场景的渲染,以及 调用cloth的函数进行衣服动画的模拟
function animate() {requestAnimationFrame( animate );var time = Date.now();var windStrength = Math.cos( time / 7000 ) * 20 + 40;windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) )windForce.normalize()windForce.multiplyScalar( windStrength );simulate( time );render();stats.update();}
代码片段3:
function render() {var p = cloth.particles;for ( var i = 0, il = p.length; i < il; i ++ ) {var v = p[ i ].position;clothGeometry.attributes.position.setXYZ( i, v.x, v.y, v.z );}clothGeometry.attributes.position.needsUpdate = true;clothGeometry.computeVertexNormals();sphere.position.copy( ballPosition );renderer.render( scene, camera );}
代码片段4:
/** Cloth Simulation using a relaxed constraints solver*/// Suggested Readings// Advanced Character Physics by Thomas Jakobsen Character
// http://freespace.virgin.net/hugo.elias/models/m_cloth.htm
// http://en.wikipedia.org/wiki/Cloth_modeling
// http://cg.alexandra.dk/tag/spring-mass-system/
// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdfvar DAMPING = 0.03;
var DRAG = 1 - DAMPING;
var MASS = 0.1;
var restDistance = 25;.......
.......
.......
代码的详细分析,在稍后上传..... 有点急事需要处理,请各位稍等...
Three.js案例分析系列1--webgl_animation_cloth 草坪上漂浮的白布相关推荐
- UEBA案例分析系列之检测失陷凭证
UEBA案例分析系列之检测失陷凭证 概述 近日万豪透漏其公司再次遭遇大规模数据泄露,可能涉及520万名客户的详细信息.此次事件攻击者使用万豪特许经营酒店两名员工的登录凭证进行数据访问. 利用合法凭证访 ...
- UEBA案例分析系列之数据泄露检测
UEBA案例分析系列之数据泄露检测 近日全球最大的域名注册商GoDaddy被披露出一起数据泄露事件.GoDaddy拥有超过1900万的用户,管理7700万域名,托管数百万个网站,因此,此次事件可能引起 ...
- ENode框架Conference案例分析系列之 - 订单处理减库存的设计
前言 前面的文章,我介绍了Conference案例的业务.上下文划分.领域模型.架构,以及代码整体流程.接下来想针对案例中一些重要的场景,分别做进一步的分析.本文想先介绍一下Conference案例的 ...
- ENode框架Conference案例分析系列之 - 复杂情况的读库更新设计
问题背景 Conference案例,是一个关于在线创建会议(类似QCon这种全球开发者大会).在线管理会议位置信息.在线预订某个会议的位置的,这样一个系统.具体可以看微软的这个项目的主页:http:/ ...
- python网页爬虫漫画案例_Python爬虫 JS案例分析:爬取鬼灭之刃漫
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 文章转载于公众号:快学Python 作者:皖渝 猪油骨,拿来卤~今天,来分享一下python图片爬 ...
- 读光OCR-文字识别技术解读与应用案例分析
读光OCR-文字识别技术解读与应用案例分析 摘要:大数据上云特惠活动系列直播,阿里巴巴高级算法专家永攀对读光OCR-文字识别技术和行业应用进行讲述.OCR的本质是识别图片中的文字,即在复杂的图片背景下 ...
- SPSS案例分析3:因子分析
http://hi.baidu.com/datasoldier/item/6689c4a50ec250dc5af1914c 因子分析在各行各业的应用非常广泛,尤其是科研论文中因子分析更是频频出现.小兵 ...
- 机器学习非监督学习—k-means及案例分析
一.非监督学习 无监督学习,顾名思义,就是不受监督的学习,一种自由的学习方式.该学习方式不需要先验知识进行指导,而是不断地自我认知,自我巩固,最后进行自我归纳,在机器学习中,无监督学习可以被简单理解为 ...
- 统计案例分析之预测社会消费品零售总额
有不足之处,还请大家私信交流. 版权声明:本文为自创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.(该文与课程报告相关,转载请务必附上出处),非常感谢. 本文链接:h ...
- 三维地图前端arcgis_【ArcGIS JS API + eCharts系列】实现二、三维网络路径图的绘制...
概述 前面两篇文章通过扩展EchartsLayer.js这个图层类,实现了使用ArcGIS JS API和eCharts,在二维和三维场景下绘制迁徙图和散点图.这篇文章继续通过绘制网络路径图的例子,再 ...
最新文章
- Redis 笔记系列(十一)——Redis的发布和订阅机制
- 洛谷P2672 推销员
- 查看mysql日志文件大小和数据库大小
- 让Visual Studio 2005 Team Foundation Server支持Wss3
- VSCode 用户自定义片段 snippet 基本语法说明
- 查看linux文件目录的大小和文件夹包含的文件数
- 国内maven镜像,快的飞起
- 3、redis之java client环境搭建
- 六、hibernate之HQL
- DevOps使用教程 华为云(18)git 把单个文件回退到某一版本
- pytorch版本升级至1.11.0
- Android OS历史版本
- related knowledge points about protein
- 2022年「博客之星」参赛博主:一个处女座的测试
- STM32 USB使用记录:使用CDC类虚拟串口(VCP)进行通讯
- 淘宝/天猫获取卖出的商品订单列表API接口,店铺订单API接口,店铺订单详情API接口
- 苹果计算机转换,便携毕亚兹苹果计算机转换器,超极本的少接口都能转换身份...
- php计算机专业毕业设计题目,计算机专业毕业论文-基于PHP的网络爬虫的设计与实现.doc...
- HP打印机同一路由(子网)下共享连接打印机
- 一文快速搞懂对95%置信区间的理解
热门文章
- 好物分享 Kvaser支持CANFD功能的CAN卡都有哪些?
- JVM——字节码指令(转)
- 中国第二代支付清算体系-总结
- VB中常用的的ASCII码chr()对应表
- 服务器怎么ghost备份系统,GHOST备份系统的方法 GHOST备份系统教程
- Ubuntu20.04禁用触摸屏键盘
- 缩短bch码能用matlab,BCH码编译码matlab仿真.doc
- 无线电波在介质中的传播速度计算公式和印刷电路板(PCB)的特性阻抗与特性阻抗控制
- 软件设计师中级考试经验总结
- linux配置串口驱动程序,[Linux 驱动] -- Linux 驱动之串口(UART)