javascript - THREE.js 水反射出现故障

标签 javascript three.js

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是代码笔。

感谢任何帮助。 提前致谢

最佳答案

感谢您分享代码笔。这实际上是 Water 中的一个错误,应在下一版本 R116 中修复。

我已在此处更新了您的代码笔并修复了:https://jsfiddle.net/q2cemtb0/1/

GitHub 上的相应 PR:https://github.com/mrdoob/three.js/pull/19016

关于javascript - THREE.js 水反射出现故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60975017/

相关文章:

javascript - 有哪些方法可以降低 Angular Controller 的复杂性(使用 ui-router)?

javascript - 在特定表中查找所有带属性的 TD(按 ID)

javascript - Three.js - 一次加载 JSON 模型并多次添加

javascript - Three.js:平滑非索引 BufferGeometry 上的法线

javascript - Traverse 未定义且性能落后 THREE.js 时钟? *虽然它有效*

html - 将 Three.js 场景与网页结合作为背景

javascript - TypeScript 中 'this' 的作用域

javascript - 缩短代码并进行表单验证

javascript - 在其布局完全安装在 Nuxt 中后呈现页面

javascript - 在 THREE.JS 中手动对 Matrix4 应用旋转和平移