我让下面的 ThreeJS 工作了一些,尽管它在某些部分可能会关闭,而且效果可能看起来还不太令人信服,我不确定。distortViaMagnets 函数是问题的核心(此处为完整运行的HTML 和源代码;此处运行演示):
'use strict';
var app = null;
window.onload = function() {
app = new App();
app.init();
}
App.prototype.init = function() {
this.scene = new THREE.Scene();
this.addCamera();
this.addLights();
this.addSphere();
this.addRenderer();
this.render();
app.animate();
};
App.prototype.distortViaMagnets = function() {
var maxMagnets = this.magnets.length, maxVertices = this.sphere.geometry.vertices.length;
var magneticMaxValue = this.getDistance3d( {x: 0, y: 0, z: 0}, {x: 1000, y: 1000, z: 1000} );
var strength = 1000, factor = 3;
for (var i = 0; i < maxMagnets; i++) {
for (var vertexI = 0; vertexI < maxVertices; vertexI++) {
var magnet = this.magnets[i];
var vertex = this.sphere.geometry.vertices[vertexI];
var distance = this.getDistance3d(magnet, vertex);
var power = magneticMaxValue / distance / strength;
vertex.x += ( (magnet.x - vertex.x) * power ) * factor;
vertex.y += ( (magnet.y - vertex.y) * power ) * factor;
vertex.z += ( (magnet.z - vertex.z) * power ) * factor;
}
}
}
App.prototype.animate = function() {
app.mainGroup.rotation.y -= .003;
requestAnimationFrame(app.animate);
app.renderer.render(app.scene, app.camera);
};
App.prototype.addCamera = function() {
this.camera = new THREE.CombinedCamera(this.width, this.height, 45, 1, 10000);
this.camera.position.set(0, 0, 400 - 200);
this.camera.lookAt( new THREE.Vector3(0, 0, 0) );
this.scene.add(this.camera);
}
App.prototype.addSphere = function() {
this.mainGroup = new THREE.Object3D();
var radius = 50, segments = 30 * 3, rings = 30 * 3;
var geometry = new THREE.SphereGeometry(radius, segments, rings);
geometry.dynamic = true;
var material = new THREE.MeshPhongMaterial( {color: 0xffffff, opacity: 1} );
this.sphere = new THREE.Mesh(geometry, material);
this.sphere.dynamic = true;
this.sphere.position.set(0, 0, 0);
this.sphere.doubleSided = true;
this.addMagnets();
this.distortViaMagnets();
this.mainGroup.add(this.sphere);
this.scene.add(this.mainGroup);
}
App.prototype.addMagnets = function(vertex) {
var max = this.sphere.geometry.vertices.length, maxMagnets = 1;
for (var i = 1; i <= 2; i++) {
var index = Misc.getRandomInt(0, max - 1);
var vertex = app.sphere.geometry.vertices[index];
var magnetI = this.magnets.length;
this.magnets[magnetI] = this.distortVertex( {x: vertex.x, y: vertex.y, z: vertex.z}, 10 );
this.showMagnet(this.magnets[magnetI]);
}
var magnetI = 0;
this.magnets[magnetI] = {x: 58, y: 0, z: 0};
this.showMagnet(this.magnets[magnetI]);
}
App.prototype.getDistance3d = function(vertex1, vertex2) {
var xfactor = vertex2.x - vertex1.x;
var yfactor = vertex2.y - vertex1.y;
var zfactor = vertex2.z - vertex1.z;
return Math.sqrt( (xfactor*xfactor) + (yfactor*yfactor) + (zfactor*zfactor) );
}
App.prototype.showMagnet = function(vertex) {
var radius = 1.5, segments = 10, rings = 10;
var geometry = new THREE.SphereGeometry(radius, segments, rings);
var material = new THREE.MeshPhongMaterial( {color: 0x11ee33, opacity: .6} );
var sphere = new THREE.Mesh(geometry, material);
sphere.position.set(vertex.x, vertex.y, vertex.z);
this.mainGroup.add(sphere);
}
App.prototype.distortVertex = function(vertex, distortion) {
vertex.x = Misc.distort(vertex.x, distortion);
vertex.y = Misc.distort(vertex.y, distortion);
vertex.z = Misc.distort(vertex.z, distortion);
return vertex;
}
App.prototype.addRenderer = function() {
this.renderer = new THREE.WebGLRenderer( {antialias: true} );
this.renderer.setSize(this.width, this.height);
var elmMain = document.getElementById('main');
elmMain.appendChild(this.renderer.domElement);
}
App.prototype.render = function() {
this.renderer.render(this.scene, this.camera);
};
App.prototype.addLights = function() {
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-50, 250, 250);
this.scene.add(light);
};
function App() {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.camera = null;
this.sphere = null;
this.controls = null;
this.mainGroup = null;
this.renderer = null;
this.scene = null;
this.magnets = [];
this.debugElm = null;
}