I’m learning about three.js.
I make a example to practise but the shadow of the items is looking wrong or stranger.
Should be like this (this image is of a old tutorial):
And the code is this:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script> <div id="WebGL-salida"> </div> <script type="text/javascript"> $(function() { var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); var color = new THREE.Color("rgb(200, 250, 250)"); renderer.setClearColor(new THREE.Color(color)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap var ejesAyuda = new THREE.AxesHelper(20); //son los ejes de ayuda creo scene.add(ejesAyuda); var planeGeometry = new THREE.PlaneGeometry(60, 20); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.receiveShadow = true; plane.rotation.x = -0.5 * Math.PI; // -90º plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; scene.add(plane); var cubeGeometry = new THREE.CubeGeometry(4, 4, 4); var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; //con esto le indicamos que queremos que emita sombra cube.position.x = -4; cube.position.y = 3; cube.position.z = 0; scene.add(cube); var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff }); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); sphere.castShadow = true; //con esto le indicamos que queremos que emita sombra sphere.position.x = 20; sphere.position.y = 4; sphere.position.z = 2; scene.add(sphere); camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); var spotLight = new THREE.SpotLight(0xffffff, 0.8); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; scene.add(spotLight); $("#WebGL-salida").append(renderer.domElement); renderer.render(scene, camera); }); </script>
And please, if you know about a good beginner three.js tutorial or course (I don’t care if it isn’t free), tell me, because i’m a bit lost in this and like web developer i’m interested in this webGL world 🙂
Advertisement
Answer
You can improve the quality of the shadow by increasing the size (and thus the resolution) of the shadow map (See SpotLight
):
var spotLight = new THREE.SpotLight(0xffffff, 0.8); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; spotLight.shadow.mapSize.width = 2048; spotLight.shadow.mapSize.height = 2048;
The quality can be further increased by restricting the light cone angle of the spotlight
spotLight.angle = Math.PI / 8.0;
These two enhancements together have the effect of increasing the resolution of the shadow map and decreasing the area to which the shadow map is mapped. As a result, more pixels of the shadow map are projected onto less area of the scene and the quality is improved.
See the code snippet:
var renderer, camera, scene, controls; var init = function (){ scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera (45, window.innerWidth/window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer(); controls = new THREE.OrbitControls( camera, renderer.domElement ); var color = new THREE.Color("rgb(200, 250, 250)"); renderer.setClearColor(new THREE.Color(color)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap var ejesAyuda = new THREE.AxesHelper(20); //son los ejes de ayuda creo scene.add(ejesAyuda); var planeGeometry = new THREE.PlaneGeometry(60, 20); var planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc}); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.receiveShadow = true; plane.rotation.x = -0.5*Math.PI; // -90º plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; scene.add(plane); var cubeGeometry = new THREE.BoxGeometry( 4, 4, 4); var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000}); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; //con esto le indicamos que queremos que emita sombra cube.position.x= -4; cube.position.y = 3; cube.position.z = 0; scene.add(cube); var sphereGeometry = new THREE.SphereGeometry (4, 20, 20); var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff}); var sphere = new THREE.Mesh (sphereGeometry, sphereMaterial); sphere.castShadow = true; //con esto le indicamos que queremos que emita sombra sphere.position.x = 20; sphere.position.y = 4; sphere.position.z = 2; scene.add(sphere); camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); var spotLight = new THREE.SpotLight(0xffffff, 0.8); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; spotLight.angle = Math.PI / 8.0; spotLight.shadow.mapSize.width = 2048; spotLight.shadow.mapSize.height = 2048; scene.add(spotLight); document.getElementById("WebGL-salida").append(renderer.domElement); resize(); window.onresize = resize; }; function animate() { requestAnimationFrame( animate ); renderer.render( scene, camera ); } function resize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); //controls.handleResize(); } init(); animate();
<!--script src="https://threejs.org/build/three.min.js"></script--> <!--script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script--> <script src="https://cdn.jsdelivr.net/npm/three@0.146/build/three.js"></script> <script src="https://cdn.jsdelivr.net/npm/three@0.146/examples/js/controls/OrbitControls.js"></script> <div id="WebGL-salida"> </div>