热门标签 | 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 );
}





推荐阅读
  • vue使用
    关键词: ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 在编写业务代码时,常常会遇到复杂的业务逻辑导致代码冗长混乱的情况。为了解决这个问题,可以利用中间件模式来简化代码逻辑。中间件模式可以帮助我们更好地设计架构和代码,提高代码质量。本文介绍了中间件模式的基本概念和用法。 ... [详细]
  • 本文介绍了一道网络流题目hdu4888 Redraw Beautiful Drawings的解题思路。题目要求以行和列作为结点建图,并通过最大流算法判断是否有解以及是否唯一。文章详细介绍了建图和算法的过程,并强调在dfs过程中要进行回溯。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • 本文介绍了如何在Jquery中通过元素的样式值获取元素,并将其赋值给一个变量。提供了5种解决方案供参考。 ... [详细]
  • Introduction(简介)Forbeingapowerfulobject-orientedprogramminglanguage,Cisuseda ... [详细]
  • 本博文基于《Amalgamationofproteinsequence,structureandtextualinformationforimprovingprote ... [详细]
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社区 版权所有