Three.js [3] 图元介绍

03.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>03</title>
    <script src="https://threejsfundamentals.org/threejs/resources/threejs/r125/build/three.js"></script>
</head>
<body>
    <script src="03.js"></script>
</body>
</html>

03.js

/*
* 图元介绍
* 图元就是一些 3D 的形状,在运行时根据大量参数生成
* 对于大多数的 3D 应用来说,通常是使用 3D 建模软件创建 3D 模型,比如, Blender, Maya, Cinema4D
* 先介绍一些最基础的 3D 形状
* */

/**
 * BoxGeometry, 立方几何体
 * BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
 * @param width     X轴上面的宽度,默认值为1。
 * @param height    Y轴上面的高度,默认值为1。
 * @param depth     Z轴上面的深度,默认值为1。
 * @param widthSegments     (可选)宽度的分段数,默认值是1。分段就是将这个面 平分成几份
 * @param heightSegments    (可选)宽度的分段数,默认值是1。
 * @param depthSegments     (可选)宽度的分段数,默认值是1。
 */

/**
 * CircleGeometry, 平面圆
 * CircleGeometry(radius : Float, segments : Integer, thetaStart : Float, thetaLength : Float)
 * @param radius            圆的半径,默认为 1
 * @param segments          分段(三角面)的数量,最小值为 3,默认值为 8
 * @param thetaStart        第一个分段的起始角度,默认为 0
 * @param thetaLength       圆形扇区的中心角,默认是 2*PI, 构成一个完整的圆
 */

/**
 * ConeGeometry, 锥体
 * ConeGeometry(radius : Float, height : Float, radialSegments : Integer, heightSegments : Integer, openEnded : Boolean, thetaStart : Float, thetaLength : Float)
 * @param radius    圆锥底部的半径,默认值为 1
 * @param height    圆锥的高度,默认值为 1
 * @param radialSegments    圆锥侧面周围的分段数,默认为 8
 * @param heightSegments    圆锥每个侧面的分段数,默认为 1
 * @param openEnded         一个 boolean 值,指明该圆锥底面是封闭的还是开放的。默认是 false, 即是封闭的
 * @param thetaStart        第一个分段的起始角度,默认为 0
 * @param thetaLength       圆锥底面圆扇区的中心角,默认是 2*PI,这使其成为一个完整的圆锥
 */

/**
 * Cylinder, 柱体
 * CylinderGeometry(radiusTop : Float, radiusBottom : Float, height : Float, radialSegments : Integer, heightSegments : Integer, openEnded : Boolean, thetaStart : Float, thetaLength : Float)
 * @param radiusTop         圆柱的顶部半径,默认是 1
 * @param radiusBottom      圆柱的底部半径,默认是 1
 * @param height            圆柱的高度, 默认是 1
 * @param radialSegments    圆柱侧面周围的分段数,默认是 8
 * @param heightSegments    圆柱侧面沿着其高度的分段数,默认是 1
 * @param openEnded         指明底部是否是开放的,默认为 false, 即关闭的
 * @param thetaStart        第一个分段的起始角度
 * @param thetaLength       底面圆扇区的中心角
 */

/**
 * DodecahedronGeometry, 十二面几何体
 * DodecahedronGeometry(radius : Float, detail : Integer)
 * @param radius    十二面体的半径,默认是 1
 * @param detail    默认值为 0,将这个值设为一个大于 0 的数将会为它增加一些顶点,使其不再是一个十二面体
 */

/*
* 全局变量
* */
const renderer = new THREE.WebGLRenderer();     // 渲染器,因为不是针对某个部分进行渲染,故需要将渲染器加入到 document 的 body 中
document.body.appendChild(renderer.domElement);
renderer.setSize(window.innerWidth, window.innerHeight);    // 全屏渲染

const camera = new THREE.PerspectiveCamera(40, 2, 0.1, 1000);   // 相机
camera.position.z = 120;

const scene = new THREE.Scene();    // 场景
scene.background = new THREE.Color(0xAAAAAA);   // 设置场景的背景色

{
    const color = 0xFFFFFF;
    const intensity = 1.5;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
}

{
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(1, -2, -4);
    scene.add(light);
}

const objects = [];         // 存放 Object3D 对象的数组
const spread = 15;

/*
* 传入 x, y 和一个 Object3D ,将其加入到场景中
* */
function addObject(x, y, obj) {
    obj.position.x = x * spread;     obj.position.y = y * spread;
    scene.add(obj);

    objects.push(obj);
}

/*
* 创建一个随机颜色的材料
* */
function createMaterial() {
    const material = new THREE.MeshPhongMaterial({
        side:THREE.DoubleSide,      // 这个告诉 Three.js ,绘制该三角形的两个面,有些图形若不设置则反面看不到
    });

    const hue = Math.random();
    const saturation = 1;
    const luminance = .5;
    material.color.setHSL(hue, saturation, luminance);

    return material;
}

/*
* 传入一个几何体,内部生成一个网格对象,并加入到场景中
* */
function addSolidGeometry(x, y, geometry) {
    const mesh = new THREE.Mesh(geometry, createMaterial());
    addObject(x, y, mesh);
}

function addLineGeometry(x, y, geometry) {
    const material = new THREE.LineBasicMaterial({color: 0x000000});
    const mesh = new THREE.LineSegments(geometry, material);
    addObject(x, y, mesh);
}

/*
* 根据不同浏览器的大小,重新设置渲染器的尺寸
* */
function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
        renderer.setSize(width, height, false);
    }
    return needResize;
}

function main() {
    console.debug("begin~");

    /* BoxGeometry 立方体 */
    {
        const width = 8;
        const height = 8;
        const depth = 8;
        addSolidGeometry(-2, 2, new THREE.BoxGeometry(width, height, depth));
    }

    /* CircleGeometry 平面圆 */
    {
        const radius = 7;
        const segments = 24;
        addSolidGeometry(-1, 2, new THREE.CircleGeometry(radius, segments));
    }

    /* ConeGeometry 锥体 */
    {
        const radius = 6;
        const height = 8;
        const segments = 16;
        addSolidGeometry(0, 2, new THREE.ConeGeometry(radius, height, segments));
    }

    /* CylinderGeometry 柱体 */
    {
        const radiusTop = 4;
        const radiusBottom = 4;
        const height = 8;
        const radialSegments = 12;
        addSolidGeometry(1, 2, new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radialSegments));
    }

    /* DodecahedronGeometry 十二面体 */
    {
        const radius = 7;
        addSolidGeometry(2, 2, new THREE.DodecahedronGeometry(radius));
    }

    /* ExtrudeGeometry 挤压几何体 */
    {
        const shape = new THREE.Shape();
        const x = -2.5;
        const y = -5;
        shape.moveTo(x + 2.5, y + 2.5);
        shape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
        shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
        shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
        shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
        shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
        shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);

        const extrudeSettings = {
            steps: 2,
            depth: 2,
            bevelEnabled: true,
            bevelThickness: 1,
            bevelSize: 1,
            bevelSegments: 2,
        };

        addSolidGeometry(-2, 1, new THREE.ExtrudeGeometry(shape, extrudeSettings));
    }

    /* IcosahedronGeometry 二十面体 */
    {
        const radius = 7;
        addSolidGeometry(-1, 1, new THREE.IcosahedronGeometry(radius));
    }

    /* LatheGeometry */
    {
        const points = [];
        for (let i = 0; i < 10; ++i) {
            points.push(new THREE.Vector2(Math.sin(i * 0.2) * 3 + 3, (i - 5) * .8));
        }
        addSolidGeometry(0, 1, new THREE.LatheGeometry(points));
    }

    /* OctahedronGeometry */
    {
        const radius = 7;
        addSolidGeometry(1, 1, new THREE.OctahedronGeometry(radius));
    }

    /* ParametricGeometry */
    {
        function klein(v, u, target) {
            u *= Math.PI;
            v *= 2 * Math.PI;
            u = u * 2;

            let x;
            let z;

            if (u < Math.PI) {
                x = 3 * Math.cos(u) * (1 + Math.sin(u)) + (2 * (1 - Math.cos(u) / 2)) * Math.cos(u) * Math.cos(v);
                z = -8 * Math.sin(u) - 2 * (1 - Math.cos(u) / 2) * Math.sin(u) * Math.cos(v);
            } else {
                x = 3 * Math.cos(u) * (1 + Math.sin(u)) + (2 * (1 - Math.cos(u) / 2)) * Math.cos(v + Math.PI);
                z = -8 * Math.sin(u);
            }

            const y = -2 * (1 - Math.cos(u) / 2) * Math.sin(v);

            target.set(x, y, z).multiplyScalar(0.75);
        }

        const slices = 25;
        const stacks = 25;
        addSolidGeometry(2, 1, new THREE.ParametricGeometry(klein, slices, stacks));
    }

    /* PlaneGeometry */
    {
        const width = 9;
        const height = 9;
        const widthSegments = 2;
        const heightSegments = 2;
        addSolidGeometry(-2, 0, new THREE.PlaneGeometry(width, height, widthSegments, heightSegments));
    }

    /* PolyhedronGeometry */
    {
        const verticesOfCube = [
            -1, -1, -1,    1, -1, -1,    1,  1, -1,    -1,  1, -1,
            -1, -1,  1,    1, -1,  1,    1,  1,  1,    -1,  1,  1,
        ];
        const indicesOfFaces = [
            2, 1, 0,    0, 3, 2,
            0, 4, 7,    7, 3, 0,
            0, 1, 5,    5, 4, 0,
            1, 2, 6,    6, 5, 1,
            2, 3, 7,    7, 6, 2,
            4, 5, 6,    6, 7, 4,
        ];
        const radius = 7;
        const detail = 2;
        addSolidGeometry(-1, 0, new THREE.PolyhedronGeometry(verticesOfCube, indicesOfFaces, radius, detail));
    }

    /* RingGeometry */
    {
        const innerRadius = 2;
        const outerRadius = 7;
        const segments = 18;
        addSolidGeometry(0, 0, new THREE.RingGeometry(innerRadius, outerRadius, segments));
    }

    /* ShapeGeometry */
    {
        const shape = new THREE.Shape();
        const x = -2.5;
        const y = -5;
        shape.moveTo(x + 2.5, y + 2.5);
        shape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
        shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
        shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
        shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
        shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
        shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
        addSolidGeometry(1, 0, new THREE.ShapeGeometry(shape));
    }

    /* SphereGeometry */
    {
        const radius = 7;
        const widthSegments = 12;
        const heightSegments = 8;
        addSolidGeometry(2, 0, new THREE.SphereGeometry(radius, widthSegments, heightSegments));
    }

    /* TetrahedronGeometry */
    {
        const radius = 7;
        addSolidGeometry(-2, -1, new THREE.TetrahedronGeometry(radius));
    }

    /* TextGeometry */
    {
        const loader = new THREE.FontLoader();
        // promisify font loading
        function loadFont(url) {
            return new Promise((resolve, reject) => {
                loader.load(url, resolve, undefined, reject);
            });
        }

        async function doit() {
            const font = await loadFont('https://threejsfundamentals.org/threejs/resources/threejs/fonts/helvetiker_regular.typeface.json');
            const geometry = new THREE.TextGeometry('Samsung', {
                font: font,
                size: 3.0,
                height: .2,
                curveSegments: 12,
                bevelEnabled: true,
                bevelThickness: 0.15,
                bevelSize: .3,
                bevelSegments: 5,
            });
            const mesh = new THREE.Mesh(geometry, createMaterial());
            geometry.computeBoundingBox();
            geometry.boundingBox.getCenter(mesh.position).multiplyScalar(-1);

            const parent = new THREE.Object3D();
            parent.add(mesh);

            addObject(-1, -1, parent);
        }
        doit();
    }

    /* TorusGeometry */
    {
        const radius = 5;
        const tubeRadius = 2;
        const radialSegments = 8;
        const tubularSegments = 24;
        addSolidGeometry(0, -1, new THREE.TorusGeometry(radius, tubeRadius, radialSegments, tubularSegments));
    }

    /* TorusKnotGeometry */
    {
        const radius = 3.5;
        const tube = 1.5;
        const radialSegments = 8;
        const tubularSegments = 64;
        const p = 2;
        const q = 3;
        addSolidGeometry(1, -1, new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q));
    }

    /* TubeGeometry */
    {
        class CustomSinCurve extends THREE.Curve {
            constructor(scale) {
                super();
                this.scale = scale;
            }
            getPoint(t) {
                const tx = t * 3 - 1.5;
                const ty = Math.sin(2 * Math.PI * t);
                const tz = 0;
                return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
            }
        }

        const path = new CustomSinCurve(4);
        const tubularSegments = 20;
        const radius = 1;
        const radialSegments = 8;
        const closed = false;
        addSolidGeometry(2, -1, new THREE.TubeGeometry(path, tubularSegments, radius, radialSegments, closed));
    }

    /* EdgesGeometry */
    {
        const width = 8;
        const height = 8;
        const depth = 8;
        const thresholdAngle = 15;
        addLineGeometry(-1, -2, new THREE.EdgesGeometry(
            new THREE.BoxGeometry(width, height, depth),
            thresholdAngle));
    }

    /* WireframeGeometry */
    {
        const width = 8;
        const height = 8;
        const depth = 8;
        addLineGeometry(1, -2, new THREE.WireframeGeometry(new THREE.BoxGeometry(width, height, depth)));
    }

    function render(time) {
        time *= 0.001;

        if (resizeRendererToDisplaySize(renderer)) {
            const canvas = renderer.domElement;
            camera.aspect = canvas.clientWidth / canvas.clientHeight;
            camera.updateProjectionMatrix();
        }

        objects.forEach((obj, ndx) => {
            const speed = .1 + ndx * .05;
            const rot = time * speed;
            obj.rotation.x = rot;
            obj.rotation.y = rot;
        });
        renderer.render(scene, camera);
        requestAnimationFrame(render);
    }
    requestAnimationFrame(render);

    console.debug("end~");
}

main();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值