Search code examples
javascriptthree.jseuler-angles

Cube cannot do a full rotation on the Y axis in three.js


I have a low poly world and I added "gravity" with raycasting to my character. Now I need to add another raycaster in front of the character (in this case the pointer lock controls) pointing forwards (always in front of the camera and in facing the same direction) to give my character the ability to walk on a non-flat surface.

Concept

In the photo shown as 'b' being the raycaster. Then I would use trigonometry to calculate the slope in order to know if it's possible to walk there, if it is, then I would just use the offset; 'a' and the distance from the character to the intersection called 'b' to translate the camera on its local Y and Z axis.

So I started testing and came up with this:

#blocker {
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,0.5);
}

#instructions {
    width: 100%;
    height: 100%;

    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    text-align: center;
    font-size: 14px;
    cursor: pointer;
}
    <div id="blocker">
        <div id="instructions">
            <p style="font-size:36px">
                Click to play
            </p>
        </div>
    </div>

<script type="module">

 import * as THREE from "https://cdn.skypack.dev/[email protected]";
 
import {PointerLockControls} from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/PointerLockControls";

  let scene = new THREE.Scene();
  
  let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
  camera.position.set(0, 8, 13);
  
  let renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setSize(innerWidth, innerHeight);
  renderer.setClearColor(0x404040);
  document.body.appendChild(renderer.domElement);
  
  window.addEventListener("resize", () => {
    camera.aspect = innerWidth / innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(innerWidth, innerHeight);
  })

  const controls = new PointerLockControls( camera, document.body );

  const blocker = document.getElementById( 'blocker' );
  const instructions = document.getElementById( 'instructions' );

  instructions.addEventListener( 'click', function () {

    controls.lock();

  } );

  controls.addEventListener( 'lock', function () {

    instructions.style.display = 'none';
    blocker.style.display = 'none';

  } );

  controls.addEventListener( 'unlock', function () {

    blocker.style.display = 'block';
    instructions.style.display = '';

  } );
  
  scene.add( controls.getObject() );

  const geometry = new THREE.BoxGeometry( 1, 1, 1 );
  const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
  let cube = new THREE.Mesh( geometry, material );
  scene.add( cube );

  function animate(){
    renderer.render(scene,camera)
    cube.position.copy(controls.getObject().position)
    cube.rotation.y = controls.getObject().rotation.y
    cube.translateZ(-10)
  }
  animate();
</script>

I don't know why Pointer Lock is not working with snippets... I probably did something wrong but I couldn't either find a Fiddle or Codepen with it so here is a video that shows clearly the issue. As you see, the cube cannot do a full rotation, it works well for a side but when I turn to the other the cube just goes on the other direction. The code relevant to this issue is mainly these 3 lines:

        cube.position.copy(controls.getObject().position)
        cube.rotation.y = controls.getObject().rotation.y
        cube.translateZ(-10)

Solution

  • SOLUTION: I had to convert the angle to radians as I was applying degrees onto the radians-based mesh rotation.