Three.js 学习

魔方

<!DOCTYPE html>

<html>

<head>
    <title>Example 04.05 - Mesh face material</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>
    <script type="text/javascript" src="../libs/TrackballControls.js"></script>
    <script type="text/javascript" src="./libs/MagicCubeFace.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() {
        var clock = new THREE.Clock();
        var stats = initStats();

        // 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();

        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = false;

        // create the ground plane
        var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({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 = 0;
        plane.position.y = -7;
        plane.position.z = 0;

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

        // position and point the camera to the center of the scene
        camera.position.x = -40;
        camera.position.y = 40;
        camera.position.z = 40;
        camera.lookAt(scene.position);

        var trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
        trackballControls.staticMoving = true;

        document.addEventListener('mousedown', onDocumentMouseDown, false);

        // add subtle ambient lighting
//        var ambientLight = new THREE.AmbientLight(0x0c0c0c);
//        scene.add(ambientLight);

        // add spotlight for the shadows
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        scene.add(spotLight);

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        var group = new THREE.Mesh();
        var cubes = [];
        initGroups(3);
        for (var x = 0; x < 3; x++) {
            for (var y = 0; y < 3; y++) {
                for (var z = 0; z < 3; z++) {
                    var cubeGeom = new THREE.BoxGeometry(2, 2, 2);
                    var cube = new THREE.Mesh(cubeGeom, createFaceMaterial() );
                    cube.position.set(x * 3 - 3, y * 3 - 3, z * 3 - 3);
                    initCubeFaces(cube, x, y, z);
                    cubes.push(cube);
                    group.add(cube);
                }
            }
        }
        console.log(groupsLog);
        // group.rotation.y = 0.5 * Math.PI;


        // call the render function
        scene.add(group);
        var step = 0;

        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.numberOfObjects = scene.children.length;
        };

        var gui = new dat.GUI();
        gui.add(controls, 'rotationSpeed', 0, 0.5);

        render();

        function render() {
            stats.update();

            // group.rotation.y = step += controls.rotationSpeed;
            // group.rotation.x = step;
            // group.rotation.z = step;
            var delta = clock.getDelta();
            trackballControls.update(delta);
            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;
        }

        function createFaceMaterial() {
            // add all the rubik cube elements
            var mats = [];
            var color = "#009e60";
            //后前 上下 右左
            mats.push(new THREE.MeshBasicMaterial({color: 0x009e60})); //green
            mats.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));  //blue, green opposite blue

            mats.push(new THREE.MeshBasicMaterial({color: 0xffd500}));
            mats.push(new THREE.MeshBasicMaterial({color: 0xffffff}));

            mats.push(new THREE.MeshBasicMaterial({color: 0xC41E3A}));
            mats.push(new THREE.MeshBasicMaterial({color: 0xff5800}));

            mats.forEach(obj => {
                // obj.side = THREE.BackSide;
                obj.side = THREE.FrontSide;
                obj.transparent = true;
                // obj.opacity = 0.5;
            });

            var faceMaterial = new THREE.MeshFaceMaterial(mats);
            return faceMaterial;
        }

        function onDocumentMouseDown(event) {

            var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
            vector = vector.unproject(camera);

            var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());

            var intersects = raycaster.intersectObjects(cubes);

            if (intersects.length > 0) {
                var selectedObj = intersects[0];
                console.log("faceIndex: " + selectedObj.faceIndex);
                // console.log(selectedObj.object.name);
                // console.log(selectedObj);
                selectedObj.object.material.materials.forEach( m => m.opacity = 0.8);
            }
        }
    }
    window.onload = init;

</script>
</body>
</html>

./libs/MagicCubeFace.js

var colorToIntMap = {yellow:0, white:1, blue:2, green:3, orange:4, red:5};
var intToColorArr = ["yellow", "white", "blue", "green", "orange", "red"];
//上黄下白 前蓝后绿 左橙右红,
var groups = [[], [], []];
var groupsLog = [[], [], []];
var axis = {
    X:0,
    Y:1,
    Z:2
};
var opTypeEnum = {
	CLOCKWISE: 0,
	COUNTERCLOCKWISE: 1,
	CLOCKWISE_DOUBLE: 2
};

var lvl = 2;
function initGroups(level) {
    lvl = level;
    for (var i = 0; i < level; i++) {
    	groups[0].push([]);
    	groups[1].push([]);
    	groups[2].push([]);
        groupsLog[0].push([]);
        groupsLog[1].push([]);
        groupsLog[2].push([]);
	}
}

var MagicCubeFace = function(originFaceDir, originLocation) {
 	var that = {
 		color: intToColorArr[originFaceDir],
 		faceDir: originFaceDir,
		location: originLocation,
 		getOriginFaceDir: function () {
			return originFaceDir;
        },
        getOriginFaceLoc: function () {
            return originFaceLoc;
        },
 		setFaceDirAndLocation: function(dir, location) {	//还没有燃尽返回true
			that.faceDir = dir;
			that.location = location;
 		}
 	};
 	return that;
}

var CubeFaces = function (colorAndCodeArr) {
    //从Three.js立方体的面索引找颜色编号, 颜色编号{yellow:0, white:1, blue:2, green:3, orange:4, red:5}
    var faceIndexToIntArr = [3, 3, 2, 2, 0, 0, 1, 1, 5, 5, 4, 4];
	var that = {};
	colorAndCodeArr.forEach(obj => {
		var colorIndex = intToColorArr[obj.color];
		that[colorIndex] = MagicCubeFace(colorIndex, obj.code);
	});
    that.getCubeFaceByFaceIndex = function (threejsFaceIndex) {
		var colorIndex = faceIndexToIntArr[threejsFaceIndex];
		return that[colorIndex];
    };
	return that;
}

//axis is int type, x axis is 0, y axis is 1, z axis is 2
function rotateLayer(axis, index, operationType) {
    rotateArr(groups[axis][index], lvl, operationType);
    groups[2][0][index],groups[2][1][index],groups[2][2][index]
}

function rotateArr(arr, colNum, operationType) {
    var ret = [];
    var rowNum = Math.ceil(arr.length/colNum);
    for (let i = 0; i < arr.length; i++) {
        let row = ~~(i / colNum), col = i % colNum;
        switch (operationType) {
            case 0://opTypeEnum.CLOCKWISE:
                ret[col * rowNum + rowNum - row - 1] = arr[i];
                break;
            case 1://opTypeEnum.COUNTERCLOCKWISE:
                ret[(colNum - 1 - col) * rowNum + row] = arr[i];
                break;
            case 2://opTypeEnum.CLOCKWISE_DOUBLE:
                let row2 = rowNum - 1 - row;
                let col2 = colNum - 1 - col;
                ret[row2 * colNum + col2] = arr[i];
                break;
        }
    }
    return ret;
}

function prettyLog(arr, colNum) {
    var ret = [], sub = [], count = 1;
    for (let i = 0; i < arr.length; i++, count++) {
        sub.push(arr[i]);
        if (count >= colNum) {
            count = 0;
            ret.push(sub);
            console.log(sub);
            sub = [];
        }
    }
    return ret;
}
// var arr = []; for (let i = 0; i < 16; i++) { arr[i] = i;}
// prettyLog(rotateArr(arr, 8, 1), 8);

function initCubeFaces(cube, x, y, z) {
    groups[axis.X][x][lvl * y + z] = cube;
    groups[axis.Y][y][lvl * x + z] = cube;
    groups[axis.Z][z][lvl * y + x] = cube;
    cube.name = x + ", " + y + ", " + z;
    groupsLog[axis.X][x][lvl * y + z] = cube.name;
    groupsLog[axis.Y][y][lvl * x + z] = cube.name;
    groupsLog[axis.Z][z][lvl * y + x] = cube.name;
    cube.lx = x, cube.ly = y, cube.lz = z;
    if (x == 0 && y == 0 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"blue", code:6}, {color:"orange", code:8}, {color:"white", code:0} ]);
    }
    if (x == 0 && y == 0 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"blue", code:7}, {color:"white", code:1} ]);
    }
    if (x == 0 && y == 0 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"blue", code:8}, {color:"white", code:2}, {color:"red", code:6} ]);
    }
    if (x == 0 && y == 1 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"blue", code:3}, {color:"orange", code:5}]);
    }
    if (x == 0 && y == 1 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"blue", code:4} ]);
    }
    if (x == 0 && y == 1 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"blue", code:5}, {color:"red", code:3} ]);
    }
    if (x == 0 && y == 2 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"blue", code:0}, {color:"orange", code:2}, {color:"yellow", code:6} ]);
    }
    if (x == 0 && y == 2 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"blue", code:1}, {color:"yellow", code:7} ]);
    }
    if (x == 0 && y == 2 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"blue", code:2}, {color:"yellow", code:8}, {color:"red", code:0} ]);
    }

    if (x == 1 && y == 0 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"orange", code:7}, {color:"white", code:3} ]);
    }
    if (x == 1 && y == 0 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"white", code:4} ]);
    }
    if (x == 1 && y == 0 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"white", code:5}, {color:"red", code:7} ]);
    }
    if (x == 1 && y == 1 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"orange", code:4} ]);
    }
    // if (x == 1 && y == 1 && z == 1) {
    //     cube.faceObj = null;
    // }
    if (x == 1 && y == 1 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"red", code:4} ]);
    }
    if (x == 1 && y == 2 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"orange", code:1}, {color:"yellow", code:3} ]);
    }
    if (x == 1 && y == 2 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"yellow", code:4} ]);
    }
    if (x == 1 && y == 2 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"yellow", code:5}, {color:"red", code:1} ]);
    }

    if (x == 2 && y == 0 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"green", code:8}, {color:"orange", code:6}, {color:"white", code:6} ]);
    }
    if (x == 2 && y == 0 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"green", code:7}, {color:"white", code:7} ]);
    }
    if (x == 2 && y == 0 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"green", code:6}, {color:"white", code:8}, {color:"red", code:8} ]);
    }
    if (x == 2 && y == 1 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"green", code:5}, {color:"orange", code:3}]);
    }
    if (x == 2 && y == 1 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"green", code:4} ]);
    }
    if (x == 2 && y == 1 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"green", code:3}, {color:"red", code:5} ]);
    }
    if (x == 2 && y == 2 && z == 0) {
        cube.faceObj = CubeFaces([ {color:"green", code:2}, {color:"orange", code:0}, {color:"yellow", code:0} ]);
    }
    if (x == 2 && y == 2 && z == 1) {
        cube.faceObj = CubeFaces([ {color:"green", code:1}, {color:"yellow", code:1} ]);
    }
    if (x == 2 && y == 2 && z == 2) {
        cube.faceObj = CubeFaces([ {color:"green", code:0}, {color:"yellow", code:2}, {color:"red", code:2} ]);
    }
}

自定义几何体
对于自定义几何体,根据顶点构造三角面时,要特别注意,凡是镜头camera 能够看到的三角面,顶点的序列必须是顺时针的,看不见的三角面的顶点序列必须是逆顺时针的,否则构造的几何体会很奇怪,并且不能产生投影

<!DOCTYPE html>

<html>

<head>
    <title>Example 02.05 - Custom geometry</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>
    <script type="text/javascript" src="../libs/TrackballControls.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() {
        var clock = new THREE.Clock();
        var stats = initStats();

        // 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();

        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;

        // create the ground plane
        var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({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 = 0;
        plane.position.y = 0;
        plane.position.z = 0;

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

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

        var trackballControls = new THREE.TrackballControls(camera);

        trackballControls.rotateSpeed = 1.0;
        trackballControls.zoomSpeed = 1.0;
        trackballControls.panSpeed = 1.0;
//        trackballControls.noZoom=false;
//        trackballControls.noPan=false;
        trackballControls.staticMoving = true;
//        trackballControls.dynamicDampingFactor=0.3;

        // add subtle ambient lighting
//        var ambientLight = new THREE.AmbientLight(0x494949);
//        scene.add(ambientLight);

        // add spotlight for the shadows
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, 10);
        spotLight.castShadow = true;
        scene.add(spotLight);

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        // call the render function
        var step = 0;


        var vertices = [
            new THREE.Vector3(0, 0, 0),
            new THREE.Vector3(0, 0, 0),
            new THREE.Vector3(1, -1, 1),
            new THREE.Vector3(1, -1, -1),
            new THREE.Vector3(-1, 0, -1),
            new THREE.Vector3(-1, 0, 1)
        ];

        var faces = [
            new THREE.Face3(1, 3, 5),
            new THREE.Face3(0, 2, 4),

            new THREE.Face3(2, 1, 5),
            new THREE.Face3(1, 0, 3),
            new THREE.Face3(3, 4, 5),

            new THREE.Face3(0, 1, 2),
            new THREE.Face3(0, 4, 3),
            new THREE.Face3(2, 5, 4)
        ];

        var geom = new THREE.Geometry();
        geom.vertices = vertices;
        geom.faces = faces;
        geom.computeFaceNormals();


        var materials = [
            // new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),
            new THREE.MeshNormalMaterial({color: 0x000000, transparent: true, opacity: 0.8}),
            new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})

        ];


        var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);
        mesh.children.forEach(function (e) {
            e.castShadow = true
        });
//        mesh.children[0].translateX(0.5);
//        mesh.children[0].translateZ(0.5);

        scene.add(mesh);

        function addControl(x, y, z) {
            var controls = {x:x, y:y, z:z};

            return controls;
        }

        var controlPoints = [];
        var half = 2.5;
        controlPoints.push(addControl(-half, -half, -half));
        controlPoints.push(addControl(half, -half, -half));
        controlPoints.push(addControl(half, -half, half));
        controlPoints.push(addControl(-half, half, -half));
        controlPoints.push(addControl(-half, half, half));
        controlPoints.push(addControl(half, half, half));

        var gui = new dat.GUI();
        gui.add(new function () {
            this.clone = function () {

                var clonedGeometry = mesh.children[0].geometry.clone();
                var materials = [
                    new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
                    new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})

                ];

                var mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
                mesh2.children.forEach(function (e) {
                    e.castShadow = true
                });

                mesh2.translateX(5);
                mesh2.translateZ(5);
                mesh2.name = "clone";
                scene.remove(scene.getChildByName("clone"));
                scene.add(mesh2);


            }
        }, 'clone');

        for (var i = 0; i < controlPoints.length; i++) {

            f1 = gui.addFolder('Vertices ' + (i + 1));
            f1.add(controlPoints[i], 'x', -10, 10);
            f1.add(controlPoints[i], 'y', -10, 10);
            f1.add(controlPoints[i], 'z', -10, 10);

        }

        render();
        function render() {
            stats.update();

            var vertices = [];
            for (var i = 0; i < controlPoints.length; i++) {
                vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));
            }

            mesh.children.forEach(function (e) {
                e.geometry.vertices = vertices;
                e.geometry.verticesNeedUpdate = true;
                e.geometry.computeFaceNormals();
            });
            mesh.position.y = 10;
            // mesh.rotation.x += 0.02;
            mesh.rotation.y += 0.01;
            // mesh.rotation.z += 0.02;

            var delta = clock.getDelta();
            trackballControls.update(delta);
            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>

http://xuewen.cnki.net/CJFD-ZOXE200609015.html
https://github.com/mrdoob/three.js/blob/master/src/geometries/DodecahedronGeometry.js
https://github.com/mrdoob/three.js/blob/master/src/geometries/PolyhedronGeometry.js

你想学习关于 three.js 的内容吗?我可以为你提供一些相关的信息和资源。首先,three.js 是一个用于创建 3D 图形的 JavaScript 库,它可以在 Web 浏览器中渲染复杂的三维场景和动画效果。如果你想学习如何使用 three.js,以下是一些步骤和资源供你参考: 1. 了解基础知识:在开始学习 three.js 之前,建议你先掌握 HTML、CSS 和 JavaScript 的基础知识。 2. 安装和设置:你可以通过下载 three.js 的最新版本文件或使用 CDN 来引入 three.js 库。确保在你的 HTML 文件中正确地链接和配置 three.js。 3. 学习文档和示例:three.js 官方网站提供了详细的文档和示例,你可以通过阅读文档和尝试示例来了解 three.js 的各种功能和用法。官方文档地址是:https://threejs.org/docs/index.html 4. 学习基本概念:熟悉 three.js 中的基本概念,如场景(Scene)、相机(Camera)、渲染器(Renderer)、几何体(Geometry)、材质(Material)等。理解这些概念对于构建三维场景至关重要。 5. 创建简单场景:从简单的场景开始,逐步添加和调整对象、光照和材质等。通过实践来熟悉 three.js 的基本用法和 API。 6. 学习进阶技术:一旦你掌握了基本的用法,你可以学习更高级的技术,如动画、纹理映射、阴影、粒子效果等。three.js 提供了丰富的功能和扩展库,你可以根据自己的需求进一步探索。 除了官方文档外,还有一些优秀的教程和资源可供参考,例如: - three.js Fundamentals:https://threejsfundamentals.org/ ***
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值