【threejs】每天一个小案例讲解:创建基本的3D场景

代码仓

GitHub - TiffanyHoo/three_practices: Learning three.js together!

可自行clone,无需安装依赖,直接liver-server运行/直接打开chapter01中的html文件

运行效果图

知识要点

核心运行代码

javascript 复制代码
<!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 size
            var 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 plane
            var 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 plane
            plane.rotation.x = -0.5 * Math.PI;
            plane.position.x = 15;
            plane.position.y = 0;
            plane.position.z = 0;

            // add the plane to the scene
            scene.add(plane);

            // create a cube
            var 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 cube
            cube.position.x = -4;
            cube.position.y = 3;
            cube.position.z = 0;

            // add the cube to the scene
            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);

            // position the sphere
            sphere.position.x = 20;
            sphere.position.y = 0;
            sphere.position.z = 2;
            sphere.castShadow = true;

            // add the sphere to the scene
            scene.add(sphere);

            // position and point the camera to the center of the scene
            camera.position.x = -25;
            camera.position.y = 30;
            camera.position.z = 25;
            camera.lookAt(new THREE.Vector3(10, 0, 0));

            // 添加光源
            // add subtle ambient lighting
            var ambiColor = "#0c0c0c";
            var ambientLight = new THREE.AmbientLight(ambiColor);
            scene.add(ambientLight);

            // add spotlight for the shadows
            var 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 pointlight
            var 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 element
            document.getElementById("WebGL-output").appendChild(renderer.domElement);

            // call the render function
            var step = 0;

            // used to determine the switch point for the light animation
            var 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 axes
                cube.rotation.x += controls.rotationSpeed;
                cube.rotation.y += controls.rotationSpeed;
                cube.rotation.z += controls.rotationSpeed;

                // bounce the sphere up and down
                step += controls.bouncingSpeed;
                sphere.position.x = 20 + (10 * (Math.cos(step)));
                sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));

                // move the light simulation
                if (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 requestAnimationFrame
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }

            function initStats() {

                var stats = new Stats();

                stats.setMode(0); // 0: fps, 1: ms

                // Align top-left
                stats.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>
相关推荐
做cv的小昊2 小时前
结合代码读3DGS&世界模型论文(3)——3DGS & 世界模型新工作GaussianDream论文及代码解读
3d
lilian23321 小时前
HarmonyOS 7 新特性(十三)|3DGS 模型加载、交互与性能回退
3d·交互·harmonyos
DolitD1 天前
云流技术深度剖析:单服务器下如何实现3D应用的多实例并发?
java·服务器·前端·3d·云原生·云计算
Liudef061 天前
腾讯混元Hunyuan3D-Part:重新定义3D部件生成的革命性架构
人工智能·3d·架构·腾讯混元hunyuan3d
2601_967659892 天前
大学实训室网络仿真环境搭建:Ranplan 3D射线跟踪双版本技术解析
网络·3d
七77.2 天前
SceneAssistant: A Visual Feedback Agent for Open-Vocabulary 3D Scene Generation
3d·agent·世界模型
rockingdingo3 天前
Codex Claude 智能体做3D/潮玩/IP设计——装上Craftsman Agent工匠智能体Skills 游泳男孩IP案例分享
网络协议·tcp/ip·3d
3D可视化大侠3 天前
数字孪生时空数据可视化:CIMPro 孪大师中的轨迹与粒子实现
3d·信息可视化
LONGZETECH3 天前
新能源汽车动力电池实训教学痛点与虚拟仿真技术解决方案
c语言·3d·unity·架构·汽车·汽车教学软件
爱分享的康康3 天前
从“识别已知”到“发现未知”:3D通用目标检测如何打开智驾感知新边界
人工智能·目标检测·3d