Three.js案例分析系列1--webgl_animation_cloth 草坪上漂浮的白布
【摘要】
案例地址 webgl_animation_cloth--草坪上随风漂浮的白布
github源代码:
效果图:
案件描述介绍:
右上角显示帧数,左上角是一个控制盘,控制一些参数
居中是一片草坪,远处的草坪皆有雾化的效果,逐渐模糊不清,草坪中央有一个单杠,挂着一块白布,随风飘摇.
为什么选中这个案例...
案例地址 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 pins
-
pinsFormation.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 );
-
-
// scene
-
-
scene = 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进制默认为白色,第二个表示光的强度,默认1
-
var 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 material
-
-
var 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 geometry
-
-
clothGeometry = new THREE.ParametricBufferGeometry( clothFunction, cloth.w, cloth.h );
-
-
// cloth mesh
-
-
object = 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
-
-
} );
-
-
// sphere
-
-
var 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 );
-
-
// renderer
-
-
renderer = 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.pdf
-
-
var DAMPING = 0.03;
-
var DRAG = 1 - DAMPING;
-
var MASS = 0.1;
-
var restDistance = 25;
-
-
.......
-
.......
-
.......
代码的详细分析,在稍后上传..... 有点急事需要处理,请各位稍等...
文章来源: fizzz.blog.csdn.net,作者:拿我格子衫来,版权归原作者所有,如需转载,请联系作者。
原文链接:fizzz.blog.csdn.net/article/details/96477991
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)