我正在修补一个太阳系模拟器,除了一个部分外,它一切顺利:当月亮或行星落在其母体后面时,你仍然可以看到它!
场景中没有透明对象,我没有对渲染对象的顺序进行任何修改,所以我不知道为什么对象出现在另一个对象后面时会出现。
我正在使用three.js r71(问题仍然出现在r84中)。
要查看它出错的地方:查看http:mrhuffman.net/projects/gp并选择火星系统;你会看到Phobos或Deimos如何在火星背后仍然可见。
这是场景的代码。它不像我刚刚开始工作那样整洁,所以如果你需要澄清或有疑问,请拍!
import THREE from '../vendor/three';
import OrbitControls from '../vendor/OrbitControlsES6';
import ColladaLoader from '../vendor/ColladaLoaderES6';
import nBodyProblem from '../algorithms/nBodyProblem';
const scene = ( function () {
//Full screen action
let w = window.innerWidth;
let h = window.innerHeight;
let requestAnimationFrameId = null;
let scene = null;
let camera = null;
let controls = null;
let renderer = null;
let system = null;
let dae = null;
let cameraControlsWrapper = null;
let orbitButton = null;
let view3DButton = null;
let pathCanvas = document.createElement( 'canvas' );
pathCanvas.style.display = 'none';
pathCanvas.style.backgroundImage = 'url(misc/starfield.jpg)';
let ctxPath = pathCanvas.getContext( '2d' );
let massCanvas = document.createElement( 'canvas' );
massCanvas.style.display = 'none';
massCanvas.style.position = 'absolute';
massCanvas.style.zIndex = 2;
massCanvas.style.top = 0;
massCanvas.style.bottom = 0;
let ctxMass = massCanvas.getContext( '2d' );
pathCanvas.width = w;
pathCanvas.height = h;
massCanvas.width = w;
massCanvas.height = h;
ctxPath.translate( w / 2, h / 2 );
ctxMass.translate( w / 2, h / 2 );
function showOrbits() {
orbitButton.style.display = 'none';
cameraControlsWrapper.style.display = 'none';
pathCanvas.style.display = 'block';
massCanvas.style.display = 'block';
view3DButton.style.display = 'block';
}
function hideOrbits() {
view3DButton.style.display = 'none';
pathCanvas.style.display = 'none';
massCanvas.style.display = 'none';
orbitButton.style.display = 'block';
cameraControlsWrapper.style.display = 'block';
}
function createBody( radius, name, type ) {
let segments = type !== 'asteroid' ? 32 : 6;
let geometry = new THREE.SphereGeometry( radius, segments, segments );
let map;
let bumpMap;
switch( type ) {
case 'asteroid':
map = THREE.ImageUtils.loadTexture('textures/Phobos.jpg');
bumpMap = THREE.ImageUtils.loadTexture('textures/PhobosBump.jpg');
break;
case 'custom':
map = THREE.ImageUtils.loadTexture('textures/Acid.jpg');
break;
case 'star':
map = THREE.ImageUtils.loadTexture('textures/Sun.jpg');
break;
case 'spacecraft':
scene.add( dae );
return dae;
default:
map = THREE.ImageUtils.loadTexture('textures/' + name + '.jpg');
bumpMap = THREE.ImageUtils.loadTexture('textures/Phobos.jpg');
}
let material = new THREE.MeshPhongMaterial( { map: map, bumpMap: bumpMap, bumpScale: 0.02 } );
let mesh = new THREE.Mesh( geometry, material );
mesh.rotation.x = 1.5;
scene.add( mesh );
return mesh;
}
function sceneSetup( callback, scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls ) {
if ( scenario.model === undefined ) {
callback( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls );
return;
}
let loader = new ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( './models/' + scenario.model + '/' + scenario.model + '.dae', ( collada ) => {
dae = collada.scene;
dae.scale.setScalar( 1 / 800 );
callback( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls );
});
}
function initSimulation( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls ) {
cameraControlsWrapper = cameraControls;
orbitButton = viewOrbits;
orbitButton.addEventListener( 'click', showOrbits, false );
view3DButton = view3D;
view3DButton.addEventListener( 'click', hideOrbits, false );
hideOrbits();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, w / h, 0.000001, 1500 );
//Prevent rolling of the camera when you view a body from another
camera.up.set( 0, 0, 1 );
camera.position.set( 0, 90, 150 );
var light = new THREE.AmbientLight(0x404040);
scene.add(light);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(w, h);
renderer.setClearColor(0x000000);
container.appendChild( pathCanvas );
container.appendChild( massCanvas );
container.appendChild( renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
//Create a new n-body problem from the selected scenario
system = new nBodyProblem( {
g: scenario.g,
law: scenario.law,
dt: scenario.dt,
masses: scenario.masses
});
//Create visual manifestations of the planets, asteroids and star(s)
for (let i = 0; i < system.masses.length; i++) {
let mass = system.masses[ i ];
mass.manifestation = createBody( mass.radius, mass.name, mass.type );
}
const render = function () {
requestAnimationFrameId = requestAnimationFrame( render );
//Update state vectors system.updatePositionVectors().updateVelocityVectors().updateBarycenter().calculateElapsedTime();
//Check if a rocket should be fired and if so check if it should be fired in this iteration; should that be the case, fire!
if ( scenario.rocketBurn === true ) {
if ( system.elapsedTime === scenario.rocketBurnTime ) {
for ( let i = 0; i < system.masses.length; i++ ) {
if ( system.masses[ i ].type === 'spacecraft' ) {
system.masses[ i ].vx = scenario.afterRocketBurnVelocity.vx;
system.masses[ i ].vy = scenario.afterRocketBurnVelocity.vy;
system.masses[ i ].vz = scenario.afterRocketBurnVelocity.vz;
}
}
}
}
ctxMass.clearRect( -0.5 * w, -0.5 * h, w, h );
//Put all the masses in their new positions and set camera position and focus
for (let i = 0; i < system.masses.length; i++) {
let mass = system.masses[ i ];
let x = mass.x * scenario.scale;
let y = mass.y * scenario.scale;
let z = mass.z * scenario.scale;
mass.manifestation.position.set( x, y, z );
let camR = camPos.value;
let name = mass.name;
if ( camR === name ) {
camera.position.set( x, y, z + ( mass.radius * 1.2 ) );
controls.enabled = false;
} else if ( camR === 'free' ) {
controls.enabled = true;
}
if ( camFocus.value === name ) {
camera.lookAt( new THREE.Vector3( x, y, z ) );
//If the camera mode is free, the user can pan, orbit and have fun
if ( camPos === 'free' ) controls.target = new THREE.Vector3( x, y, z );
}
ctxPath.fillStyle = mass.color;
ctxPath.fillRect( x, y, 1, 1 );
ctxMass.beginPath();
ctxMass.fillStyle = mass.color;
ctxMass.arc( x, y, 6, 0, 2 * Math.PI );
ctxMass.fill();
ctxMass.font = "14px Arial";
ctxMass.fillText( mass.name, x + 8, y );
}
//Put the barycenter of the system in its new position
let barycenterX = system.x * scenario.scale;
let barycenterY = system.y * scenario.scale;
ctxMass.strokeStyle = 'limegreen';
ctxMass.lineWidth = 2;
ctxMass.beginPath();
ctxMass.moveTo( barycenterX - 20, barycenterY );
ctxMass.lineTo( barycenterX + 20, barycenterY );
ctxMass.moveTo( barycenterX, barycenterY - 20 );
ctxMass.lineTo( barycenterX, barycenterY + 20 );
ctxMass.stroke();
ctxMass.fillStyle = 'limegreen';
ctxMass.font = "14px Arial";
ctxMass.fillText( 'Barycenter', barycenterX, barycenterY - 25 );
renderer.render( scene, camera );
};
//Makes the scene responsive
//Note that traces are cleared when the size of the viewport changes
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
w = window.innerWidth;
h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize( w, h );
pathCanvas.width = w;
pathCanvas.height = h;
massCanvas.width = w;
massCanvas.height = h;
ctxPath.clearRect( -0.5 * w, -0.5 * h, w, h );
ctxMass.clearRect( -0.5 * w, -0.5 * h, w, h );
ctxPath.translate( w / 2, h / 2 );
ctxMass.translate( w / 2, h / 2 );
}
render();
}
//Tidy up
function resetSimulation() {
orbitButton.removeEventListener( 'click', showOrbits );
view3DButton.removeEventListener( 'click', hideOrbits );
cancelAnimationFrame( requestAnimationFrameId );
ctxPath.clearRect( -0.5 * w, -0.5 * h, w, h );
renderer.domElement.parentNode.removeChild( renderer.domElement );
pathCanvas.parentNode.removeChild( pathCanvas );
massCanvas.parentNode.removeChild( massCanvas );
}
//API
return {
startSimulation: ( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls ) => {
sceneSetup( initSimulation, scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls );
},
resetSimulation: resetSimulation
};
}());
export default scene;