代碼倉
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>