热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

保持three.js布料模拟的长宽比

在他们网站上显示的示例中,正在使用的布料质地为正方形,如您所见

在他们网站上显示的示例中,正在使用的布料质地为正方形,如您所见here。

但是,在示例页面中,它的高度显示为拉伸,如下面的屏幕截图所示。禁用风时,您会很容易注意到这一点。

如何保持正确的宽高比,为什么在three.js示例中不尊重它?

保持three.js布料模拟的长宽比

下面的完整代码:

var params = {
enableWind: true,showBall: false,tooglePins: togglePins
};
var DAMPING = 0.03;
var DRAG = 1 - DAMPING;
var MASS = 0.1;
var restDistance = 25;
var xSegs = 10;
var ySegs = 10;
var clothFunction = plane( restDistance * xSegs,restDistance * ySegs );
var cloth = new Cloth( xSegs,ySegs );
var GRAVITY = 981 * 1.4;
var gravity = new THREE.Vector3( 0,- GRAVITY,0 ).multiplyScalar( MASS );
var TIMESTEP = 18 / 1000;
var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
var pins = [];
var windForce = new THREE.Vector3( 0,0 );
var ballPosition = new THREE.Vector3( 0,- 45,0 );
var ballSize = 60; //40
var tmpForce = new THREE.Vector3();
var lastTime;
function plane( width,height ) {
return function ( u,v,target ) {
var x = ( u - 0.5 ) * width;
var y = ( v + 0.5 ) * height;
var z = 0;
target.set( x,y,z );
};
}
function Particle( x,z,mass ) {
this.position = new THREE.Vector3();
this.previous = new THREE.Vector3();
this.original = new THREE.Vector3();
this.a = new THREE.Vector3( 0,0 ); // acceleration
this.mass = mass;
this.invMass = 1 / mass;
this.tmp = new THREE.Vector3();
this.tmp2 = new THREE.Vector3();
// init
clothFunction( x,this.position ); // position
clothFunction( x,this.previous ); // previous
clothFunction( x,this.original );
}
// Force -> acceleration
Particle.prototype.addForce = function ( force ) {
this.a.add(
this.tmp2.copy( force ).multiplyScalar( this.invMass )
);
};
// Performs Verlet integration
Particle.prototype.integrate = function ( timesq ) {
var newPos = this.tmp.subVectors( this.position,this.previous );
newPos.multiplyScalar( DRAG ).add( this.position );
newPos.add( this.a.multiplyScalar( timesq ) );
this.tmp = this.previous;
this.previous = this.position;
this.position = newPos;
this.a.set( 0,0 );
};
var diff = new THREE.Vector3();
function satisfyConstraints( p1,p2,distance ) {
diff.subVectors( p2.position,p1.position );
var currentDist = diff.length();
if ( currentDist === 0 ) return; // prevents division by 0
var correction = diff.multiplyScalar( 1 - distance / currentDist );
var correctiOnHalf= correction.multiplyScalar( 0.5 );
p1.position.add( correctionHalf );
p2.position.sub( correctionHalf );
}
function Cloth( w,h ) {
w = w || 10;
h = h || 10;
this.w = w;
this.h = h;
var particles = [];
var cOnstraints= [];
var u,v;
// Create particles
for ( v = 0; v <= h; v ++ ) {
for ( u = 0; u <= w; u ++ ) {
particles.push(
new Particle( u / w,v / h,MASS )
);
}
}
// Structural
for ( v = 0; v for ( u = 0; u constraints.push( [
particles[ index( u,v ) ],particles[ index( u,v + 1 ) ],restDistance
] );
constraints.push( [
particles[ index( u,particles[ index( u + 1,restDistance
] );
}
}
for ( u = w,v = 0; v constraints.push( [
particles[ index( u,restDistance
] );
}
for ( v = h,u = 0; u constraints.push( [
particles[ index( u,restDistance
] );
}
// While many systems use shear and bend springs,// the relaxed constraints model seems to be just fine
// using structural springs.
// Shear
// var diagOnalDist= Math.sqrt(restDistance * restDistance * 2);
// for (v=0;v // for (u=0;u // constraints.push([
// particles[index(u,v)],// particles[index(u+1,v+1)],// diagonalDist
// ]);
// constraints.push([
// particles[index(u+1,// particles[index(u,// diagonalDist
// ]);
// }
// }
this.particles = particles;
this.cOnstraints= constraints;
function index( u,v ) {
return u + v * ( w + 1 );
}
this.index = index;
}
function simulate( time ) {
if ( ! lastTime ) {
lastTime = time;
return;
}
var i,j,il,particles,particle,constraints,constraint;
// Aerodynamics forces
if ( params.enableWind ) {
var indx;
var normal = new THREE.Vector3();
var indices = clothGeometry.index;
var normals = clothGeometry.attributes.normal;
particles = cloth.particles;
for ( i = 0,il = indices.count; i for ( j = 0; j <3; j ++ ) {
indx = indices.getX( i + j );
normal.fromBufferAttribute( normals,indx );
tmpForce.copy( normal ).normalize().multiplyScalar( normal.dot( windForce ) );
particles[ indx ].addForce( tmpForce );
}
}
}
for ( particles = cloth.particles,i = 0,il = particles.length; i particle = particles[ i ];
particle.addForce( gravity );
particle.integrate( TIMESTEP_SQ );
}
// Start Constraints
cOnstraints= cloth.constraints;
il = constraints.length;
for ( i = 0; i cOnstraint= constraints[ i ];
satisfyConstraints( constraint[ 0 ],constraint[ 1 ],constraint[ 2 ] );
}
// Ball Constraints
ballPosition.z = - Math.sin( Date.now() / 600 ) * 90; //+ 40;
ballPosition.x = Math.cos( Date.now() / 400 ) * 70;
if ( params.showBall ) {
sphere.visible = true;
for ( particles = cloth.particles,il = particles.length; i particle = particles[ i ];
var pos = particle.position;
diff.subVectors( pos,ballPosition );
if ( diff.length() // collided
diff.normalize().multiplyScalar( ballSize );
pos.copy( ballPosition ).add( diff );
}
}
} else {
sphere.visible = false;
}
// Floor Constraints
for ( particles = cloth.particles,il = particles.length; i particle = particles[ i ];
pos = particle.position;
if ( pos.y <- 250 ) {
pos.y = - 250;
}
}
// Pin Constraints
for ( i = 0,il = pins.length; i var xy = pins[ i ];
var p = particles[ xy ];
p.position.copy( p.original );
p.previous.copy( p.original );
}
}
/* 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 ) ];
}
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 );
scene.fog = new THREE.Fog( 0xcce0ff,500,10000 );
// camera
camera = new THREE.PerspectiveCamera( 30,window.innerWidth / window.innerHeight,10000 );
camera.position.set( 1000,50,1500 );
// lights
scene.add( new THREE.AmbientLight( 0x666666 ) );
var light = new THREE.DirectionalLight( 0xdfebff,1 );
light.position.set( 50,200,100 );
light.position.multiplyScalar( 1.3 );
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();
var clothTexture = loader.load( 'textures/patterns/circuit_pattern.png' );
clothTexture.anisotropy = 16;
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 );
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;
sphere.visible = false;
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
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 ),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
var cOntrols= new 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 );
//
var gui = new GUI();
gui.add( params,'enableWind' );
gui.add( params,'showBall' );
gui.add( params,'tooglePins' );
}
//
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionmatrix();
renderer.setSize( window.innerWidth,window.innerHeight );
}
//
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 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 );
}





推荐阅读
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
author-avatar
别禳莴觞芯_737
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有