zoukankan      html  css  js  c++  java
  • threejs 初识

    用于展示3D动效,就是 跟拍电影一样,需要有3大模块:scene,camera,renderer。

    • scene:场景,用于放置用到的模型。
    • camera:摄像机,拍电影似的,得有个摄像机。
    • renderer:渲染器,很重要,用于与被渲染的dom元素挂钩,也用于 与场景、摄像机 挂钩。

    一个动效的制作过程如下:

    1. 得到三大基础模块:scene, camera, renderer

    2. 绘制结果与DOM挂钩

    3. 加载摄像头控制器(可选),用于 旋转、缩放等效果

    4. 添加场景内 模型

    5. 渲染

    6. 事件设置(可选)

    示例是一个 星球,顶点上 是 文字。可旋转,缩放:

    <html>
    <head>
        <title>球状旋转_sprite_v2.html</title>
        <meta charset="utf-8">
        <style>
            body { margin: 0; }
        </style>
    </head>
    <body>
    </body>
    <script src="js/three.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script>
        /**
         * 3d加载步骤
         * 1、得到三大基础模块:scene, camera, renderer
         * 2、绘制结果与DOM挂钩
         * 3、加载摄像头控制器(可选)
         * 4、添加场景内 模型
         * 5、渲染
         * 6、事件设置(可选)
         */
    
        var scene, camera, renderer, controls, group;
        var container;
        var startX, startY;
        container = document.createElement( 'div' );
        document.body.appendChild( container );
    
    
        /*1*/
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera( 40, window.innerWidth/window.innerHeight, 1, 1000 );
        camera.position.z = 50;
        renderer = new THREE.WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
    
        /*2*/
        container.appendChild( renderer.domElement );
    
        /*3*/
        // controls
        controls = new THREE.OrbitControls( camera, renderer.domElement );
        controls.minDistance = 20;
        controls.maxDistance = 50;
        controls.maxPolarAngle = Math.PI / 2;
    
        /*4*/
        group = new THREE.Group();
        scene.add( group );
    
        var vertices = new THREE.DodecahedronGeometry( 10 ).vertices;
    
        //多个精灵
        vertices.forEach(function (item, index) {
            var sprite = createSpriteTextNoPosition(index);
            sprite.position.set(item.x, item.y, item.z);
            sprite.clickFlag = true;
            sprite.aa = '序号:' + index;
            group.add(sprite);
        });
    
        /*5*/
        var animate = function () {
            requestAnimationFrame( animate );
    
    //        group.rotation.x += 0.005;
            group.rotation.y += 0.005;
    
            renderer.render( scene, camera );
        };
        animate();
    
        /*6*/
        //监听移动端touchstart事件
        function onTouchStart(e) {
    //        console.log('触摸开始')
    //        console.log(e)
    
            var touch = e.touches[0]; //获取第一个触点
            var x = Number(touch.pageX); //页面触点X坐标
            var y = Number(touch.pageY); //页面触点Y坐标
            //记录触点初始位置
            startX = x;
            startY = y;
        }
        //监听移动端touchEnd事件
        function onTouchEnd(e) {
    //        console.log('触摸结束')
    //        console.log(e);
            if (e.changedTouches[0].pageX == startX && e.changedTouches[0].pageY == startY)
                getClickMap(e);
        }
    
        function getClickMap(event) {
            event.preventDefault();
            var mouse = {};
    
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            if(event.touches) {
                mouse.x = (event.changedTouches[0].pageX / window.innerWidth) * 2 - 1;
                mouse.y = -(event.changedTouches[0].pageY / window.innerHeight) * 2 + 1;
            }
            var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
    
            vector = vector.unproject(camera);
    
            var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    
            var intersects = raycaster.intersectObjects(group.children);
    
            //TODO 这个50 距离原点的距离, 正好就是 摄像头 到 球心的距离应该是。
            if (intersects.length > 0 && intersects[0].distance < 50 && intersects[0].object.clickFlag) {
                console.log(intersects[0].object.aa);
            }
        }
        function createSpriteTextNoPosition(index){
            //先用画布将文字画出
            let canvas = document.createElement("canvas");
            canvas.width = 400;
            let ctx = canvas.getContext("2d");
            ctx.fillStyle = "#ffff00";
            ctx.font = "Bold 100px Arial";
            ctx.lineWidth = 4;
            ctx.fillText("萨克拉" + index,4,104);
            let texture = new THREE.Texture(canvas);
            texture.needsUpdate = true;//不设置,会 不出现
    
            //使用Sprite显示文字
            let material = new THREE.SpriteMaterial({map:texture});
            let textObj = new THREE.Sprite(material);
            textObj.scale.set(4, 2, 1);
            return textObj;
        }
        document.addEventListener('mousedown', getClickMap, false);
        document.addEventListener('touchstart', onTouchStart, false);
        document.addEventListener('touchend', onTouchEnd, false);
    
    </script>
    </html>

    实现过程中遇到了一些问题,这里特做以记录:

    1、geometry 带有顶点的 几何图形

    2、获取几何图形的顶点,数组
    利用属性 vertices

    3、group 组的概念,用于 多个模型分组。
    常用于 整个组 内容 一起 旋转之类。

    4、group.children 可获取到 组内所有的 模型。scene.children同理
    5、光投影

    6、orbitControls 与移动端 touchmove事件冲突,不能共存
    7、利用 touchStart 和 touchEnd 判断是否为点击事件
    利用 touch事件对象 的 changedTouches[0];start和 end皆有; 如果 start里的 坐标 等于 end 里的 坐标,则为点击。

    8、模型上移
    不做其他改变,使用定位,将画布绝对定位 top=-100px;点击事件里 pageY + 100

    9、bug:手机浏览器 画布过大,超过屏幕,与google调试不一致;
    强行指定canvas给渲染器,并 important 宽高 为100%。

    10、球形顶点 多点旋转:点与数据量实施方案
    顶点数须大于数据量:遍历顶点,数据量不够则再来一遍。铺满

    11、MeshPhongMaterial 镜面材质,需要灯光
    12、MeshBasicMaterial 基础材质,普通上色,不需灯光

    13、动效切换,清除
    a、停止动效 (必须cancelAnimationFrame)
    b、清除场景内模型 (需要深清除,内存里的)
    移除场景内的子元素,需注意 不要移除 摄像机和灯光(子元素包含了)。
    c、有绑定事件的 移除事件

    14、canvas文本显示不清晰,
    解决:使用textObj.scale.set(4,2,1); 对sprite 进行缩放,参数是 缩放量,三维的。改变前两参数就行

  • 相关阅读:
    异或运算
    GitHub使用简介
    归并排序
    快速排序
    字符串匹配
    Runner站立会议06
    Runner站立会议05
    Runner站立会议04
    记计账需求分析
    Runner站立会议03
  • 原文地址:https://www.cnblogs.com/fan-zha/p/10368673.html
Copyright © 2011-2022 走看看