Dar*_*man 11 javascript formula three.js
我正试图用THREE.js重新创建一个原子,我正在探讨我的第一个问题 - 因为每种类型的原子都有不同数量的质子/中子,我试图找到一种方法来定位它们自动,以便没有碰撞,因此它们的最终结果将使尽可能接近球体的东西 - 请参阅此图像以获取示例
img http://www.alternativephysics.org/book/img/ANuc-ball-nucleus.jpg.
有没有办法计算这个并用公式轻松分配每个中子/质子的位置?或者我是否必须让物理引擎参与到将球体挤压在一起并希望每次运行时获得最佳效果?
我还没有任何代码,因为我只想弄清楚从哪一部分开始.
编辑
我还应该注意,我希望球体在较大球体的空间内被挤压在一起.我并不是想让所有的球体都在更大球体的半径上.
编辑2
我研究了使用物理引擎将它们全部挤压到一个小区域,但是我找不到一个引擎可以让我用重力将场景中的所有物体移动到位置(0,0,0) .所有发动机只是让重力压下一个物体.我仍然宁愿使用公式来定位球体,而不是将整个物理引擎包含在我的项目中.
编辑3,04/06/06
我做了一些实验,但我仍然无法做到.这是现在的样子:
但正如你所看到的,看起来真的很糟糕.当我制造铀原子而不是碳原子(更多的质子/中子/电子)时会发生这种情况
它可能只是我,但它看起来更像是一些花式料理鼠王而不是铀原子.
我是怎么来的
我试图制作我正在寻找的东西,这里的前提是:
(particleObject
是粒子的父级,粒子将相对于此对象移动)
added number % 2 == 0
,(这是我的测试)我会将旋转设置为(pi * 2) / 2
< - 最后两个在那里代表上面两个.I
都会增加l
变量.(希望)只要i
等于loopcount
变量,就意味着我将球体放置在球体形状中.然后我乘以loopcount
3来找出下一次运行需要多少个球体.我将其设置l
为0,以便重置球体的定位,并且循环将递增,从而使下一行球体在x轴上放置1个单位. (对不起这里的术语,很难解释.请参阅代码.)
var PNamount = atomTypes[type].protons + atomTypes[type].neutrons;
var loopcount = 1;
if(PNamount % 2 == 0) {
var rotate = (PI * 2) / 2;
loopcount = 2;
}
var neutrons = 0,
protons = 0,
loop = 1,
l = 0;
for(var i = 0; i < PNamount; i++) {
if(i == loopcount){
loopcount = loopcount * 3;
loop++;
rotate = (PI * 2) / loopcount;
l = 0;
} else {
l++;
}
particleObject.rotation.x = rotate * l;
particleObject.rotation.y = rotate * l;
particleObject.rotation.z = rotate * l;
particle.position.x = loop;
}
Run Code Online (Sandbox Code Playgroud)
老实说,我对3D数学一点也不好.所以任何帮助都会非常有帮助.另外,我的定位方法很可能在各方面都是完全错误的.谢谢!
我肯定会说这是物理引擎的完美用例.在没有物理引擎的情况下进行这种模拟听起来像是一个真正的麻烦,所以"包括整个物理引擎"并不像我这么大的成本.无论如何,我发现的大多数JavaScript物理引擎都很重要.然而,它会为物理计算需要一些额外的CPU功率!
我坐下来试图创建类似于你用物理引擎CANNON.js描述的东西.让基本模拟工作变得非常容易,但是为了获得恰到好处的参数,看起来有点棘手,需要更多的调整.
你提到你已经尝试了这个但是无法使粒子倾向于一个点,使用CANNON.js(可能还有大多数其他物理引擎)这可以通过在负位置方向对物体施加力来实现:
function pullOrigin(body){
body.force.set(
-body.position.x,
-body.position.y,
-body.position.z
);
}
Run Code Online (Sandbox Code Playgroud)
实现将身体拉向某个父对象的行为也很容易,而父对象又会拉向所有其他父对象的平均位置.这样你就可以创造出完整的分子.
一个棘手的问题是让电子在一定距离内循环质子和中子.为了达到这个目的,我向它们施加一个轻微的力量,同时向所有质子和中子施加一点力.最重要的是,我还在模拟开始时给他们一个小推动,以便他们开始循环中心.
如果您希望我澄清任何特定部分,请告诉我.
let scene = new THREE.Scene();
let world = new CANNON.World();
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 5;
let camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
let renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
function Proton(){
let radius = 1;
return {
// Cannon
body: new CANNON.Body({
mass: 1, // kg
position: randomPosition(6),
shape: new CANNON.Sphere(radius)
}),
// THREE
mesh: new THREE.Mesh(
new THREE.SphereGeometry( radius, 32, 32 ),
new THREE.MeshPhongMaterial( { color: 0xdd5555, specular: 0x999999, shininess: 13} )
)
}
}
function Neutron(){
let radius = 1;
return {
// Cannon
body: new CANNON.Body({
mass: 1, // kg
position: randomPosition(6),
shape: new CANNON.Sphere(radius)
}),
// THREE
mesh: new THREE.Mesh(
new THREE.SphereGeometry( radius, 32, 32 ),
new THREE.MeshPhongMaterial( { color: 0x55dddd, specular: 0x999999, shininess: 13} )
)
}
}
function Electron(){
let radius = 0.2;
return {
// Cannon
body: new CANNON.Body({
mass: 0.5, // kg
position: randomPosition(10),
shape: new CANNON.Sphere(radius)
}),
// THREE
mesh: new THREE.Mesh(
new THREE.SphereGeometry( radius, 32, 32 ),
new THREE.MeshPhongMaterial( { color: 0xdddd55, specular: 0x999999, shininess: 13} )
)
}
}
function randomPosition(outerRadius){
let x = (2 * Math.random() - 1 ) * outerRadius,
y = (2 * Math.random() - 1 ) * outerRadius,
z = (2 * Math.random() - 1 ) * outerRadius
return new CANNON.Vec3(x, y, z);
}
function addToWorld(object){
world.add(object.body);
scene.add(object.mesh);
}
// create our Atom
let protons = Array(5).fill(0).map( () => Proton() );
let neutrons = Array(5).fill(0).map( () => Neutron() );
let electrons = Array(15).fill(0).map( () => Electron() );
protons.forEach(addToWorld);
neutrons.forEach(addToWorld);
electrons.forEach(addToWorld);
let light = new THREE.AmbientLight( 0x202020 ); // soft white light
scene.add( light );
let directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set( -1, 1, 1 );
scene.add( directionalLight );
camera.position.z = 18;
const timeStep = 1/60;
//Small impulse on the electrons to get them moving in the start
electrons.forEach((electron) => {
let centerDir = electron.body.position.vsub(new CANNON.Vec3(0, 0, 0));
centerDir.normalize();
let impulse = centerDir.cross(new CANNON.Vec3(0, 0, 1));
impulse.scale(2, impulse);
electron.body.applyLocalImpulse(impulse, new CANNON.Vec3(0, 0, 0));
});
function render () {
requestAnimationFrame( render );
// all particles pull towards the center
protons.forEach(pullOrigin);
neutrons.forEach(pullOrigin);
electrons.forEach(pullOrigin);
// electrons should also be pushed by protons and neutrons
electrons.forEach( (electron) => {
let pushForce = new CANNON.Vec3(0, 0, 0 );
protons.forEach((proton) => {
let f = electron.body.position.vsub(proton.body.position);
pushForce.vadd(f, pushForce);
});
neutrons.forEach((neutron) => {
let f = electron.body.position.vsub(neutron.body.position);
pushForce.vadd(f, pushForce);
});
pushForce.scale(0.07, pushForce);
electron.body.force.vadd(pushForce, electron.body.force);
})
// protons and neutrons slows down (like wind resistance)
neutrons.forEach((neutron) => resistance(neutron, 0.95));
protons.forEach((proton) => resistance(proton, 0.95));
// Electrons have a max velocity
electrons.forEach((electron) => {maxVelocity(electron, 5)});
// Step the physics world
world.step(timeStep);
// Copy coordinates from Cannon.js to Three.js
protons.forEach(updateMeshState);
neutrons.forEach(updateMeshState);
electrons.forEach(updateMeshState);
renderer.render(scene, camera);
};
function updateMeshState(object){
object.mesh.position.copy(object.body.position);
object.mesh.quaternion.copy(object.body.quaternion);
}
function pullOrigin(object){
object.body.force.set(
-object.body.position.x,
-object.body.position.y,
-object.body.position.z
);
}
function maxVelocity(object, vel){
if(object.body.velocity.length() > vel)
object.body.force.set(0, 0, 0);
}
function resistance(object, val) {
if(object.body.velocity.length() > 0)
object.body.velocity.scale(val, object.body.velocity);
}
render();
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
编辑
我已将粒子模块化为可从Atom函数检索的Atom对象.如果您不确定任何内容,还会在代码中添加更多注释.我建议你真正研究代码,并检查CANNON.js文档(它真的是thourogh).与力有关的东西在Cannon.js 的Body类中.我所做的就是将THREE.Mesh和CANNON.Body组合成一个对象(对于每个粒子).然后我模拟了CANNON.Body上的所有动作,在我渲染THREE之前,我将CANNON.Body的位置和旋转复制到THREE.Mesh.
这是Atom函数(改变了一些电子物理学):
function Atom(nProtons, nNeutrons, nElectrons, pos = new CANNON.Vec3(0, 0, 0)){
//variable to move the atom, which att the particles will pull towards
let position = pos;
// create our Atom
let protons = Array(nProtons).fill(0).map( () => Proton() );
let neutrons = Array(nNeutrons).fill(0).map( () => Neutron() );
let electrons = Array(nElectrons).fill(0).map( () => Electron() );
// Public Functions
//=================
// add to a three.js and CANNON scene/world
function addToWorld(world, scene) {
protons.forEach((proton) => {
world.add(proton.body);
scene.add(proton.mesh);
});
neutrons.forEach((neutron) => {
world.add(neutron.body);
scene.add(neutron.mesh);
});
electrons.forEach((electron) => {
world.add(electron.body);
scene.add(electron.mesh);
});
}
function simulate() {
protons.forEach(pullParticle);
neutrons.forEach(pullParticle);
//pull electrons if they are further than 5 away
electrons.forEach((electron) => { pullParticle(electron, 5) });
//push electrons if they are closer than 6 away
electrons.forEach((electron) => { pushParticle(electron, 6) });
// give the particles some friction/wind resistance
//electrons.forEach((electron) => resistance(electron, 0.95));
neutrons.forEach((neutron) => resistance(neutron, 0.95));
protons.forEach((proton) => resistance(proton, 0.95));
}
function electronStartingVelocity(vel) {
electrons.forEach((electron) => {
let centerDir = electron.body.position.vsub(position);
centerDir.normalize();
let impulse = centerDir.cross(new CANNON.Vec3(0, 0, 1));
impulse.scale(vel, impulse);
electron.body.applyLocalImpulse(impulse, new CANNON.Vec3(0, 0, 0));
});
}
// Should be called after CANNON has simulated a frame and before THREE renders.
function updateAtomMeshState(){
protons.forEach(updateMeshState);
neutrons.forEach(updateMeshState);
electrons.forEach(updateMeshState);
}
// Private Functions
// =================
// pull a particale towards the atom position (if it is more than distance away)
function pullParticle(particle, distance = 0){
// if particle is close enough, dont pull more
if(particle.body.position.distanceTo(position) < distance)
return false;
//create vector pointing from particle to atom position
let pullForce = position.vsub(particle.body.position);
// same as: particle.body.force = particle.body.force.vadd(pullForce)
particle.body.force.vadd( // add particle force
pullForce, // to pullForce
particle.body.force); // and put it in particle force
}
// Push a particle from the atom position (if it is less than distance away)
function pushParticle(particle, distance = 0){
// if particle is far enough, dont push more
if(particle.body.position.distanceTo(position) > distance)
return false;
//create vector pointing from particle to atom position
let pushForce = particle.body.position.vsub(position);
particle.body.force.vadd( // add particle force
pushForce, // to pushForce
particle.body.force); // and put it in particle force
}
// give a partile some friction
function resistance(particle, val) {
if(particle.body.velocity.length() > 0)
particle.body.velocity.scale(val, particle.body.velocity);
}
// Call this on a particle if you want to limit its velocity
function limitVelocity(particle, vel){
if(particle.body.velocity.length() > vel)
particle.body.force.set(0, 0, 0);
}
// copy ratation and position from CANNON to THREE
function updateMeshState(particle){
particle.mesh.position.copy(particle.body.position);
particle.mesh.quaternion.copy(particle.body.quaternion);
}
// public API
return {
"simulate": simulate,
"electrons": electrons,
"neutrons": neutrons,
"protons": protons,
"position": position,
"updateAtomMeshState": updateAtomMeshState,
"electronStartingVelocity": electronStartingVelocity,
"addToWorld": addToWorld
}
}
function Proton(){
let radius = 1;
return {
// Cannon
body: new CANNON.Body({
mass: 1, // kg
position: randomPosition(0, 6), // random pos from radius 0-6
shape: new CANNON.Sphere(radius)
}),
// THREE
mesh: new THREE.Mesh(
new THREE.SphereGeometry( radius, 32, 32 ),
new THREE.MeshPhongMaterial( { color: 0xdd5555, specular: 0x999999, shininess: 13} )
)
}
}
function Neutron(){
let radius = 1;
return {
// Cannon
body: new CANNON.Body({
mass: 1, // kg
position: randomPosition(0, 6), // random pos from radius 0-6
shape: new CANNON.Sphere(radius)
}),
// THREE
mesh: new THREE.Mesh(
new THREE.SphereGeometry( radius, 32, 32 ),
new THREE.MeshPhongMaterial( { color: 0x55dddd, specular: 0x999999, shininess: 13} )
)
}
}
function Electron(){
let radius = 0.2;
return {
// Cannon
body: new CANNON.Body({
mass: 0.5, // kg
position: randomPosition(3, 7), // random pos from radius 3-8
shape: new CANNON.Sphere(radius)
}),
// THREE
mesh: new THREE.Mesh(
new THREE.SphereGeometry( radius, 32, 32 ),
new THREE.MeshPhongMaterial( { color: 0xdddd55, specular: 0x999999, shininess: 13} )
)
}
}
function randomPosition(innerRadius, outerRadius){
// get random direction
let x = (2 * Math.random() - 1 ),
y = (2 * Math.random() - 1 ),
z = (2 * Math.random() - 1 )
// create vector
let randVec = new CANNON.Vec3(x, y, z);
// normalize
randVec.normalize();
// scale it to the right radius
randVec = randVec.scale( Math.random() * (outerRadius - innerRadius) + innerRadius); //from inner to outer
return randVec;
}
Run Code Online (Sandbox Code Playgroud)
并使用它:
let scene = new THREE.Scene();
let world = new CANNON.World();
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 5;
let camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
let renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// create a Atom with 3 protons and neutrons, and 5 electrons
// all circulating position (-4, 0, 0)
let atom = Atom(3, 3, 5, new CANNON.Vec3(-4, 0, 0));
// move atom (will not be instant)
//atom.position.x = -2;
// add to THREE scene and CANNON world
atom.addToWorld(world, scene);
let light = new THREE.AmbientLight( 0x202020 ); // soft white light
scene.add( light );
let directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set( -1, 1, 1 );
scene.add( directionalLight );
camera.position.z = 18;
const timeStep = 1/60;
// give the atoms electrons some starting velocity
atom.electronStartingVelocity(2);
function render () {
requestAnimationFrame( render );
// calculate all the particles positions
atom.simulate();
// Step the physics world
world.step(timeStep);
//update the THREE mesh
atom.updateAtomMeshState();
renderer.render(scene, camera);
};
render();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1063 次 |
最近记录: |