代码仓
GitHub - TiffanyHoo/three_practices: Learning three.js together!
可自行clone,无需安装依赖,直接liver-server运行/直接打开chapter01中的html文件
运行效果图
知识要点
常见光照类型及其特点如下:
1. 环境光(AmbientLight)
• 特点:均匀照亮场景所有物体,不考虑光源位置,营造基础明暗氛围。
• 应用:常用于模拟间接光照(如室内墙壁反射光),需配合其他光源使用,避免场景过平。
• 示例:new THREE.AmbientLight(0x404040, 0.6)(颜色和强度可调整)。
2. 平行光(DirectionalLight)
• 特点:类似太阳光照,光线平行照射,方向固定,不受距离影响。
• 应用:模拟太阳光、大型场景主光源,可通过旋转调整光照方向。
• 示例:new THREE.DirectionalLight(0xffffff, 0.8),需设置direction属性(如指向地面)。
3. 点光源(PointLight)
• 特点:从单一位置向四周发散光线,光照强度随距离衰减。
• 应用:模拟灯泡、蜡烛等点光源效果,可通过distance和decay控制衰减范围。
• 示例:new THREE.PointLight(0xff0000, 1, 100)(红色光,强度1,有效距离100)。
4. 聚光灯(SpotLight)
• 特点:光线呈锥形发散,可控制照射角度、边缘柔和度等,类似手电筒。
• 应用:舞台灯光、局部重点照明,可通过angle(锥角)和penumbra(边缘模糊)调整效果。
• 示例:new THREE.SpotLight(0xffffff, 1, 100, Math.PI/4)(白光,强度1,锥角45度)。
5. 半球光(HemisphereLight)
• 特点:模拟天空和地面的光照,顶部为天空色,底部为地面色,光线柔和。
• 应用:户外场景自然光照(如蓝天与地面反射),参数包括天空色、地面色和强度。
• 示例:new THREE.HemisphereLight(0xaaaaaa, 0x444444, 1)(天空浅灰,地面深灰)。
关键参数对比
• 位置影响:平行光(方向)、点/聚光灯(位置),环境光/半球光无位置概念。
• 衰减特性:点/聚光灯支持距离衰减,平行光/环境光无衰减。
• 阴影支持:平行光和聚光灯可投射阴影(需开启castShadow),其他光源通常不支持。
通过组合不同光照类型,可实现复杂场景的光影效果,例如“平行光(主光源)+ 环境光(基础照明)+ 点光源(局部补光)”的搭配。
核心运行代码
<!DOCTYPE html><html><head><title>Example 03.02 - point Light</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {/* set margin to 0 and overflow to hidden, to go fullscreen */margin: 0;overflow: hidden;}</style>
</head><body><div id="Stats-output"></div><!-- Div which will hold the Output --><div id="WebGL-output"></div><!-- Javascript code that runs our Three.js examples --><script type="text/javascript">// once everything is loaded, we run our Three.js stuff.function init() {// create a scene, that will hold all our elements such as objects, cameras and lights.var scene = new THREE.Scene();// create a camera, which defines where we're looking at.var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);// create a render and set the sizevar renderer = new THREE.WebGLRenderer();// var renderer = new THREE.WebGLRenderer({alpha: true});/*** alpha: true 启用透明度支持* !!!透明度没有生效* 1.因为没有启用渲染器透明度支持* 2.没有正确使用setClearColor方法两个参数* renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));* 透明度 (0-1) 0 完全透明 1完全不透明**/renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));renderer.setSize(window.innerWidth, window.innerHeight);// renderer.shadowMapEnabled = true;// 启用阴影贴图:用于在3D场景中生成和渲染物体的阴影// create the ground planevar planeGeometry = new THREE.PlaneGeometry(60, 20, 20, 20);var planeMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff });var plane = new THREE.Mesh(planeGeometry, planeMaterial);plane.receiveShadow = true; // 接收阴影// rotate and position the planeplane.rotation.x = -0.5 * Math.PI;plane.position.x = 15;plane.position.y = 0;plane.position.z = 0;// add the plane to the scenescene.add(plane);// create a cubevar cubeGeometry = new THREE.BoxGeometry(4, 4, 4);var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff7777 });// MeshLambertMaterial 基于Lambert反射模型的材质,适用于不发光且没有高光的物体(表面粗糙、没有明显反光)。它支持颜色、贴图、透明度等属性。var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);cube.castShadow = true; // 投射阴影// position the cubecube.position.x = -4;cube.position.y = 3;cube.position.z = 0;// add the cube to the scenescene.add(cube);var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff });var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);// position the spheresphere.position.x = 20;sphere.position.y = 0;sphere.position.z = 2;sphere.castShadow = true;// add the sphere to the scenescene.add(sphere);// position and point the camera to the center of the scenecamera.position.x = -25;camera.position.y = 30;camera.position.z = 25;camera.lookAt(new THREE.Vector3(10, 0, 0));// 添加光源// add subtle ambient lightingvar ambiColor = "#0c0c0c";var ambientLight = new THREE.AmbientLight(ambiColor);scene.add(ambientLight);// add spotlight for the shadowsvar spotLight = new THREE.SpotLight(0xffffff);console.log(spotLight.position);spotLight.position.set(-40, 60, -10);spotLight.castShadow = true;console.log(spotLight);console.log(spotLight.target); // 默认(0,0,0)console.log(spotLight.shadow); // undefined shadow属性是在r128之后引入的// scene.add( spotLight );var pointColor = "#ccffcc";var pointLight = new THREE.PointLight(pointColor); // 无阴影pointLight.distance = 100; // 0 无限远 光线强度不随距离增加而减弱scene.add(pointLight);// add a small sphere simulating the pointlightvar sphereLight = new THREE.SphereGeometry(0.2);var sphereLightMaterial = new THREE.MeshBasicMaterial({ color: 0xac6c25 });var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);sphereLightMesh.castShadow = true;sphereLightMesh.position = new THREE.Vector3(3, 0, 3);scene.add(sphereLightMesh);// const directionalLight = new THREE.DirectionalLight(0xffffff, 1);// directionalLight.position.set(-40, 60, -10);// directionalLight.castShadow = true;// scene.add(directionalLight);// add the output of the renderer to the html elementdocument.getElementById("WebGL-output").appendChild(renderer.domElement);// call the render functionvar step = 0;// used to determine the switch point for the light animationvar invert = 1;var phase = 0;var controls = new function () {this.rotationSpeed = 0.03;this.bouncingSpeed = 0.03;this.ambientColor = ambiColor;this.pointColor = pointColor;this.intensity = 1;this.distance = 100;};var gui = new dat.GUI();gui.addColor(controls, 'ambientColor').onChange(function (e) {ambientLight.color = new THREE.Color(e);});gui.addColor(controls, 'pointColor').onChange(function (e) {pointLight.color = new THREE.Color(e);});gui.add(controls, 'intensity', 0, 3).onChange(function (e) {pointLight.intensity = e;});gui.add(controls, 'distance', 0, 100).onChange(function (e) {pointLight.distance = e;});var stats = initStats();render();function render() {stats.update();// rotate the cube around its axescube.rotation.x += controls.rotationSpeed;cube.rotation.y += controls.rotationSpeed;cube.rotation.z += controls.rotationSpeed;// bounce the sphere up and downstep += controls.bouncingSpeed;sphere.position.x = 20 + (10 * (Math.cos(step)));sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));// move the light simulationif (phase > 2 * Math.PI) {invert = invert * -1;phase -= 2 * Math.PI;} else {phase += controls.rotationSpeed;}sphereLightMesh.position.z = +(7 * (Math.sin(phase)));sphereLightMesh.position.x = +(14 * (Math.cos(phase)));sphereLightMesh.position.y = 5;if (invert < 0) {var pivot = 14;sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;}pointLight.position.copy(sphereLightMesh.position);// render using requestAnimationFramerequestAnimationFrame(render);renderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: ms// Align top-leftstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init</script>
</body></html>