欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Three.js骨骼笔记

程序员文章站 2022-03-26 14:40:31
...

Three.js骨骼笔记

版权声明:本文为CSDN博主「郭隆邦技术博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014291990/article/details/103353337

参考自郭隆邦老师的笔记,点击跳转

郭隆邦老师提供的代码,相信也有小伙伴没运行出来
稍作修改,能运行出个样子,但是还有报错
用代码的小伙伴记得修改js的url

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="/three.js/three.js"></script>
    <script src="/three.js/OrbitControls.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>

    <script>
        /**
         * 创建场景对象
         */
        var scene = new THREE.Scene();
        /**
         * 创建网格模型
         */
        //var geometry=new THREE.OctahedronGeometry(60);//创建一个立方体几何对象

        /**
 * 创建骨骼网格模型SkinnedMesh
 */
        // 创建一个圆柱几何体,高度120,顶点坐标y分量范围[-60,60]
        var geometry = new THREE.CylinderGeometry(5, 10, 120, 50, 300);
        geometry.translate(0, 60, 0); //平移后,y分量范围[0,120]
        console.log("name", geometry.vertices); //控制台查看顶点坐标
        //
        /**
         * 设置几何体对象Geometry的蒙皮索引skinIndices、权重skinWeights属性
         * 实现一个模拟腿部骨骼运动的效果
         */
        //遍历几何体顶点,为每一个顶点设置蒙皮索引、权重属性
        //根据y来分段,0~60一段、60~100一段、100~120一段
        for (var i = 0; i < geometry.vertices.length; i++) {
            var vertex = geometry.vertices[i]; //第i个顶点
            if (vertex.y <= 60) {
                // 设置每个顶点蒙皮索引属性  受根关节Bone1影响
                geometry.skinIndices.push(new THREE.Vector4(0, 0, 0, 0));
                // 设置每个顶点蒙皮权重属性
                // 影响该顶点关节Bone1对应权重是1-vertex.y/60
                geometry.skinWeights.push(new THREE.Vector4(1 - vertex.y / 1000, 0, 0, 0));
            } else if (60 < vertex.y && vertex.y <= 60 + 40) {
                // Vector4(1, 0, 0, 0)表示对应顶点受关节Bone2影响
                geometry.skinIndices.push(new THREE.Vector4(1, 0, 0, 0));
                // 影响该顶点关节Bone2对应权重是1-(vertex.y-60)/40
                geometry.skinWeights.push(new THREE.Vector4(1 - (vertex.y - 60) / 1000, 0, 0, 0));
            } else if (60 + 40 < vertex.y && vertex.y <= 60 + 40 + 20) {
                // Vector4(2, 0, 0, 0)表示对应顶点受关节Bone3影响
                geometry.skinIndices.push(new THREE.Vector4(2, 0, 0, 0));
                // 影响该顶点关节Bone3对应权重是1-(vertex.y-100)/20
                geometry.skinWeights.push(new THREE.Vector4(1 - (vertex.y - 100) / 1000, 0, 0, 0));
            }
        }
        // 材质对象
        var material = new THREE.MeshPhongMaterial({
            skinning: true, //允许蒙皮动画
            // wireframe:true,
        });
        // 创建骨骼网格模型
        var SkinnedMesh = new THREE.SkinnedMesh(geometry, material);
        SkinnedMesh.position.set(50, 120, 50); //设置网格模型位置
        SkinnedMesh.rotateX(Math.PI); //旋转网格模型
        scene.add(SkinnedMesh); //网格模型添加到场景中

        /**
         * 骨骼系统
         */
        var Bone1 = new THREE.Bone(); //关节1,用来作为根关节
        var Bone2 = new THREE.Bone(); //关节2
        var Bone3 = new THREE.Bone(); //关节3
        // 设置关节父子关系   多个骨头关节构成一个树结构
        Bone1.add(Bone2);
        Bone2.add(Bone3);
        // 设置关节之间的相对位置
        //根关节Bone1默认位置是(0,0,0)
        Bone2.position.y = 60; //Bone2相对父对象Bone1位置
        Bone3.position.y = 40; //Bone3相对父对象Bone2位置

        // 所有Bone对象插入到Skeleton中,全部设置为.bones属性的元素
        var skeleton = new THREE.Skeleton([Bone1, Bone2, Bone3]); //创建骨骼系统
        // console.log(skeleton.bones);
        // 返回所有关节的世界坐标
        // skeleton.bones.forEach(elem => {
        //   console.log(elem.getWorldPosition(new THREE.Vector3()));
        // });
        //骨骼关联网格模型
        SkinnedMesh.add(Bone1); //根骨头关节添加到网格模型
        SkinnedMesh.bind(skeleton); //网格模型绑定到骨骼系统
        console.log(SkinnedMesh);
        /**
         * 骨骼辅助显示
         */
        var skeletonHelper = new THREE.SkeletonHelper(SkinnedMesh);
        scene.add(skeletonHelper);

        // 转动关节带动骨骼网格模型出现弯曲效果  好像腿弯曲一样
        skeleton.bones[1].rotation.x = 0.1;
        skeleton.bones[2].rotation.x = 0.1;


        /**
         * 光源设置
         */
        //点光源
        var point = new THREE.PointLight(0xFDFEFF);
        point.position.set(200, 800, 300);//点光源位置
        scene.add(point);//点光源添加到场景中
        //点光源2
        //var point2=new THREE.PointLight(0xff0000);
        //point2.position.set(-400,-200,-300);//点光源位置
        //scene.add(point2);//点光源添加到场景中
        //环境光
        var ambient = new THREE.AmbientLight(0x444444);
        scene.add(ambient);
        /**
         * 相机设置
         */
        var width = window.innerWidth;//窗口宽度
        var height = window.innerHeight;//窗口高度
        var k = width / height;//窗口宽高比
        var s = 200;//三维场景缩放系数
        //创建相机对象
        var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
        camera.position.set(292, 109, 268);//设置相机位置
        camera.lookAt(scene.position);//设置相机方向(指向的场景对象)
        /**
         * 创建渲染器对象
         */
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(width, height);
        renderer.setClearColor(0xb9d3ff, 1);//设置背景颜色
        document.body.appendChild(renderer.domElement);//body元素中插入canvas对象

        var n = 0;
        var T = 50;
        var step = 0.01;
        // 渲染函数
        function render() {
            renderer.render(scene, camera);
            requestAnimationFrame(render);
            n += 1;
            if (n < T) {
                // 改变骨关节角度
                skeleton.bones[0].rotation.x = skeleton.bones[0].rotation.x - step;
                skeleton.bones[1].rotation.x = skeleton.bones[1].rotation.x + step;
                skeleton.bones[2].rotation.x = skeleton.bones[2].rotation.x + 2 * step;
            }
            if (n < 2 * T && n > T) {
                skeleton.bones[0].rotation.x = skeleton.bones[0].rotation.x + step;
                skeleton.bones[1].rotation.x = skeleton.bones[1].rotation.x - step;
                skeleton.bones[2].rotation.x = skeleton.bones[2].rotation.x - 2 * step;
            }
            if (n === 2 * T) {
                n = 0;
            }
        }
        render();

    </script>
</body>

</html>
相关标签: three.js html5