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





推荐阅读
  • PBO(PixelBufferObject),将像素数据存储在显存中。优点:1、快速的像素数据传递,它采用了一种叫DMA(DirectM ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 入门指南:使用FastRPC技术连接Qualcomm Hexagon DSP
    本文旨在为初学者提供关于如何使用FastRPC技术连接Qualcomm Hexagon DSP的基础知识。FastRPC技术允许开发者在本地客户端实现远程调用,从而简化Hexagon DSP的开发和调试过程。 ... [详细]
  • 在Qt框架中,信号与槽机制是一种独特的组件间通信方式。本文探讨了这一机制相较于传统的C风格回调函数所具有的优势,并分析了其潜在的不足之处。 ... [详细]
  • 本文将深入探讨 Unreal Engine 4 (UE4) 中的距离场技术,包括其原理、实现细节以及在渲染中的应用。距离场技术在现代游戏引擎中用于提高光照和阴影的效果,尤其是在处理复杂几何形状时。文章将结合具体代码示例,帮助读者更好地理解和应用这一技术。 ... [详细]
  • pypy 真的能让 Python 比 C 还快么?
    作者:肖恩顿来源:游戏不存在最近“pypy为什么能让python比c还快”刷屏了,原文讲的内容偏理论,干货比较少。我们可以再深入一点点,了解pypy的真相。正式开始之前,多唠叨两句 ... [详细]
  • 本打算教一步步实现koa-router,因为要解释的太多了,所以先简化成mini版本,从实现部分功能到阅读源码,希望能让你好理解一些。希望你之前有读过koa源码,没有的话,给你链接 ... [详细]
  • ipsec 加密流程(二):ipsec初始化操作
    《openswan》专栏系列文章主要是记录openswan源码学习过程中的笔记。Author:叨陪鲤Email:vip_13031075266163.comDate:2020.1 ... [详细]
  • iOS snow animation
    CTSnowAnimationView.hCTMyCtripCreatedbyalexon1614.Copyright©2016年ctrip.Allrightsreserved.# ... [详细]
  • MySQL初级篇——字符串、日期时间、流程控制函数的相关应用
    文章目录:1.字符串函数2.日期时间函数2.1获取日期时间2.2日期与时间戳的转换2.3获取年月日、时分秒、星期数、天数等函数2.4时间和秒钟的转换2. ... [详细]
  • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
  • IO流——字符流 BufferedReader / BufferedWriter 进行文件读写
    目录节点流、处理流读文件:BufferedReader的使用写文件:BufferedWriter的使用节点流处理流节点流和处理流的区别和联系字符流Buf ... [详细]
  • Quora问题探讨:26岁开始转行做开发是否太迟? ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
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社区 版权所有