旋转相机后,Three.js的skybox似乎坏了

Three.js skybox seems broken after rotating camera

本文关键字:skybox 坏了 js 相机 Three 旋转      更新时间:2023-09-26

js和我正在尝试基于这个演示创建一个简单的skybox。到目前为止,一切似乎都很好,除了一件事,当我旋转相机时(我使用的是orbitControl.js),z值不是可能的最小值,然后纹理表现得很奇怪,看起来很破碎。

来源:

var camera, scene, renderer, controls, skybox;
var toRadians = function(deg) {
    return deg * Math.PI / 180
}
var toDegrees = function(radians) {
    return radians * (180 / Math.PI);
}
var init = function() {
    // scene
    scene = new THREE.Scene();
    scene.fog = new THREE.FogExp2( 0xffffff, 0.00010);
    // camera
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
    camera.position.z = 5000;
    scene.add( camera );

    // skydome
    var urlPrefix = "http://three.dev/skybox/textures/";
    var urls = [urlPrefix + "px.png", urlPrefix + "nx.png",
                urlPrefix + "py.png", urlPrefix + "ny.png",
                urlPrefix + "pz.png", urlPrefix + "nz.png"];
    var textureCube = THREE.ImageUtils.loadTextureCube( urls );
    var shader = THREE.ShaderLib[ "cube" ];
    shader.uniforms[ "tCube" ].value = textureCube;
    var material = new THREE.ShaderMaterial( {
        fragmentShader: shader.fragmentShader,
        vertexShader: shader.vertexShader,
        uniforms: shader.uniforms,
        depthWrite: false,
        side: THREE.BackSide
    } ),
    skybox = new THREE.Mesh( new THREE.BoxGeometry( 10000, 10000, 10000 ), material );
    scene.add( skybox );
    //var texture = THREE.ImageUtils.loadTexture( 'http://three.dev/skybox/textures/wood.jpg')
    //var paintMaterial = new THREE.MeshBasicMaterial({map: textureCube})
    // var lightAmb = new THREE.AmbientLight(0x333333); 
    // lightAmb.position.set( 0,0,0 );
    // scene.add(lightAmb);

    // var directionalLightTop = new THREE.DirectionalLight( 0xffffff, 1 );
    // directionalLightTop.position.set( 0, 0, 0 ).normalize();
    // scene.add( directionalLightTop );    
    // var color = new THREE.Color("rgb(255,0,0)");
    // var pointLightRed = new THREE.PointLight(color, 1, 8000);
    //  pointLightRed.position.set( 0, 0, 0);
    //  camera.add( pointLightRed );        

    // renderer
    renderer = new THREE.WebGLRenderer( {alpha: true, antialias: true} );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setClearColor( 0xffffff, 1 );
    renderer.autoClear = false;
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.rotateSpeed = 0.5;
    controls.minDistance = 500;
    controls.maxDistance = 6000;
    document.body.appendChild( renderer.domElement );
    window.addEventListener( 'resize', onWindowResize, false );
    // start rendering
    render();
}
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
  render();
}
var update = function() {
}
var render = function() {
    update();
    controls.update();
    requestAnimationFrame( render );
    renderer.render(scene, camera);
}
window.onload = function(){
    init();
}

您正在"主"场景中添加一个skybox。一个更好的方法来完成一个天空穹顶将是创建一个新的场景。这将是"主"场景的"背景"。还有一个关于skydomes与skyboxes的讨论,简单地说,一个盒子可以节省多边形,一个圆顶看起来更好。在这个例子中,我将使用一个圆顶/球体。

var renderer = new THREE.WebGLRenderer( {alpha: true, antialias: true} );
var mainScene = new THREE.Scene();
var mainCamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
var skydome = {
    scene: new THREE.Scene(),
    camera: new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
};
skydome.material = new THREE.MeshBasicMaterial({color: 0x0F0F0F}) //the material for the skydome, for sake of lazyness i took a MeshBasicMaterial.
skydome.mesh = new THREE.Mesh(new THREE.SphereGeometry(100, 20, 20), skydome.material);
skydome.scene.add(skydome.mesh);

现在,在渲染功能期间,只调整skydome摄影机的旋转,而不调整位置。

var render = function(){
    requestAnimationFrame( render );
    skydome.camera.quaternion = mainCamera.quaternion;
    renderer.render(skydome.scene, skydome.camera); //first render the skydome
    renderer.render(mainScene, mainCamera);//then render the rest over the skydome
};
renderer.autoclear = false; //otherwise only the main scene will be rendered.