因为计图项目是海底世界创建,所以虽然画出了个竹子,但是还是想画海草。
由于海草也是波浪形的,想起之前在一个博客里看到了波浪平面的生成是利用ParametricGeometry
生成的,于是也想试一试,就写出了如下代码:
//海草形状
var radialWave = function (u, v) {
var r = 150;
var z = Math.sin(u) * r;
var x = Math.sin(v / 2) * r;
var y = (Math.sin(u * 4 * Math.PI) + Math.cos(v * 2 * Math.PI)) * 10;
return new THREE.Vector3(x, y, z);
};
//按照形成海草形状的参数方程来生成海草几何体,再生成海草网格
var mesh = new THREE.Mesh(new THREE.ParametricGeometry(radialWave, 12, 12),
new THREE.MeshPhongMaterial( {
size:50,
color:0x00ff00,
side:THREE.DoubleSide
})
);
mesh.position.set(0,0,-200);
mesh.scale.set(1,0.5,2);
mesh.rotation.x = Math.PI*0.5;
scene.add(mesh);
在某个可以在线运行js代码的网站上成功画出了海草:
于是兴高采烈的搬到了本地代码里,然而什么都没画出来!!
以为是浏览器的锅,换成了高大上的chrome,还是没画出来orz..
然后就怀疑我的three.js是不是yan-ge版,找到了three官方的文件,对照下来,差不多嘛,
但是官网中的实现有这么一句话!!非常关键!!
if ( func.length < 3 ) {
console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
}
什么意思呢?就是说,参数方程那个函数的参数表必须有三个参数,而这个第三个参数是一个Vector3的类型,在我们的func里需要修改这个Vector3,而不是前面实现的返回值为Vector3!!
而我的本地代码里的three.js虽然实现是一样的,但是并没有提示报错…
于是把函数改成了这样:
var radialWave = function (u, v, p0) {
var r = 150;
var z = Math.sin(u) * r;
var x = Math.sin(v / 2) * r;
var y = (Math.sin(u * 4 * Math.PI) + Math.cos(v * 2 * Math.PI)) * 10;
p0 = new THREE.Vector3(x, y, z);
};
对不起,还是没有画出来orz
再看了一次官网源码,感觉没有什么不对劲啊,于是去看了官网给出的示例的代码,发现别人是这样写的:
target.set( x, y, z );
噢,原来要用set方法,果然js还是不太熟,以为都是引用传参,其实这里的=是浅复制,等函数执行完,分配的内存就被释放了,p0并没有被改变。
改完代码,好了,终于看到这根绿油油亮的晃眼的海草了。
顺带一提官网的例子里还给了几个形状(克莱因瓶,平面,二维莫比乌斯带,三维莫比乌斯带)的产生函数,
贴一下地址:https://github.com/mrdoob/three.js/blob/master/examples/js/ParametricGeometries.js
也顺便贴一下代码:
klein: function ( v, u, target ) {
u *= Math.PI;
v *= 2 * Math.PI;
u = u * 2;
var x, y, z;
if ( u < Math.PI ) {
x = 3 * Math.cos( u ) * ( 1 + Math.sin( u ) ) + ( 2 * ( 1 - Math.cos( u ) / 2 ) ) * Math.cos( u ) * Math.cos( v );
z = - 8 * Math.sin( u ) - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( u ) * Math.cos( v );
} else {
x = 3 * Math.cos( u ) * ( 1 + Math.sin( u ) ) + ( 2 * ( 1 - Math.cos( u ) / 2 ) ) * Math.cos( v + Math.PI );
z = - 8 * Math.sin( u );
}
y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
target.set( x, y, z );
},
plane: function ( width, height ) {
return function ( u, v, target ) {
var x = u * width;
var y = 0;
var z = v * height;
target.set( x, y, z );
};
},
mobius: function ( u, t, target ) {
// flat mobius strip
// http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
u = u - 0.5;
var v = 2 * Math.PI * t;
var x, y, z;
var a = 2;
x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) );
y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
z = u * Math.sin( v / 2 );
target.set( x, y, z );
},
mobius3d: function ( u, t, target ) {
// volumetric mobius strip
u *= Math.PI;
t *= 2 * Math.PI;
u = u * 2;
var phi = u / 2;
var major = 2.25, a = 0.125, b = 0.65;
var x, y, z;
x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi );
z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi );
y = ( major + x ) * Math.sin( u );
x = ( major + x ) * Math.cos( u );
target.set( x, y, z );
}
};