js用于制作水景。我按照官方示例创建了场景,但是在加载外部GLTF模型后,我注意到反射效果不佳。
在第一帧中一切正常,但是一旦我移动相机,一切都会出错。
我认为这是由于我自己的摄像机运动代码所致,但我不明白为什么。
这是代码:
let div = document.body.children[0];
let rect = div.getBoundingClientRect();
// create scene
let scene = new THREE.Scene();
// load boat model
{
let loader = new THREE.GLTFLoader();
// load a glTF resource
loader.load(
// resource URL
"https://raw.githubusercontent.com/mrdoob/three.js/master/examples/models/gltf/Duck/glTF/Duck.gltf",
// called when the resource is loaded
function (gltf) {
let duck = gltf.scene.children[0];
scene.add(duck);
},
// called while loading is progressing
function (xhr) {
console.log(xhr, (xhr.loaded / xhr.total * 100) + "% loaded");
},
// called when loading has errors
function (error) {
console.log("An error happened", error);
}
);
}
// create camera pivot to orbit around center
let cameraHorizontal = new THREE.Object3D();
let cameraVertical = new THREE.Object3D();
let cameraPlaceholder = new THREE.Object3D();
cameraPlaceholder.position.z = 10;
cameraVertical.add(cameraPlaceholder);
cameraVertical.rotation.x = -.2;
cameraHorizontal.add(cameraVertical);
cameraHorizontal.updateMatrixWorld(true);
let camera = new THREE.PerspectiveCamera(75, rect.width/rect.height, 0.1, 1000);
function updateCamera() {
let worldPosition = cameraPlaceholder.getWorldPosition();
camera.position.copy(worldPosition);
let worldQuaternion = cameraPlaceholder.getWorldQuaternion();
camera.setRotationFromQuaternion(worldQuaternion);
camera.updateProjectionMatrix();
}
// create light
let light = new THREE.DirectionalLight(0xffffff, 0.8);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff));
// create water
let waterGeometry = new THREE.PlaneBufferGeometry(10000, 10000);
let water = new THREE.Water(
waterGeometry,
{
textureWidth: 2048,
textureHeight: 2048,
waterNormals: new THREE.TextureLoader().load("https://rawgit.com/mrdoob/three.js/master/examples/textures/waternormals.jpg", function (texture) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
}),
alpha: 0,
sunDirection: light.position.clone().normalize(),
sunColor: 0xffffff,
waterColor: 0x001e0f,
distortionScale: 0,
fog: scene.fog !== undefined
}
);
water.rotation.x = -Math.PI / 2;
water.matrixAutoUpdate = false;
water.rotationAutoUpdate = false;
water.updateMatrix();
scene.add(water);
// create skybox
let sky = new THREE.Sky();
let uniforms = sky.material.uniforms;
uniforms.turbidity.value = 10;
uniforms.rayleigh.value = 2;
uniforms.luminance.value = 1;
uniforms.mieCoefficient.value = 0.005;
uniforms.mieDirectionalG.value = 0.8;
let parameters = {
distance: 400,
inclination: 0.2,
azimuth: 0.205
};
let cubeCamera = new THREE.CubeCamera(0.1, 1, 512);
cubeCamera.renderTarget.texture.generateMipmaps = true;
cubeCamera.renderTarget.texture.minFilter = THREE.LinearMipmapLinearFilter;
scene.background = cubeCamera.renderTarget;
// create renderer
let renderer = new THREE.WebGLRenderer();
renderer.setSize(rect.width, rect.height);
div.appendChild(renderer.domElement);
function updateSun() {
let theta = Math.PI * (parameters.inclination - 0.5);
let phi = 2 * Math.PI * (parameters.azimuth - 0.5);
light.position.x = parameters.distance * Math.cos(phi);
light.position.y = parameters.distance * Math.sin(phi) * Math.sin(theta);
light.position.z = parameters.distance * Math.sin(phi) * Math.cos(theta);
sky.material.uniforms.sunPosition.value = light.position.copy(light.position);
water.material.uniforms.sunDirection.value.copy(light.position).normalize();
cubeCamera.update(renderer, sky);
}
updateSun();
// add event listeners for rotate camera
let movingWith = null;
renderer.domElement.addEventListener("pointerdown", event => {
if (movingWith != null) {
return;
}
event.preventDefault();
movingWith = event.pointerId;
function onmove(event) {
if (event.pointerId !== movingWith) {
return;
}
event.preventDefault();
cameraVertical.rotation.x = Math.max(Math.min(cameraVertical.rotation.x - (event.movementY / 50), -.01), -(Math.PI / 2) + .2);
cameraHorizontal.rotation.y = (cameraHorizontal.rotation.y - (event.movementX / 50)) % (2 * Math.PI);
cameraHorizontal.updateMatrixWorld(true);
}
window.addEventListener("pointermove", onmove);
window.addEventListener("pointerup", function onup() {
if (event.pointerId !== movingWith) {
return;
}
event.preventDefault();
window.removeEventListener("pointermove", onmove);
window.removeEventListener("pointerup", onup);
movingWith = null;
})
});
let lastTime;
let animate = function () {
let now = Date.now();
let deltaTime = (now - lastTime) / 1000;
lastTime = now;
water.material.uniforms.time.value += deltaTime;
updateCamera();
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
lastTime = Date.now();
animate();
// resize canvas with window
window.addEventListener("resize", this._onresize = () => {
let rect = div.getBoundingClientRect();
renderer.setSize(rect.width, rect.height);
camera.aspect = rect.width / rect.height;
camera.updateProjectionMatrix();
});
Here是密码笔。
感谢您的帮助。 预先感谢
答案 0 :(得分:3)
感谢您分享Codepen。这实际上是Water
中的一个错误,应该在下一发行版R116
中进行修复。
我在此处使用以下修复程序更新了您的Codepen:https://jsfiddle.net/q2cemtb0/1/
GitHub上的相应PR:https://github.com/mrdoob/three.js/pull/19016