rainit2006 / JS-room

javascript knowledge
0 stars 0 forks source link

Three.js #9

Open rainit2006 opened 6 years ago

rainit2006 commented 6 years ago

rainit2006 commented 6 years ago

入门教程


入門 To actually be able to display anything with three.js, we need three things: scene, camera and renderer.

Geometry 几何形状类型汇总: BoxGeometry 是四边形几何类, THREE.BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) PlaneGeometry 是平面类, 其实是一个长方形。 THREE.PlaneGeometry(width, height, widthSegments, heightSegments) SphereGeometry 是球体类。 THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, thetaStart, thetaLength) CircleGeometry 几何类可以创建圆形或者扇形; THREE.CircleGeometry(radius, segments, thetaStart, thetaLength) CylinderGeometry 表示柱体类 TetrahedronGeometry 正四面体、 OctahedronGeometry / 正八面体、 IcosahedronGeometry / 正二十面体 TorusGeometry 即圆环面, 也为甜甜圈的形状; TorusKnotGeometry / 圆环结, 形如打了结的甜甜圈; ExtrudeGeometry 几何类, 用于从一条路径中抽取出特征用于构建几何形状; ConeGeometry 锥形几何类; image image Three.js 还提供了很多其他几何类, 详情可以在 Three.js 文档搜索框中输入 Geometry 关键字, 查看 Geometries 下栏目.


カメラ

正投影和透视投影的区别是:透视投影有一个基本点,就是远处的物体比近处的物体小。我们看看著名的蒙娜丽莎的微笑就是典型的透视作品。 在工程建筑领域,正投影的例子很多。其特点是,远近高低比例都相同。

PerspectiveCamera( fov, aspect, near, far )

fov — Camera frustum vertical field of view.
aspect — Camera frustum aspect ratio.
near — Camera frustum near plane.
far — Camera frustum far plane.

PerspectiveCamera( 視野角 , アスペクト比(縦横比) , カメラから視体積の手前までの距離 , カメラから視体積の奥までの距離); 视野角数值越小,物体越大(离物体越近)。视角越大,中间的物体越小,这是因为,视角越大,看到的场景越大,那么中间的物体相对于整个场景来说,就越小了。

1、视角fov:这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,但是在180度的时候,往往物体很小,因为他在你的整个可视区域中的比例变小了。 2、纵横比aspect:实际窗口的纵横比,即宽度除以高度。这个值越大,说明你宽度越大,那么你可能看的是宽银幕电影了,如果这个值小于1,那么可能你看到的是如下的图中的LED屏幕了。 3、近平面near:这个呢,表示你近处的裁面的距离。补充一下,也可以认为是眼睛距离近处的距离,假设为10米远,请不要设置为负值,Three.js就傻了,不知道怎么算了, 4、远平面far:这个呢,表示你远处的裁面, image

image image image

http://gupuru.hatenablog.jp/entry/2013/11/20/183100

three.jsで扱えるレンダラー(渲染器) WebGLRendererとCanvasRendererは標準で組み込まれていて、それ以外は外部ライブラリを読み込むことで利用可能となる。 WebGLに対応した環境ではWebGLRendererを利用し、対応していない(かつ、HTML5に対応している)環境ではCanvasRendererを利用するというように使いわけることができる。

WebGLRenderTarget: オフスクリーンレンダリング(バックグラウンドでのレンダリング)を可能にする。 画像処理を行いながら動的にテクスチャを生成したりできる。

CanvasRenderer: 一般的に2Dグラフィックスを描画するときに使用するCanvas2Dで3Dグラフィックスを実現する。WebGLと異なり、CPUで演算を行うため実行速度が遅くなるが、WebGLで実現できることの大半がCanvas2Dでも可能。

SVGRenderer: ベクトル画像を扱うSVGを用いた3Dグラフィックスを実現する。

SoftwareRenderer: すべての計算をGPU側でなくCPU側で行うソフトウェアレンダリングを実現する。 GPUの制限を受けない分柔軟性はあるが、実行速度が遅くなる。

CSS3DRenderer: HTMLの要素とCSS3で3Dグラフィックスを実現する。 three.jsの演算機能でCSS transformを扱うことができ、WebGLが対応していないモバイル端末でも3Dグラフィックスを簡単に実現できる。

var renderer;

canvas = document.getElementById('canvas'); // div要素の取得
renderer = new THREE.WebGLRenderer(); // レンダラーの生成
renderer.setSize(canvas.clientWidth, canvas.clientHeight); // レンダラーのサイズをdivのサイズに設定
renderer.setClearColor(0x000000, 1.0); // レンダラーの背景色を黒色(不透過)に設定
canvas.appendChild(renderer.domElement); // div領域にレンダラーを配置

如何让 Windows 下的 Chrome 支持 WebGL ? https://www.zhihu.com/question/19647275

rainit2006 commented 6 years ago
rainit2006 commented 6 years ago

轨道控制器OrbitControls.js js文件所在路径:Three.js下载文件包里的examples\examples\js\controls目录里。 也可以通过npm来安装 npm i three-orbit-controls

轨道控制器OrbitControls.js是一个相当神奇的控件,用它可以实现场景用鼠标交互,让场景动起来,控制场景的旋转、平移,缩放。

const controls = this.controls = new OrbitControls(this.camera)
controls.maxPolarAngle = 1.5
controls.minPolarAngle = 0.5
controls.rotateSpeed = 5.0
controls.zoomSpeed = 5
controls.panSpeed = 2
controls.onZoom = false
controls.noPan = false
controls.staticMoving = true
controls.dynamicDampingFactor = 0.3
controls.minDistance = 10
controls.maxDistance = 800

maxPolarAngle和minPolarAngle可以限制旋转的角度。

当相机旋转的时候更新一下

function animate() {
  requestAnimationFrame( animate );
  // required if controls.enableDamping or controls.autoRotate are set to true
  controls.update();
  renderer.render( scene, camera );
}
rainit2006 commented 6 years ago

加载3d模型 首先,先装一个引人模型的loader npm i three-obj-loader

把一个.obj格式的3d模型加载进来就好了

const loader = new THREE.OBJLoader()
    loader.load('assets/chair.obj', obj => {
      obj.traverse(child=> {
        if (child instanceof Mesh) {
          child.material.side = THREE.DoubleSide
          this.scene.add(obj)
        }
      })
})

把模型加载进来后要添加到场景中(this.scene.add(obj))

进行到这一步就差不多完成了,还差最后一步,实现模型随着手指的移动而转动,原理其实很简单,改变相机的位置就可以了,这里我们用orbitControl库实现。 https://www.yanshuo.me/p/115491

rainit2006 commented 6 years ago

材料(Materials) http://techbrood.com/threejs/docs/#参考手册/材料(Materials)/基础线条材料(LineBasicMaterial)

rainit2006 commented 6 years ago

加入网格 使用GridHelper

var size = 10;
var step = 1;

var gridHelper = new THREE.GridHelper( size, step );
scene.add( gridHelper );

three.js の座標軸を AxisHelper で表示する

普通、数学だと z 軸が高さですが、three.js では y 軸が高さなっています。

<html>
<head>
    <script type="text/javascript" src="libs/three.min.js"></script>
    <script type="text/javascript" src="libs/OrbitControls.js"></script>
   // カメラの移動に OrbitControls を使っています。
</head>

<body>
    <div id="WebGL-area"></div>

    <script type="text/javascript">
        function init() {
            var scene = new THREE.Scene();

            // 座標軸を表示
            var axes = new THREE.AxisHelper(25);
            scene.add(axes);

            // 物体
            var sphere = new THREE.Mesh(new THREE.SphereGeometry(2), new THREE.MeshBasicMaterial({color: 0xff00ff, wireframe : true}));
            sphere.position.set(5, 10, 15);
            scene.add(sphere);

            var camera = new THREE.PerspectiveCamera(45, 1.5, 0.1, 1000);
            camera.position.set(30, 45, 30);
            camera.lookAt(scene.position);
            var controls = new THREE.OrbitControls(camera);

            var renderer = new THREE.WebGLRenderer();
            renderer.setSize(300, 200);

            document.getElementById("WebGL-area").appendChild(renderer.domElement);

            render();

            function render() {
                controls.update();
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }
        }
        window.onload = init
    </script>
</body>
</html>

效果图: image

rainit2006 commented 6 years ago

动画实现

  1. 利用window.requestAnimationFrame方法
    APP.animate = function() {
      APP.cube.rotation.x = APP.cube.rotation.x + 0.01;
      APP.cube.rotation.y = APP.cube.rotation.y + 0.01;
      APP.renderer.render(APP.scene, APP.camera);
      window.requestAnimationFrame( APP.animate );
    }
rainit2006 commented 6 years ago

three.js meshのグループ化 複数meshを同時に動かしたい時とか

var boxes = new THREE.Group();

    // 先ほどのboxをグループに追加
    boxes.add(box);
    boxes.add(box2);

    // sceneに追加
    scene.add(boxes);

rainit2006 commented 6 years ago

Scene

THREE.Scene.getObjectName('cube-1');

rainit2006 commented 6 years ago

更换mesh的颜色

            var geometry = new THREE.BoxGeometry( 1, 1, 1 );
            var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
            var cube = new THREE.Mesh( geometry, material );
            scene.add( cube );

            camera.position.z = 5;
            var index = 0;
            function animate() {
                requestAnimationFrame( animate );

                cube.rotation.x += 0.1;
                cube.rotation.y += 0.1;
                //cube.color=Three.color(0xff00ff);
                if(index >= 200 ){
                                        ////在这里进行颜色变换处理
                    material = new THREE.MeshBasicMaterial( { color: 0x00ffff } );
                    cube.material = material;
                }
                index ++;

                renderer.render( scene, camera );
            }
            animate();
rainit2006 commented 6 years ago

動畫實現: 數據移動軌跡圖

                    // global variables
                    var renderer;
                    var scene;
                    var camera;
                    var cameraControl;
                    var geometry;
                    var material;
                    var plotMesh;
                    var dataplot;
                    var plot;

                    function init() {

                    // create a scene, that will hold all our elements such as objects, cameras and lights.
                    scene = new THREE.Scene();

                    // create a camera, which defines where we're looking at.
                    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
                    camera.position.set(200, 0, 75);

                    // create a render, sets the background color and the size
                    renderer = new THREE.WebGLRenderer();
                    renderer.setClearColor(0xffffff, 1.0);
                    renderer.setSize(window.innerWidth, window.innerHeight);
                    renderer.shadowMapEnabled = true;

                    // add controls
                    cameraControl = new THREE.OrbitControls(camera);

                    // Scatter plot
                    scatterPlot = new THREE.Object3D();
                    scene.add(scatterPlot);

                    // Make grid
                    xzColor = 'red';
                    xyColor = '0x33CCFF';
                    yzColor = 'yellow';
                    var colorSet = d3.scale.linear().domain([0,5]).range(["red", "yellow"]).interpolate(d3.interpolateLab);
                    console.log(colorSet(0));

                    var gridXZ = new THREE.GridHelper(600, 10, "red", "black");
                    gridXZ.position.set(0, 00, 0);
                    scatterPlot.add(gridXZ);
/*
                    var gridXY = new THREE.GridHelper(600, 50);
                    gridXY.position.set(0, 0, 00);
                    gridXY.rotation.x = Math.PI / 2;
                    gridXY.setColors(new THREE.Color(xyColor), new THREE.Color(xyColor));
                    scatterPlot.add(gridXY);

                    var gridYZ = new THREE.GridHelper(600, 50);
                    gridYZ.position.set(00, 0, 0);
                    gridYZ.rotation.z = Math.PI / 2;
                    gridYZ.setColors(new THREE.Color(yzColor), new THREE.Color(yzColor));
                    scatterPlot.add(gridYZ);
*/
                    // Make Plot
                    geometry = new THREE.SphereGeometry(5, 50, 50);
                    material = new THREE.MeshNormalMaterial();
                    plotMesh = new THREE.Mesh(geometry, material);
                    plotMesh.name = 'plot';
                    scene.add(plotMesh);
                    // 位置設定                                                
                    plotMesh.position.set(0,0,0);   

                    plot = [i];

                    for (var i = 0; i < 100; i++) {
                        var vertex = new THREE.Vector3();

                        var max = 500;
                        var min = -500;

                        vertex.x = Math.random() * (max - min) + min;
                        vertex.y = Math.random() * (max - min) + min;
                        vertex.z = Math.random() * (max - min) + min;

                        geometry.vertices.push(vertex);
                    }

                    dataplot = new THREE.Mesh(geometry, material);
                    scatterPlot.add(dataplot);

                    //document.body.appendChild(renderer.domElement);
                    document.getElementById("container-3d").appendChild( renderer.domElement );

                    var index = 0;
                    var position = [{x: 10, y: 10, z:10}, {x: 50, y: 50, z:50}, {x: 100, y: 50, z:50}, {x: 150, y: 50, z:50}, {x: 210, y: 50, z:50}];

                    render();

                    setInterval(function(){

                                if( index < 5){
                                    // Make Plot
                                    geometry = new THREE.SphereGeometry(5, 50, 50);
                                    material = new THREE.MeshBasicMaterial({color: colorSet(0)});
                                    plotMesh = new THREE.Mesh(geometry, material);
                                    plotMesh.name = 'plot'+ index;
                                    scene.add(plotMesh);
                                    // 位置設定                                                
                                    plotMesh.position.set(position[index]["x"],position[index]["y"],position[index]["z"]);   

                                    for(var n=0; n < index; n++)
                                    {
                                            var name = "plot"+ String(n);
                                            var object = scene.getObjectByName(name);
                                            console.log(object);
                                            var col_index = index > n ? (index-n):0; 
                                            material = new THREE.MeshBasicMaterial({color: colorSet(col_index)});
                                            object.material = material;
                                    }

                                    //var object = scene.getObjectByName( "plot" );
                                    //material = new THREE.MeshBasicMaterial({color: 0xffff00});
                                    //object.material = material;

                                }
                                index ++;
                            }, 
                            1000);

                    }

                    function render() {

                        // update the camera
                        cameraControl.update();

                        // and render the scene
                        renderer.render(scene, camera);

                        // render using requestAnimationFrame
                        requestAnimationFrame(render);
                    }

                    function handleResize() {
                        camera.aspect = window.innerWidth / window.innerHeight;
                        camera.updateProjectionMatrix();
                        renderer.setSize(window.innerWidth, window.innerHeight);
                    }

                    // calls the init function when the window is done loading.
                    window.onload = init;
                    // calls the handleResize function when the window is resized
                    window.addEventListener('resize', handleResize, false);