threeJs实现裸眼3D小狗

发布于:2025-04-11 ⋅ 阅读:(26) ⋅ 点赞:(0)

一、实现效果

使用threeJs实现裸眼3D小狗,效果如下,其实如果将小狗换成建模小狗,效果更好,这个是模拟了一只小狗。

二、实现代码

代码如下:

<!DOCTYPE html>
<html>
<head>
    <title>星空小狗</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
    <script>
        // 初始化场景、相机和渲染器
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        //renderer.setClearColor(0x000000); // 黑色背景
        document.body.appendChild(renderer.domElement);

        // 添加星空背景
        function createStarField() {
            const starsGeometry = new THREE.BufferGeometry();
            const starCount = 5000;
            const positions = new Float32Array(starCount * 3);

            for(let i = 0; i < starCount * 3; i += 3) {
                positions[i] = (Math.random() - 0.5) * 2000;
                positions[i+1] = (Math.random() - 0.5) * 2000;
                positions[i+2] = (Math.random() - 0.5) * 2000;
            }

            starsGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
            const starsMaterial = new THREE.PointsMaterial({
                color: 0xFFFFFF,
                size: 0.7,
                transparent: true
            });
            const starField = new THREE.Points(starsGeometry, starsMaterial);
            scene.add(starField);
        }
        createStarField();

        // 光源配置
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(0, 100, 50);
        scene.add(directionalLight);

        // 创建小狗模型
        function createDog() {
            const dog = new THREE.Group();

            // 身体
            const bodyGeometry = new THREE.CylinderGeometry(1, 1, 2, 8);
            const bodyMaterial = new THREE.MeshPhongMaterial({ color: 0x8B4513 });
            const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
            body.rotation.z = Math.PI/2;
            dog.add(body);

            // 头部
            const headGeometry = new THREE.SphereGeometry(0.8);
            const head = new THREE.Mesh(headGeometry, bodyMaterial);
            head.position.set(1.5, 0, 0);
            dog.add(head);

            // 眼睛
            const eyeGeometry = new THREE.SphereGeometry(0.1);
            const eyeMaterial = new THREE.MeshPhongMaterial({ color: 0x000000 });
            const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
            const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial);
            leftEye.position.set(0.7, 0.3, 0.3);
            rightEye.position.set(0.7, 0.3, -0.3);
            head.add(leftEye, rightEye);

            // 鼻子
            const nose = new THREE.Mesh(
                new THREE.SphereGeometry(0.2),
                new THREE.MeshPhongMaterial({ color: 0x000000 })
            );
            nose.position.set(0.7, 0, 0);
            head.add(nose);

            // 耳朵
            const earGeometry = new THREE.ConeGeometry(0.3, 0.8, 8);
            const earMaterial = new THREE.MeshPhongMaterial({ color: 0x4B3621 });
            const leftEar = new THREE.Mesh(earGeometry, earMaterial);
            const rightEar = new THREE.Mesh(earGeometry, earMaterial);
            leftEar.position.set(1.2, 0.6, 0.4);
            rightEar.position.set(1.2, 0.6, -0.4);
            leftEar.rotation.z = -0.3;
            rightEar.rotation.z = 0.3;
            dog.add(leftEar, rightEar);

            // 腿
            const legGeometry = new THREE.CylinderGeometry(0.2, 0.2, 1);
            const legs = [
                [0.5, -1.2, 0.5],   // 前左
                [0.5, -1.2, -0.5],  // 前右
                [-0.5, -1.2, 0.5],  // 后左
                [-0.5, -1.2, -0.5]  // 后右
            ];
            legs.forEach(pos => {
                const leg = new THREE.Mesh(legGeometry, bodyMaterial);
                leg.position.set(...pos);
                dog.add(leg);
            });

            // 尾巴
            const tailGeometry = new THREE.CylinderGeometry(0.1, 0.05, 1);
            const tail = new THREE.Mesh(tailGeometry, bodyMaterial);
            tail.position.set(-1.2, -0.5, 0);
            tail.rotation.z = -0.5;
			tail.rotation.x = 10;
            dog.add(tail);

            return dog;
        }

        const dog = createDog();
        scene.add(dog);

        // 相机初始位置
        camera.position.set(0, 3, 8);
        camera.lookAt(0, 0, 0);

        // 轨道控制器
        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            
            // 尾巴摆动
            dog.children[8].rotation.x = Math.sin(Date.now() * 0.005) * 0.5 - 0.5;
            
            controls.update();
            renderer.render(scene, camera);
        }

        // 窗口自适应
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        animate();
    </script>
</body>
</html>

这个示例创建了一个由基本几何体组成的卡通风格3D小狗,包含以下特征:

  1. 使用圆柱体作为身体和四肢

  2. 球体作为头部

  3. 圆锥体作为耳朵

  4. 黑色小球作为鼻子,眼睛

  5. 简单的摇尾巴动画

  6. 支持鼠标控制视角(旋转、缩放)

  7. 响应式布局(自动适应窗口大小)

使用方法:

  1. 将代码保存为HTML文件

  2. 用现代浏览器打开

  3. 你可以通过鼠标:

    • 左键拖动旋转视角

    • 右键拖动平移视角

    • 滚轮缩放

可以调整的部分:

  • 颜色值(修改各个材质的color参数)

  • 几何体尺寸(修改各个Geometry的参数)

  • 动画效果(修改animate函数中的变换参数)

  • 光照参数(调整光源位置和强度)

要创建更逼真的模型,可以考虑:

  1. 使用更复杂的几何体

  2. 添加纹理贴图

  3. 使用3D建模软件创建模型后导入

  4. 添加骨骼动画系统

  5. 增加更多细节(眼睛、毛发等)

三、重点代码片段讲解

片段1:小狗的组(group)创建与部件组合

function createDog() {
    const dog = new THREE.Group();

    // 身体 (圆柱体)
    const bodyGeometry = new THREE.CylinderGeometry(1, 1, 2, 8);
    const bodyMaterial = new THREE.MeshPhongMaterial({ color: 0x8B4513 });
    const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
    body.rotation.z = Math.PI/2; // 让圆柱体横置
    dog.add(body);

    // 头部 (球体)
    const head = new THREE.Mesh(
        new THREE.SphereGeometry(0.8),
        new THREE.MeshPhongMaterial({ color: 0x8B4513 })
    );
    head.position.set(1.5, 0, 0); // 向右偏移
    dog.add(head);

    // 其他部件...
    return dog;
}

重点解析:

  1. 组(Group)对象

    • THREE.Group() 创建了一个空容器,用于组合所有小狗部件

    • 类似于HTML中的<div>容器,可以统一控制所有子元素的位置/旋转/缩放

  2. 坐标系操作

    • body.rotation.z = Math.PI/2 将圆柱体旋转90度,使其水平放置

    • head.position.set(1.5, 0, 0) 将头部定位在身体右侧(Three.js坐标系:x右,y上,z屏幕外)

  3. 部件层级关系

    • 通过dog.add()将各个身体部件添加到组中

    • 最终返回的dog对象包含所有子部件的完整层级结构

片段2:动画循环与尾巴摆动

function animate() {
    requestAnimationFrame(animate);
    
    // 摇尾巴动画
    dog.children[8].rotation.z = Math.sin(Date.now() * 0.005) * 0.5 - 0.5;
    
    controls.update();
    renderer.render(scene, camera);
}

重点解析:

  1. 动画循环机制

    • requestAnimationFrame 是浏览器提供的动画API,以约60fps的频率循环调用animate函数

    • 每次循环都会重新渲染场景(renderer.render)

  2. 数学函数实现动画

    • Math.sin(Date.now() * 0.005) 通过正弦函数生成周期性数值

    • *0.5 -0.5 将数值范围从[-1,1]映射到[-1,0],实现尾巴摆动效果

    • 随时间变化的参数 (Date.now()) 驱动动画持续进行

  3. 部件索引访问

    • dog.children[6] 访问之前添加到组中的第7个元素(尾巴)

    • 通过修改rotation.z实现绕z轴旋转(Three.js使用右手坐标系)


补充说明:

  • 这两个片段分别代表了Three.js的:

    1. 场景构建:通过组合基本几何体创建复杂模型

    2. 动态交互:使用数学函数驱动动画变化

  • 实际开发中可以通过给部件命名(而不是使用children索引)来更安全地访问特定部件

  • 通过调整正弦函数的参数(如将0.005改为0.01),可以改变尾巴摆动的速度

可以尝试修改这些参数观察效果变化,这是理解Three.js动画原理的最佳实践方式!


网站公告

今日签到

点亮在社区的每一天
去签到