精华内容
下载资源
问答
  • Threejs初教程

    2021-07-20 10:05:38
    Threejs初教程学习记录 threejs是什么 可以做什么 three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。 Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、...

    Threejs初教程学习记录

    threejs是什么 可以做什么

    1. three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。
    2. Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象
    3. vue-3D可以将3D模型展示到浏览器中,进行展示 滑动 转动
    4. threejs可以做更多关于3D的东西

    threejs文档教程 官网 案例

    能提供的就这么多了,我相信html能实现的vue也能全面实现

    1. threejs中文文档
    2. threejs国外官网
    3. threejs初级案例下载

    好了 开始学习 第一课

    场景 scene 、相机camera 和渲染器renderer 必不可少 还要添加网格Mesh 模型BoxGeometry 模型材质MeshBasicMaterial 光源PointLight 颜色对象color 纹理属性Texture 添加到场景中

    场景

    var scene = new THREE.Scene(); //创建场景

    相机 摄像机

    相机共同配置

    camera.position.set(0, 0, 5);//设置相机距离模型距离 不写默认会 0,0,0 ,模型也是0,0,0重合不显示
    camera.lookAt(new THREE.Vector3(0, 0, 0));//设置相机观察的目标点 正中央
    //相机设置全部完成后 加入场景中
     scene.add(camera);
    

    three.js里有几种不同的相机

    1 (透视摄像机)

    四个参数fov:视野角度 w/h:长宽比 近截面(near)和远截面(far)

     var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
    
    2正交摄像机OrthographicCamera
    new THREE.OrthographicCamera()构造函数用于创建一个正交摄像机,该构造函数中有六个参数,分别是left,right,top,bottom,near,far。
    left — 摄像机视锥体左侧面。
    right — 摄像机视锥体右侧面。
    top — 摄像机视锥体上侧面。
    bottom — 摄像机视锥体下侧面。
    near — 摄像机视锥体近端面。
    far — 摄像机视锥体远端面。
    left的值不能够大于right的值,而且left和right设置的值必须位于摄像机position中x坐标的两侧,否则将看不到影像。
    对应的top和bottom也一样,bottom值不能大于top值,且位于摄像机position坐标y值两边,否则也会看不到投影影像。
     var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
    

    正交摄像机第一次看到可能会很懵 但是多尝试一下还是可以理解的
    摄像机视锥体 不是很熟悉 但是这个值是决定x轴和y轴·和z轴的距离 值越大 物体宽高就要写的大点
    值越小 物体就可以写的很小 占的比例是相同的 left一般和right相加是等于零 right 和top 比例应该和画布大小比例相同
    举个栗子 画布大小为 w 400 h 300 right 和top比例应该是4比3 16比12 都可以
    四个值你写-4,4,3,-3 可以 你写 -16,16,12,-12 也可以
    正方形 x =2 y = 2 和 x=8 y = 8 是一样的大小
    z轴的话就不限制
    很懵 找到了解释的地方 下面有案例

    渲染器

    看到的不同都写上去
    第一种

    //页面
    <canvas id="mainCanvas" width="400px" height="300px" ></canvas>
    
    //定义渲染器
    var renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById('mainCanvas')
    });
    renderer.setClearColor(0x000000);       //设置渲染器背景颜色
    //最后一步 渲染
    renderer.render(scene, camera);
    

    第二种

    //页面为空
    //创建
    var renderer = new THREE.WebGLRenderer();
    document.body.appendChild( renderer.domElement );
    //最后一步渲染
    renderer.render( scene, camera );
    

    哪种实用就用哪种

    模型

    1 立方体

    参数为 X Y Z px py pz 的值 X Y Z也就决定正宽高高度 px py pz表示三个方向上的分段数

    //老版本立方体
    new THREE.CubeGeometry(1, 2, 3)
    //新版本立方体
    var geometry = new THREE.BoxGeometry( 1, 1, 1 ); 
    

    2 PlaneGeometry是二维平面几何体

    看上去是扁平的,因为它只有两个维度,给定宽高,即可创建这种几何体。 立方体
    width:x方向上的长度;
    height:是y方向上的长度;
    widthSegments:x轴方向的分段;
    heightSegments:y轴方向的分段。

    var planeGeo = new THREE.PlaneGeometry(1.5, 3);
    

    3 几何体 不太懂

    //见过的写法1
    var triGeo = new THREE.Geometry();//声明一个几何体对象Geometry
    triGeo.vertices = [new THREE.Vector3(0, -0.8, 0),new THREE.Vector3(-2, -0.8, 0), new THREE.Vector3(-1, 0.8, 0)];//三个顶点坐标  写几个坐标就是几条边
    triGeo.faces.push(new THREE.Face3(0, 2, 1));
    //见过的写法2  Z轴线条
    var zGeo = new THREE.Geometry();
    zGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    zGeo.vertices.push(new THREE.Vector3(0, 0, 5));
    var zMat = new THREE.LineBasicMaterial({
          color: 0x00ccff
    });
    var zAxis = new THREE.Line(zGeo, zMat);
    
    

    4 基本几何形状 球体

    //构造函数
    THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, thetaStart, thetaLength)
    radius:是半径;
    segmentsWidth:经度上的切片数,相当于经度被切成了几瓣;
    segmentsHeight:纬度上的切片数,相当于纬度被切成了几层;
    phiStart:经度开始的弧度;
    phiLength:经度跨过的弧度;
    thetaStart:纬度开始的弧度;
    thetaLength:纬度跨过的弧度。
    经度 X Y轴的圆
    纬度 Z轴的圆
    弧度为 Math.PI180° Math.PI/290° Math.PI/360° Math.PI/445°
    	  Math.PI/536° Math.PI/630°
    var sphere = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 6), material);
    // var sphere = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 6,
    //      0, Math.PI * 2, Math.PI / 6, Math.PI / 2), material);
    // var sphere = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 6,
    //      Math.PI / 2, Math.PI, Math.PI / 6, Math.PI / 2), material);
    // var sphere = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 6,
    //      Math.PI / 6, Math.PI / 3), material);
    // var sphere = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 6,
    //      0, Math.PI * 2, Math.PI / 6, Math.PI / 3), material);
    // var sphere = new THREE.Mesh(new THREE.SphereGeometry(3, 8, 6,
    //      Math.PI / 2, Math.PI, Math.PI / 6, Math.PI / 2), material);
    

    5 圆形(CircleGeometry)

    可以创建圆形或者扇形

    构造函数:
     THREE.CircleGeometry(radius, segments, thetaStart, thetaLength) 
    radius:半径;
    segments:以一个点为中心的切片数(切蛋糕?);
    thetaStart:开始位置;
    thetaLength:扇面跨度;
     var circle = new THREE.Mesh(new THREE.CircleGeometry(3, 18, Math.PI / 3, Math.PI / 3 * 4), material);
    

    6 圆柱体(CylinderGeometry) 圆台 圆锥 棱锥

    构造函数:
    THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded) 
    radiusTop:顶面的半径;
    radiusBottom:底面的半径;
    height:是圆柱体的高度;
    radiusSegments:两底面的分段切片;
    heightSegments:侧面的分段切片;
    openEnded:是一个布尔值,表示是否没有顶面和底面,缺省值为false,表示有顶面和底面。
    例如,new THREE.CylinderGeometry(2, 2, 4, 20, 20, false),将创建一个上下底面半径为2,高度为4,其各面的切片为20,有底面
    

    7 多面体

    构造函数
    正四面体(TetrahedronGeometry)、正八面体(OctahedronGeometry)、正二十面体(IcosahedronGeometry)的构造函数较为类似
    正四面体(TetrahedronGeometry)THREE.TetrahedronGeometry(radius, detail)
    正八面体(OctahedronGeometry):THREE.OctahedronGeometry(radius, detail)
    正二十面体(IcosahedronGeometry):THREE.IcosahedronGeometry(radius, detail)
    radius:半径;
    detail:细节层次(Level of Detail)的层数
    这里我们不对detail多作展开,一般可以对这个值缺省。
    正四面体 :var tetra = new THREE.Mesh(new THREE.TetrahedronGeometry(3), material);
    正八面体:var octa = new THREE.Mesh(new THREE.OctahedronGeometry(3), material);
    正二十面体:var icosa = new THREE.Mesh(new THREE.IcosahedronGeometry(3), material);
    

    8 圆环面(TorusGeometry)

    构造函数  THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)
    radius:圆环半径;
    tube:管道半径;
    radialSegments与tubularSegments分别是两个分段数,详见下图;
    arc是圆环面的弧度,缺省值为Math.PI * 2

    偷来的详解

    9 圆环结(TorusKnotGeometry)

    构造函数THREE.TorusKnotGeometry(radius, tube, radialSegments, tubularSegments, p, q, heightScale)
    圆环节和圆环很相似,只是多了一些参数。
    radius : 圆环的半径,默认值为1。
    tube : 管道的半径,默认值为0.4。
    tubularSegments : 管道的分段数量,默认值为64。
    radialSegments : 横截面分段数量,默认值为8。
    p : 这个值决定了几何体将绕着其旋转对称轴旋转多少次,默认值是2。
    q : 这个值决定了几何体将绕着其内部圆环旋转多少次,默认值是3var torus = new THREE.Mesh(new THREE.TorusKnotGeometry(2, 0.2, 30, 10), material);
    var torus = new THREE.Mesh(new THREE.TorusKnotGeometry(2, 0.2, 230, 8,4,3), material);
    

    10 管道体 TubeGeometry

    TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean)
    其中各参数描述如下:
    path — Curve - 从曲线基类继承的路径(曲线,路径,即管道的形状)
    tubularSegments — Integer - 构成管的段数,默认为64(管道分成多少段)
    radius — Float - 管的半径,默认值为1(管道的半径)
    radialSegments — Integer - 构成横截面的线段数,默认值为8 (管道口分成多少段,即管道口是几边形)
    closed — Boolean 管是否打开或关闭,默认值为false (是否闭合管道,首尾相接的意思)
    用法:
    function CustomSinCurve( scale ) {
    	THREE.Curve.call( this );
    	this.scale = ( scale === undefined ) ? 1 : scale;
    }
    CustomSinCurve.prototype = Object.create( THREE.Curve.prototype );
    CustomSinCurve.prototype.constructor = CustomSinCurve;
    CustomSinCurve.prototype.getPoint = function ( t ) {
    	var tx = t * 3 - 1.5;
    	var ty = Math.sin( 2 * Math.PI * t );
    	var tz = 0;
    	return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
    };
    var path = new CustomSinCurve( 10 );
    var tube = new THREE.Mesh(new THREE.TubeGeometry( path, 20, 1, 3, false ), material);
    

    11 三维文字TextGeometry

    更好(容易)地生成三维文字
    构造函数 THREE.TextGeometry(text : String, parameters : Object)
    text — 需要显示的文本. (要显示的字符串)
    parameters — 对象,该对象可以包含以下参数
    	font — an instance of THREE.Font.(字体格式)
    	size — Float. 文本的大小。默认值为100.(字体大小)
    	height — Float. 拉伸文本的厚度。默认值为50.(字体的深度)
    	curveSegments — Integer. 曲线上的点数。默认值为12.(曲线控制点数)
    	bevelEnabled — Boolean. 是否启用“倒角”。默认值为False.(斜角)
    	bevelThickness — Float. 斜角的深度。默认值为10.(斜角的深度)
    	bevelSize — Float. 斜角的大小。默认值为8.(斜角的大小)
    	bevelSegments — Integer. 斜面段数。默认值为3.(斜角段数)
    

    材质

    我们知道一个材质结合 THREE.Geometry 对象,可以构成 THREE.Mesh 对象。材质就像物体的皮肤,决定了几何体的外表。例如皮肤定义了一个几何体看起来是否像金属、透明与否、或者显示为线框。


    程序后面如果要改变材质或者模型可这样子写进行覆盖

     var material = new THREE.MeshLambertMaterial({
         color: 0xffff00
    });
    var geometry = new THREE.CubeGeometry(1, 2, 3);
    var mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
                    
    mesh.material = new THREE.MeshLambertMaterial({
         color: 0x00ff00
    });
    

    看这 这个解释在有详细解释 各种材质 解释 共同属性等 https://www.hangge.com/blog/cache/detail_1815.html


    MeshBasicMaterial是一种非常简单的材质,这种材质不考虑场景中光照的影响。使用这种材质的网格会被渲染成简单的平面多边形,而且也可以显示几何体的线框。

    1 当网格中加入 wireframe: true 会变成几何体边框 普通材质

    //color(颜色)	设置材质的颜色
    //wireframe(线框)	设置这个属性的可以将材质渲染成线框,非常适合调试
    //wireframeLinewidth(线框宽度)	如果已经打开了wirefreme,这个属性定义线框中线的宽度
    //wireframeLinecap(线框线段端点)	这个属性定义了线框模式下顶点键线段的端点如何显示。可选的值包括butt(平)、round(圆)和square(方)。默认值为round。在实际使用中,这个属性的修改结果很难看出来。WebGLRenderer对象不支持该属性。
    //wireframeLinejoin(线框线段连接点)	这个属性定义了线段的连接点如何显示。可选的值有round(圆)、bevel(斜角)和miter(尖角)。默认值为round。如果你在一个使用低透明度和wireframeLinewidth值很大的例子里靠近观察,就可以看到这个属性的效果。WebGLRenderer对象不支持该属性
    //shading(着色)	该属性定义如何着色。可选的值有THREE.SmoothShading、THREE.NoShading和THREE.FlatShading。默认值为THREE.SmoothShading,这将产生一个平滑的对象,看不到单个面
    //vertexColors(顶点颜色)	可以通过这个属性给每个顶点定义不同的颜色。默认值为THREE.NoColors。如果将这个值设置为THREE.VertexColors,渲染器会采用THREE.Geometry对象的colors属性的值。该属性对象CanvasRenderer不起作用,但对WebGLRenderer起作用
    //fog(雾化)	该属性指定当前材质是否受全局雾化效果设置的影响。默认true,如果设置为false,将不会受雾化的影响
    var material = new THREE.MeshBasicMaterial( { color: 0x00ff00,<--wireframe: true--> } );
    

    2 THREE.LineBasicMaterial用于绘制线段的基础材质。

    //color :该属性设置材质的颜色,如果设置了vertexColors,这是属性将被忽略
    //linewidth :设置线的宽度,默认值为1.0
    //linecap :这个属性定义了线框模式下顶点间线段的端点如何显示。可选的值包括butt(平)、round(圆)和square(方)。默认值为round。在实际使用中,这个属性的修改结果很难看出来。WebGLRenderer对象不支持该属性
    //linejoin :这个属性定义了线段的连接点如何显示。可选的值有round(圆)、bevel(斜角)和miter(尖角)。默认值为round。
    //如果你在一个使用低透明度和很大wireframeLinewidth值的例子里靠近观察,就可以看到这个属性的效果。WebGLRenderer对象不支持该属性
    //vertexColors :将这个属性设置成THREE.VertexColors值,就可以给每个顶点指定一种颜色
    //fog :该属性指定当前材质是否受全局雾化效果设置的影响
    var material = new THREE.LineBasicMaterial( {
        color: 0xffffff,
        linewidth: 1,
        linecap: 'round', 
        linejoin:  'round' 
    } );
    

    3 高级材质THREE.MeshLambertMaterial

    //这种材质可以用来创建暗淡的并不光亮的表面。
    //无光泽表面的材质,无镜面高光。
    //这可以很好地模拟一些表面(如未经处理的木材或石头),但不能用镜面高光(如上漆木材)模拟光泽表面。
    //该材质非常易用,而且会对场景中的光源产生反应。
    //构造函数
    var cubeMaterial = new THREE.MeshLambertMaterial({color: 0x00ffff});//实例化一个蓝色的材质
    //参数
    
    名称描述
    color(颜色)设置材质的颜色
    wireframe(线框)设置这个属性可以将材质渲染成线框,非常适用于调试。
    wireframeLinewidth(线框线宽)如果已经打开了 wireframe,这个属性定义线框中线的宽度
    wireframeLinecap(线框线段端点)这个属性定义了线框模式下顶点间线段的端点如何显示。可选的值包括:round 圆(默认值)butt:平 square:方 WebGLRenderer 对象不支持该属性
    wireframeLinejoin(线框线段连接点)这个属性定义了线段的连接点如何显示。可选的值有:round:圆(默认值) bevel:斜角 miter:尖角 如果在一个使用低透明度和 wirefiameLinewidth 值很大的例子里靠近观察,就可以看到这个属性的效果。 WebGLRenderer 对象不支持该属性。
    shading(着色)该属性定义如何着色。可选的值有: THREE.SmoothShading(默认值,这个将产生一个平滑的对象,看不到单个面) THREE.NoShading THREE.FlatShading
    vertexColors(顶点颜色)可以通过这个属性给每个顶点定义不同的颜色。默认值为:THREE.NoColors。如果将这个值设置为 THREE.VertexColors,渲染器会采用 THREE.Geometry 对象的 colors 属性的值。该属性对 CanvasRenderer不起作用,但对 WebGLRender 起作用。比如我们可以使用该属性为线段的不同部分设置不同的颜色。也可以使用这个属性为这种材质类型创建渐变效果。
    fog(雾化)该属性指定当前材质是否受全局雾化效果设置的影响。如果将该属性设置为 false,那么我们全局雾化效果设置就不会影响当前对象的渲染

    4 THREE.MeshPhongMaterial(网格 Phong 材质)

    可以创建一种光亮的材质。

    网格

    两个参数 模型 和 材质

    var plane = new THREE.Mesh(planeGeo, material);
    

    网格配置

    plane.position.x = 1;//向X轴移动1
    plane.position.y = 1;//向y轴移动1
    plane.position.z = 1;//向z轴移动1
    plane.position.set(-1.6,0,0)//x y z
    plane.rotation.set(-1.6,0,0)//旋转角度 x y z
    

    绘制轴

    // x-axis
    var xGeo = new THREE.Geometry();
    xGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    xGeo.vertices.push(new THREE.Vector3(5, 0, 0));
    var xMat = new THREE.LineBasicMaterial({
        color: 0xff0000
    });
    var xAxis = new THREE.Line(xGeo, xMat);
    scene.add(xAxis);
                    
    // y-axis
    var yGeo = new THREE.Geometry();
    yGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    yGeo.vertices.push(new THREE.Vector3(0, 5, 0));
    var yMat = new THREE.LineBasicMaterial({
        color: 0x00ff00
    });
    var yAxis = new THREE.Line(yGeo, yMat);
    scene.add(yAxis);
                    
    // z-axis
    var zGeo = new THREE.Geometry();
    zGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    zGeo.vertices.push(new THREE.Vector3(0, 0, 5));
    var zMat = new THREE.LineBasicMaterial({
        color: 0x00ccff
    });
    var zAxis = new THREE.Line(zGeo, zMat);
    scene.add(zAxis);
                
    

    旋转是让在模型的网格旋转 模型才会旋转

    正交摄像机 和 透视摄像机看到的框架也不相同

    加载 FontLoader 字体库

    var loader = new THREE.FontLoader();
    loader.load('../lib/helvetiker_regular.typeface.json', function(font) {
         var mesh = new THREE.Mesh(new THREE.TextGeometry('/', {
               font: font,
               size: 1,
                height: 1
        }), material);
        scene.add(mesh);
                       
        // render
        renderer.render(scene, camera);
    });
    

    Threejs支持了许多格式的3D模型导入,包括*.obj、 .sea、.3mf 、.amf、.sea、.pmd、.json等。

    加载外部模型 OBJ类型 OBJLoader

    THREE.OBJLoader() 函数说明:

    objLoader.setMaterials( materials ):设置obj使用的材质贴图
    objLoader.setPath( options.objPath ):设置obj文件所在路径
    objLoader.load( filename,onSuccess(object ),onProgress(xhr),onError(error)):obj文件名、 加载成功后回调处理(参数为生成的三维对象)、加载过程中回调处理(xhr对象属性可计算出已完成加载百分比)、失败回调处理。
    在onSuccess(object ){}回调里我们可以对生成的三维对象做一些处理:对材质进行调色、设置透明度、设置贴图模式等,对设置旋转、缩放、位置摆放、自发光颜色、环境光颜色。
    如果obj文件代表的三维对象是由多个子模型构成的模型组合,我们可以调用object.traverse(function(child){})来对每个子模型进行处理。

    //上面摄像机
    var loader = new THREE.OBJLoader();
    loader.load('../lib/port.obj', function(obj) {
           obj.traverse(function(child) {
               if (child instanceof THREE.Mesh) {
                  child.material.side = THREE.DoubleSide;
              }
          });
          mesh = obj;
          scene.add(obj);
    });
    //下面光源
    

    修改OBJ文件的颜色等

    //上面摄像机
     var loader = new THREE.OBJLoader();
     loader.load('../lib/port.obj', function(obj) {
           obj.traverse(function(child) {
                 if (child instanceof THREE.Mesh) {
                       child.material = new THREE.MeshLambertMaterial({//高级材质
                             color: 0xff0000,
                             side: THREE.DoubleSide
                        });
                  }
            });
                        
            mesh = obj;
            scene.add(obj);
    });
    //下面光源
    

    加载外部模型 mtl类型 MTLLoader

    THREE.MTLLoader()函数说明:
    mtlLoader.setBaseUrl():设置材质路径
    mtlLoader.setPath():设置mtl文件所在路径
    mtlLoader.load(filename,onSuccess(materials ),onProgress(xhr),onError(error)):mtl文件名、 加载成功后回调处理(参数为生成的材质库)、加载过程中回调处理(xhr对象属性可计算出已完成加载百分比)、失败回调处理

    //上面摄像机
    var mtlLoader = new THREE.MTLLoader();
    mtlLoader.setPath('../lib/');
    mtlLoader.load('port.mtl', function(materials) {
    	materials.preload();
    	// model loader
    	var objLoader = new THREE.OBJLoader();
    	objLoader.setMaterials(materials);
    	objLoader.setPath('../lib/');
    	objLoader.load('port.obj', function(object) {
    		object.position.y = -95;
    		// if has object, add to scene
    		if(object.children.length > 0) {
    			scene.add(object.children[0]);
    		}
    	});
    });
    //下面光源
    

    加载外部模型 dae类型 ColladaLoader

    Collada是一种用基于XML的格式定义数字内容的格式。这也是一种被广泛使用的格式,差不多所有的三维软件和渲染引擎都支持这种格式。
    Collada模型中不仅定义了几何体,也定义了材质,甚至还可以定义光源。

    //上面摄像机
    var loader = new THREE.ColladaLoader();
        loader.load('../lib/port.dae', function (collada) {
             if (collada.scene.children.length > 0) {
                 scene.add(collada.scene.children[0]);
            }
        });
    //下面光源
    

    光源

    点光源

    PointLight 点光源,照射所有方向的光源,例如灯泡发出的光,可以投射阴影。

    构造函数
    PointLight( color : Integer, intensity : Float, distance : Number, decay : Float )
    参数 :color:光源的颜色  intensity:光源的强度  distance:光的照射距离  decay:光的衰减指数
    属性:
    .decay : Float:光源的衰减指数
    .distance : Float:光的照射距离
    .isPointLight : Boolean:判断是否是点光源
    .power : Float:光照强度,power = intensity * 4π
    .shadow : LightShadow:阴影
    方法: .copy ( source : PointLight ) : PointLight:把所有的属性复制到光源
    

    环境光源

    THREE.AmbientLight()环境光源,一般不会单独使用,需要配合其他光源类似使用。
    环境光会照亮场景中的所有物体,不能用来投射阴影,因为环境光是没有方向的。
    不需要指定位置。

    var light = new THREE.AmbientLight(0xcccccc);
    //color:颜色值,默认为白色
    //intensity:光的强度,默认为1
    

    聚光灯

    THREE.SpotLight 聚光灯 是一种具有锥形效果的光源,该光源拥有产生光的方向和角度。我们可以将其与手电筒或者灯笼产生的光进行对比。THREE.SpotLight 是最常使用的光源之一

    构造函数
    SpotLight( color : Integer, intensity : Float, distance : Float, angle : Radians, penumbra : Float, decay : Float )
    //color - (可选) 十六进制颜色的光 默认为 0xffffff(white).
    //intensity - (可选) 光的强度数值. 默认值为1.
    //distance - 光源从原点发出的距离,值越大,光的强度会逐渐衰减.
    //angle - 光源的散射角度默认为Math.PI/2.
    //penumbra - 光影聚焦的百分比 0-1之间,默认值为0,所以阴影会产生锯齿效果.
    //decay - 光在距离上的强度.
    

    方法:
    angle:角度。即光源发射出的光束的宽度。单位是弧度,默认值:Math.PI/3
    castShadow:投影。如果设置为 true,这个光源就会生成阴影。
    color:光源颜色。
    distance:光源照射的距离。默认值为 0,这意味着光线强度不会随着距离增加而减弱。
    exponent:光强衰减指数。使用 THREE.SpotLight 光源,发射的光线的强度随着光源距离的增加而减弱。exponent 属性决定了光线强度递减的速度。使用低值,从光源发出的光线将到达远处的物体,而使用高值,光线仅能到达非常接近 THREE.SpotLight 光源的物体。
    intensity:光源照射的强度。默认值:1
    onlyShadow:仅阴影。如果此属性设置为 true,则该光源只生成阴影,而不会在场景中添加任何光照。
    position:光源在场景中的位置
    shadow.bias:用来偏置阴影的位置。当你使用非常薄的对象时,可以使用它来解决一些奇怪的效果。如果你看到奇怪的阴影效果,将该属性设置为很小的值(例如 0.01)通常可以解决问题。此属性的默认值为 0。
    shadow.camera.far:投影远点。表示到距离光源的哪一个位置可以生成阴影。默认值:5000
    shadow.camera.fov:投影视场。表示用于生成阴影的视场有多大。默认值:50
    shadow.camera.near:投影近点。表示距离光源的哪一个位置开始生成阴影。默认值为 50
    shadow.map.width 和 shadow.map.height:阴影映射宽度和阴影映射高度。决定了有多少像素用来生成阴影。当阴影具有锯齿状边缘或看起来不光滑时,可以增加这个值。在场景渲染之后无法更改。两者的默认值均为:512
    target:目标。使用 THREE.SpotLight 光源时,它的指向很重要。使用 target 属性,你可以将 THREE.SpotLight 光源指向场景中的特定对象或位置。注意,此属性需要一个 THREE.Object3D 对象(如 THREE.Mesh)。
    visible:是否可见。如果该属性设置为 true(默认值),该光源就会打开。如果设置 false,光源就会关闭。

    平行光

    THREE.DirectionalLight 平行光 可以看作距离很远的光。它发出的所有光线都是平行的。比如太阳光,由于太阳离我们很远,我们可以把太阳的光线看作是平行的。

    与点光源和聚光灯光源的区别
    最大的区别就是,点光源和聚光灯光源距离物体越远光线越暗。光是从一点发出的。
    而被平行光照亮的整个区域接收到的光强是一样的。光是平行的。

    //第一个参数 Hex:光的颜色 第二个参数 Intensity:光源的强度,默认是1.0,如果为0.5,则强度是一半,意思是颜色会淡一些
    //第三个参数 Distance:光线的强度,从最大值衰减到0,需要的距离。 默认为0,表示光不衰减,如果非0,则表示从光源的位置到Distance的距离,光都在线性衰减。到离光源距离Distance时,光源强度为0.
    var light = new THREE.DirectionalLight(0xFF0000,1, 0);
    var light = new THREE.DirectionalLight(0xffffff);
    light.position.set(20, 10, 5);//位置
    

    Color颜色对象,有以下多种初始化方法。

    //空的构造函数 -- 默认为白色
    var color = new THREE.Color();
    
    //十六进制颜色 (推荐使用)
    var color = new THREE.Color( 0xff0000 );
    
    //RGB 字符串
    var color = new THREE.Color("rgb(255, 0, 0)");
    var color = new THREE.Color("rgb(100%, 0%, 0%)");
    
    //颜色值 - 140 种支持,不是驼峰命名
    var color = new THREE.Color( 'skyblue' );
    
    //HSL 字符串
    var color = new THREE.Color("hsl(0, 100%, 50%)");
    
    //RGB 值 在 0 到 1 之间
    var color = new THREE.Color( 1, 0, 0 );
    

    Texture 纹理属性

    构造函数
    Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy )
    //id	此纹理实例的唯一编号。
    //uuid	此对象实例的UUID。这会自动分配,所以不应该编辑。
    //name	对象的名称,可以重复,默认值为空字符串
    //image	一个Image对象,通常使用 ImageUtils 或 ImageLoader 类来创建。Image对象可以包括图像 (比如 PNG, JPG, GIF, DDS), 视频 (e.g., MP4, OGG/OGV), 或者六幅图像的集合用于一个立方体贴图。 要使用视频作为一个纹理,你需要把一个HTML5视频元素作为纹理图像的源,并在视频播放时不断更新这个纹理-VideoTexture类会自动处理。
    //mipmap	用户指定的mipmap数组(可选)
    //mapping	如何将图像应用到对象。默认为 UV贴图(THREE.UVMapping)类型,这里U,V 坐标用来应用映射,要求是单个纹理。其他类型包括:THREE.CubeReflectionMapping:立方体反射映射THREE.CubeRefractionMapping:立方体折射映射THREE.EquirectangularReflectionMapping:圆柱反射映射THREE.EquirectangularRefractionMapping:圆柱折射映射THREE.SphericalReflectionMapping:球面反射映射
    //wrapS	缺省为 THREE.ClampToEdgeWrapping, 表示边缘被夹到纹理单元(texels)的外边界。THREE.ClampToEdgeWrapping:夹边。超过1.0的值被固定为1.0。超过1.0的其它地方的纹理,沿用最后像素的纹理。用于当叠加过滤时,需要从0.0到1.0精确覆盖且没有模糊边界的纹理。其他两个选项是:THREE.RepeatWrapping:平铺重复。超过1.0的值都被置为0.0。纹理被重复一次。在渲染具有诸如砖墙之类纹理的物体时,如果使用包含一整张砖墙的纹理贴图会占用较多的内存,通常只需载入一张具有一块或多块砖瓦的较小的纹理贴图,再把它按照重叠纹理寻址模式在物体表面映射多次,就可以达到和使用整张砖墙贴图同样的效果。THREE.MirroredRepeatWrapping:镜像重复。每到边界处纹理翻转,意思就是每个1.0 u或者v处纹理被镜像翻转。
    //wrapT	缺省为 THREE.ClampToEdgeWrapping, 表示边缘被夹到纹理单元(texels)的外边界。其他两个选项是 THREE.RepeatWrapping 和 THREE.MirroredRepeatWrapping。注意: 平铺图像纹理仅在图像尺寸是2的幂次方(2,4,8,16,32,64,128,256,512,1024,2048,…)时工作。每个维度的值不一定是相同的,但每一个维度都必须是2的幂次方。这是WebGL的限制,不是Three.js的。
    //magFilter	该属性定义当一个纹理单元(texel)覆盖多个像素点时纹理如何采样。缺省为 THREE.LinearFilter,表示获取4个最近的纹理单元执行双向线性插值计算(显示效果好)。另外的选项是 THREE.NearestFilter, 表示使用最近的texel(性能优)。
    //minFilter	该属性定义当一个纹理单元(texel)不足以覆盖单个像素点时纹理如何采样。缺省为 THREE.LinearMipMapLinearFilter, 表示使用多级纹理贴图(mipmapping)以及一个三线性滤波器。其他选项是:THREE.NearestFilter:最近滤镜。在纹理基层上执行最邻近过滤。THREE.NearestMipMapNearestFilter:选择最临近的mip层,并执行最临近的过滤。THREE.NearestMipMapLinearFilter:在mip层之间执行线性插补,并执行最临近的过滤。THREE.LinearFilter:在纹理基层上执行线性过滤。THREE.LinearMipMapNearestFilter:选择最临近的mip层,并执行线性过滤。THREE.LinearMipMapLinearFilter:在mip层之间执行线性插补,并执行线性过滤。
    //anisotropy	表示纹理的各向异性。沿纹理单元密度最高方向的轴线所取样本数。默认情况下,这个值为1。较高的值比基础MipMap要更清晰,但需要更多的采样。 使用renderer.getMaxAnisotropy()方法来找到GPU最大有效各向异性值;这个值通常是2的幂次方。
    //format	缺省纹理格式为THREE.RGBAFormat。其他格式有:THREE.AlphaFormat:对应于GL_ALPHA。Alpha 值THREE.RGBFormat:Red, Green, Blue 三原色值THREE.RGBAFormat:Red, Green, Blue 和 Alpha 值THREE.LuminanceFormat:灰度值THREE.LuminanceAlphaFormat:灰度值和 Alpha 值THREE.RGBEFormat
    //type	缺省纹理格式为THREE.RGBAFormat。其他格式有:THREE.UnsignedByteType:无符号8位整形值(1个字节)THREE.ByteType:带符号8位整形值(1个字节)THREE.ShortType:带符号16位整形值(2个字节)THREE.UnsignedShortType:无符号16未整形值(2个字节)THREE.IntType:带符号32位整形值(4个字节)THREE.UnsignedIntType:无符号32位整形值(4个字节)THREE.FloatType:单精度浮点型(4个字节)THREE.HalfFloatType:半浮点型
    //offset	在U和V方向上,纹理在模型表面上重复绘制时的偏移。通常范围是0.0 到 1.0。注意: offset属性是一个便捷修饰符,仅影响Texture对模型上第一组UV的应用。如果纹理用作需要额外UV集的贴图(例如,大多数库存材料的aoMap或lightMap),则必须手动分配这些UV以获得所需的偏移量。
    //repeat	纹理在整个表面上重复多少次,在每个方向U和V上。如果在任一方向上repeat设置为大于1,则相应的Wrap参数也应设置为 THREE.RepeatWrapping或THREE.MirroredRepeatWrapping以实现所需的平铺影响。注意: repeat属性是一个便捷修饰符,仅影响Texture对模型上第一组UV的应用。如果纹理用作需要额外UV集的贴图(例如,大多数库存材料的aoMap或lightMap),则必须手动分配这些UV以实现所需的重复。
    //rotation	纹理围绕中心点旋转多少,以弧度表示。正值是逆时针的。缺省值是0。
    //center	旋转发生的点。值(0.5,0.5)对应于纹理的中心。默认值是(0,0),左下角。
    //matrixAutoUpdate	是否更新纹理的UV-变换.matrix从纹理特性.offset,.repeat, .rotation和.center。默认情况下为真。如果直接指定uv-transform矩阵,则将其设置为false。
    //matrix	纹理的uv转换矩阵。从质地特性渲染更新.offset,.repeat, .rotation和.center当纹理的.matrixAutoUpdate属性为true。当.matrixAutoUpdate属性为false时,可以手动设置此矩阵。默认值是单位矩阵。
    //generateMipmaps	是否为纹理生成mipmap(如果可能)。默认情况下为真。如果您手动创建mipmap,请将其设置为false。
    //premultiplyAlpha	在默认情况下,这是PNG图像的标准。如果RGB值已被预乘alpha,则设置为true。
    //flipY	默认为真。翻转图像的Y轴以匹配WebGL纹理坐标空间。
    //unpackAlignment	默认值为4。指定内容中每个像素行起点的对齐要求。有效值有 1 (字节对齐byte-alignment), 2 (行起点按偶数字节对齐), 4 (字对齐word-alignment), 和 8(行起点按双字对齐)。参阅:glPixelStorei 以了解更多信息。
    //encoding	编码方式。默认设置为 THREE.LinearEncoding,但是支持 sRGB, RGBE, RGBM, RGBD, LogLuv 和 Gamma。 重要:如果纹理中的这个值在材料已用后被改变,则需要触发一个Material.needsUpdate操作,以便该值在着色器中得到实现。
    //version	从0开始计算needsUpdate更新次数
    //onUpdate	一个回调函数,当纹理被更新时调用(例如,当needsUpdate被设置为true并且纹理被使用时)。
    //needsUpdate	将其设置为true以在下次使用纹理时触发更新。对于设置换行模式尤为重要。
    
    //案例:
    // load a texture, set wrap mode to repeat
    var texture = new THREE.TextureLoader().load( "textures/water.jpg" );
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set( 4, 4 );
    //放入材质
    var material = new THREE.MeshLambertMaterial({
                        map: texture
                    });
    

    另外要知道的小知识

    window.requestAnimationFrame()

    window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
    在threejs用到的有

    var requestAnimationFrame = window.requestAnimationFrame 
                        || window.mozRequestAnimationFrame
                        || window.webkitRequestAnimationFrame
                        || window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
    
     id = requestAnimationFrame(draw);//传入一个函数 返回一个非零值 可当作id
     function draw() {
              mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
              renderer.render(scene, camera);
              id = requestAnimationFrame(draw);//继续调用 id更新
    }
    function stop() {
            if (id !== null) {
                window.cancelAnimationFrame(id);//传入id 停止调用
                id = null;
            }
    }
     
    

    THREEJS状态显示类stats的应用

    效果如下:
    在这里插入图片描述
    当前场景的显存占用问题
    在这里插入图片描述
    当前场景的渲染帧率
    用法:

    //引入文件 ../lib/stat.js
    //初始化的时候
    var stat = null;
    stat = new Stats();
    stat.domElement.style.position = 'absolute';
    stat.domElement.style.right = '0px';
    stat.domElement.style.top = '0px';
    document.body.appendChild(stat.domElement);
    //渲染的时候
    stat.begin();
    mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
    renderer.render(scene, camera);
    stat.end();
    
    展开全文
  • Threejs 框选功能

    2021-10-20 10:13:03
    threejs 框选功能@TOC 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 新的改变 ...

    Threejs 框选功能

    在threejs中模型交互主要是通过射线检测选中单个物体或者在这条射线上的物体,如果要选择多个物体就比较麻烦了,框选功能比较适合这种。下面的代码只支持透视相机
    threejs版本为 0.124.0
    框选模型节点效果

    原理概述

    鼠标按下和抬起时的两个位置就是一个矩形,再利用相机位置可以生成一个四棱台,类似视椎体,然后遍历各个节点的包围盒中心是否在这个视椎体内。

    部分细节说明

    • 初始化
      constructor(viewer) { //传递过来的viewer里定义了webGLRenderer,Scene,camera等
          this.viewer = viewer;
          this.renderer = viewer.renderer;
          this.camera = viewer.activeCamera;
          this.controls = viewer.controls;//框选时需要把控制器(orbit)禁用
          this.scene = viewer.scene;
          this.useSelect = false;//这个值为true时才能框选物体。可以在按下ctrl时设为true,松开时设为false
          this.currentIsPersectiveCamera = true; //只有透视相机才能框选
      
          this.selectionShape = null;//框选时在屏幕上出现的矩形区域
      
          this.startX = - Infinity;
          this.startY = - Infinity;
          this.startZ = -Infinity;
      
          this.prevX = - Infinity;
          this.prevY = - Infinity;
          this.prevZ = - Infinity;
      
          this.selectionPoints = [];//保存鼠标按下和松开时的坐标
          this.dragging = false;
          this.selectionShapeNeedsUpdate = false;
          this.init(); //用于初始化显示在屏幕上的矩形和绑定鼠标事件的函数
      }
      
    • 鼠标事件
      这里用到的鼠标事件有pointerdown,pointerup,pointermove。鼠标按下时记录按下的位置及将一些变量置空,鼠标移动中需要更新矩形的另一个点(第一个点是按下的位置),更新这个点后后续才能更新屏幕上的矩形。鼠标松开时构建四棱台并进行模型遍历。
    		//鼠标按下事件
            this.renderer.domElement.addEventListener('pointerdown', e => {
                if (!this.useSelect) return;
                this.prevX = e.clientX;
                this.prevY = e.clientY;
                var rect = this.renderer.domElement.getBoundingClientRect();
                this.startX = ((e.clientX  - rect.left) / rect.width) * 2 - 1;
                this.startY =(-(e.clientY - rect.top) / rect.height) * 2 + 1;
    
                this.startZ = 0
    
                this.selectionPoints.length = [];
                this.dragging = true;
            });
    
            //鼠标松开事件
            this.renderer.domElement.addEventListener('pointerup', () => {
                if (!this.useSelect) return;
                if(!this.currentIsPersectiveCamera) message.info("请使用透视相机框选!");
                this.shape();
                this.selectionShape.visible = false;
                this.selectionPoints.length = [];
                this.selectionShapeNeedsUpdate = true;
                this.dragging = false;
            });
    
            //鼠标移动事件
            this.renderer.domElement.addEventListener('pointermove', e => {
                if (!this.useSelect) return;
                // If the left mouse button is not pressed
                if ((1 & e.buttons) === 0) {
                    return;
                }
    
                const ex = e.clientX;
                const ey = e.clientY;
    
                var rect = this.renderer.domElement.getBoundingClientRect();
                let nx =((e.clientX  - rect.left) / rect.width) * 2 - 1;// (e.clientX / window.innerWidth) * 2 - 1;
                let ny = (-(e.clientY - rect.top) / rect.height) * 2 + 1;//- ((e.clientY / window.innerHeight) * 2 - 1);
    
                // set points for the corner of the box
                this.selectionPoints.length = 3 * 5;
    
                this.selectionPoints[0] = this.startX;
                this.selectionPoints[1] = this.startY;
                this.selectionPoints[2] = this.startZ;
    
                this.selectionPoints[3] = nx;
                this.selectionPoints[4] = this.startY;
                this.selectionPoints[5] = this.startZ;
    
                this.selectionPoints[6] = nx;
                this.selectionPoints[7] = ny;
                this.selectionPoints[8] = this.startZ;
    
                this.selectionPoints[9] = this.startX;
                this.selectionPoints[10] = ny;
                this.selectionPoints[11] = this.startZ;
    
                this.selectionPoints[12] = this.startX;
                this.selectionPoints[13] = this.startY;
                this.selectionPoints[14] = this.startZ;
    
    
                if (ex !== this.prevX || ey !== this.prevY) {
                    this.selectionShapeNeedsUpdate = true;
                    if(!this.selectionShape.visible)
                        this.selectionShape.visible = true;
                }
                this.prevX = ex;
                this.prevY = ey;
                this.selectionShape.visible = true;
            });
    
    • 更新框选矩形
      这个函数需要时时调用,也就是需要放到animate函数(调用了requestAnimationFrame的函数)中调用
    	/**
         *更新框选形状
         */
        update() {
            if (!this.selectionShape) return;
            // Update the selection lasso lines
            if (this.selectionShapeNeedsUpdate) {
                this.selectionShape.geometry.setAttribute(
                    'position',
                    new Float32BufferAttribute(this.selectionPoints, 3, false)
                );
    
                this.selectionShape.frustumCulled = false;
                this.selectionShapeNeedsUpdate = false;
            }
    
            //根据相机设置框选形状的位置,让它显示在屏幕上  很重要!
            const yScale = Math.tan(MathUtils.DEG2RAD * this.camera.fov / 2) * this.selectionShape.position.z;
            this.selectionShape.scale.set(- yScale * this.camera.aspect, - yScale, 1);
        }
    
    • 生成虚拟四棱台并遍历模型
      这个阶段会生成一个虚拟的四棱台(为什么是四棱台?因为透视相机的视野范围就是一个四棱台),也就是把框选区域从屏幕上的2D转到世界空间的3D。检测比较算法具体看代码
    /**
         * 松开鼠标后开始比较、隐藏mesh
         */
        shape(){
            if(this.selectionPoints.length<12) return;
            //根据框选矩形4个点和相机位置求出当前视景体的八个点,用视景体比较mesh是否在框选区域内
            this.selectionShape.updateMatrixWorld();
            let p1 = new Vector3(this.selectionPoints[0],this.selectionPoints[1],this.selectionPoints[2]).applyMatrix4(this.selectionShape.matrixWorld);
            let p2 = new Vector3(this.selectionPoints[3],this.selectionPoints[4],this.selectionPoints[5]).applyMatrix4(this.selectionShape.matrixWorld);
            let p3 = new Vector3(this.selectionPoints[6],this.selectionPoints[7],this.selectionPoints[8]).applyMatrix4(this.selectionShape.matrixWorld);
            let p4 = new Vector3(this.selectionPoints[9],this.selectionPoints[10],this.selectionPoints[11]).applyMatrix4(this.selectionShape.matrixWorld);
            let cameraPos = this.camera.getWorldPosition(new Vector3());
            let dir1 = p1.clone().sub(cameraPos).normalize();
            let dir2 = p2.clone().sub(cameraPos).normalize();
            let dir3 = p3.clone().sub(cameraPos).normalize();
            let dir4 = p4.clone().sub(cameraPos).normalize();
    
            let scale = 20;//可以理解为视景体最大深度,需要确保所有物体都在这范围内,根据需要修改
            let newPos1 = cameraPos.clone().add(dir1.clone().multiplyScalar(scale));
            let newPos2 = cameraPos.clone().add(dir2.clone().multiplyScalar(scale));
            let newPos3 = cameraPos.clone().add(dir3.clone().multiplyScalar(scale));
    
            let center = newPos1.clone().add(newPos3).multiplyScalar(0.5);
            let centerDir = center.clone().sub(cameraPos).normalize();
            let centerDis = center.clone().distanceTo(cameraPos);
            let top = newPos1.clone().add(newPos2).multiplyScalar(0.5);
            let topDir = top.clone().sub(cameraPos).normalize();
            let topScale = top.clone().distanceTo(cameraPos)/centerDis;
            let right = newPos2.clone().add(newPos3).multiplyScalar(0.5);
            let rightDir = right.clone().sub(cameraPos).normalize();
            let rightScale = right.clone().distanceTo(cameraPos)/centerDis;
    
            let highlightObj = [];
            let vertices = [];
    
            //遍历所有模型的所有mesh,查看这个mesh的包围盒中心是否在框选区域内
            for(var i=0;i<this.models.length;i++){
                this.models[i].traverse(node=>{
                    if(node.isMesh || (node.type == "Sprite" && node._type != "measure" && node._type != "file")){
                        if(!node.visible) return;
                        let boxCenter = null;
                        if(node.geometry.boundingBox){
                            boxCenter = node.geometry.boundingBox.getCenter(new Vector3());
                            boxCenter.applyMatrix4(node.matrixWorld);
                        }
                         else{
                            let box = new Box3().expandByObject(node);
                            boxCenter = box.getCenter(new Vector3());
                        }
                        let centerDis = this.projectVector(boxCenter,cameraPos,centerDir);
                        let topDis = centerDis * topScale;
                        let rightDis = centerDis * rightScale;
    
                        let centerPos = cameraPos.clone().add(centerDir.clone().multiplyScalar(centerDis));
                        let topPos = cameraPos.clone().add(topDir.clone().multiplyScalar(topDis));
                        let rightPos = cameraPos.clone().add(rightDir.clone().multiplyScalar(rightDis));
     
    
                        let tempTopDir = topPos.clone().sub(centerPos).normalize();
                        let tempRightDir = rightPos.clone().sub(centerPos).normalize();
    
                        let X = rightPos.clone().distanceTo(centerPos);
                        let Y = topPos.clone().distanceTo(centerPos);
    
                        let x = this.projectVector(boxCenter,centerPos,tempRightDir.clone());
                        let y = this.projectVector(boxCenter,centerPos,tempTopDir.clone());
    
                        //在框选范围内
                        if(x<= X && y <= Y){
                            //node.visible = false;
                            highlightObj.push(node); //将区域内的节点缓存
                        }
                    }
                })
             }
             if(this.highlightCB) this.highlightCB(highlightObj); //其它脚本定义的高亮函数,将选定的节点高亮显示
        }
        
    	/**
         * 计算向量vec1在向量vec2上的投影长度
         */
        projectVector(pos1,pos2,dir){
            let angle = pos1.clone().sub(pos2).angleTo(dir);
            let dis = pos1.clone().distanceTo(pos2) * Math.cos(angle);
            return Math.abs(dis);
        }
    

    完整代码

    import {
        Line,
        Float32BufferAttribute,
        MathUtils,
        Vector3,
        Box3,
    } from 'three'
    
    /**
     * 本脚本用于框选物体,并将框选区域内的mesh隐藏,针对的是mesh,不是整个模型
     * 先使用setModel()将模型加入数组
     * 再使用changeMode()打开框选
     */
    class SelectArea {
        constructor(viewer) {
            this.viewer = viewer;
            this.renderer = viewer.renderer;
            this.camera = viewer.activeCamera;
            this.controls = viewer.controls;//框选时需要把控制器(orbit)禁用
            this.scene = viewer.scene;
            this.useSelect = false;//这个值为true时才能框选物体
            this.currentIsPersectiveCamera = true; //只有透视相机才能框选
    
            this.selectionShape = null;//框选时在屏幕上出现的矩形区域
    
            this.startX = - Infinity;
            this.startY = - Infinity;
            this.startZ = -Infinity;
    
            this.prevX = - Infinity;
            this.prevY = - Infinity;
            this.prevZ = - Infinity;
    
            this.selectionPoints = [];
            this.dragging = false;
            this.selectionShapeNeedsUpdate = false;
            this.init();
        }
    
        /**
         * 将模型加入数组,方便后续比较,外部调用
         * @param {*} model 
         */
        setModel(model){
            if(model){
                this.models.push(model)
            }
        }
    
        /**
         * 切换是否框选物体
         */
        changeMode(enabled) {
            this.useSelect = enabled;
            if (this.controls)  //如果有orbit控制器,在框选时需要禁用
                this.controls.enabled = !this.useSelect;
        }
    
        init() {
    
            // selection shape
            this.selectionShape = new Line();
            this.selectionShape.material.color.set(0xFFFF00).convertSRGBToLinear();
            this.selectionShape.renderOrder = 1;
            this.selectionShape.position.z = - 0.2;
            this.selectionShape.depthTest = false;
            this.selectionShape.scale.setScalar(1);
            this.camera.add(this.selectionShape);
    
            //鼠标按下事件
            this.renderer.domElement.addEventListener('pointerdown', e => {
                if (!this.useSelect) return;
                this.prevX = e.clientX;
                this.prevY = e.clientY;
                var rect = this.renderer.domElement.getBoundingClientRect();
                this.startX = ((e.clientX  - rect.left) / rect.width) * 2 - 1;
                this.startY =(-(e.clientY - rect.top) / rect.height) * 2 + 1;
    
                this.startZ = 0
    
                this.selectionPoints.length = [];
                this.dragging = true;
            });
    
            //鼠标松开事件
            this.renderer.domElement.addEventListener('pointerup', () => {
                if (!this.useSelect) return;
                if(!this.currentIsPersectiveCamera) console.log("请使用透视相机框选!");
                this.shape();
                this.selectionShape.visible = false;
                this.selectionPoints.length = [];
                this.selectionShapeNeedsUpdate = true;
                this.dragging = false;
            });
    
            //鼠标移动事件
            this.renderer.domElement.addEventListener('pointermove', e => {
                if (!this.useSelect) return;
                // If the left mouse button is not pressed
                if ((1 & e.buttons) === 0) {
                    return;
                }
    
                const ex = e.clientX;
                const ey = e.clientY;
    
                var rect = this.renderer.domElement.getBoundingClientRect();
                let nx =((e.clientX  - rect.left) / rect.width) * 2 - 1;// (e.clientX / window.innerWidth) * 2 - 1;
                let ny = (-(e.clientY - rect.top) / rect.height) * 2 + 1;//- ((e.clientY / window.innerHeight) * 2 - 1);
    
                // set points for the corner of the box
                this.selectionPoints.length = 3 * 5;
    
                this.selectionPoints[0] = this.startX;
                this.selectionPoints[1] = this.startY;
                this.selectionPoints[2] = this.startZ;
    
                this.selectionPoints[3] = nx;
                this.selectionPoints[4] = this.startY;
                this.selectionPoints[5] = this.startZ;
    
                this.selectionPoints[6] = nx;
                this.selectionPoints[7] = ny;
                this.selectionPoints[8] = this.startZ;
    
                this.selectionPoints[9] = this.startX;
                this.selectionPoints[10] = ny;
                this.selectionPoints[11] = this.startZ;
    
                this.selectionPoints[12] = this.startX;
                this.selectionPoints[13] = this.startY;
                this.selectionPoints[14] = this.startZ;
    
    
                if (ex !== this.prevX || ey !== this.prevY) {
                    this.selectionShapeNeedsUpdate = true;
                    if(!this.selectionShape.visible)
                        this.selectionShape.visible = true;
                }
                this.prevX = ex;
                this.prevY = ey;
                this.selectionShape.visible = true;
            });
    
        }
    
        /**
         *更新框选形状
         */
        update() {
            if (!this.selectionShape) return;
            // Update the selection lasso lines
            if (this.selectionShapeNeedsUpdate) {
                this.selectionShape.geometry.setAttribute(
                    'position',
                    new Float32BufferAttribute(this.selectionPoints, 3, false)
                );
    
                this.selectionShape.frustumCulled = false;
                this.selectionShapeNeedsUpdate = false;
            }
    
            //根据相机设置框选形状的位置,让它显示在屏幕上
            const yScale = Math.tan(MathUtils.DEG2RAD * this.camera.fov / 2) * this.selectionShape.position.z;
            this.selectionShape.scale.set(- yScale * this.camera.aspect, - yScale, 1);
        }
    
        setHighlightCB(cb){
            this.highlightCB = cb;
        }
    
        /**
         * 松开鼠标后开始比较、隐藏mesh
         */
        shape(){
            if(this.selectionPoints.length<12) return;
            //根据框选矩形4个点和相机位置求出当前视景体的八个点,用视景体比较mesh是否在框选区域内
            this.selectionShape.updateMatrixWorld();
            let p1 = new Vector3(this.selectionPoints[0],this.selectionPoints[1],this.selectionPoints[2]).applyMatrix4(this.selectionShape.matrixWorld);
            let p2 = new Vector3(this.selectionPoints[3],this.selectionPoints[4],this.selectionPoints[5]).applyMatrix4(this.selectionShape.matrixWorld);
            let p3 = new Vector3(this.selectionPoints[6],this.selectionPoints[7],this.selectionPoints[8]).applyMatrix4(this.selectionShape.matrixWorld);
            let p4 = new Vector3(this.selectionPoints[9],this.selectionPoints[10],this.selectionPoints[11]).applyMatrix4(this.selectionShape.matrixWorld);
            let cameraPos = this.camera.getWorldPosition(new Vector3());
            let dir1 = p1.clone().sub(cameraPos).normalize();
            let dir2 = p2.clone().sub(cameraPos).normalize();
            let dir3 = p3.clone().sub(cameraPos).normalize();
            let dir4 = p4.clone().sub(cameraPos).normalize();
    
            let scale = 20;//可以理解为视景体最大深度,需要确保所有物体都在这范围内,外面的物体不会进行比较
            let newPos1 = cameraPos.clone().add(dir1.clone().multiplyScalar(scale));
            let newPos2 = cameraPos.clone().add(dir2.clone().multiplyScalar(scale));
            let newPos3 = cameraPos.clone().add(dir3.clone().multiplyScalar(scale));
    
            let center = newPos1.clone().add(newPos3).multiplyScalar(0.5);
            let centerDir = center.clone().sub(cameraPos).normalize();
            let centerDis = center.clone().distanceTo(cameraPos);
            let top = newPos1.clone().add(newPos2).multiplyScalar(0.5);
            let topDir = top.clone().sub(cameraPos).normalize();
            let topScale = top.clone().distanceTo(cameraPos)/centerDis;
            let right = newPos2.clone().add(newPos3).multiplyScalar(0.5);
            let rightDir = right.clone().sub(cameraPos).normalize();
            let rightScale = right.clone().distanceTo(cameraPos)/centerDis;
    
            let highlightObj = [];
            let vertices = [];
    
            //遍历所有模型的所有mesh,查看这个mesh的包围盒中心是否在框选区域内
            for(var i=0;i<this.models.length;i++){
                this.models[i].traverse(node=>{
                    if(node.isMesh || (node.type == "Sprite" && node._type != "measure" && node._type != "file")){
                        if(!node.visible) return;
                        let boxCenter = null;
                        if(node.geometry.boundingBox){
                            boxCenter = node.geometry.boundingBox.getCenter(new Vector3());
                            boxCenter.applyMatrix4(node.matrixWorld);
                        }
                         else{
                            let box = new Box3().expandByObject(node);
                            boxCenter = box.getCenter(new Vector3());
                        }
                        let centerDis = this.projectVector(boxCenter,cameraPos,centerDir);
                        let topDis = centerDis * topScale;
                        let rightDis = centerDis * rightScale;
    
                        let centerPos = cameraPos.clone().add(centerDir.clone().multiplyScalar(centerDis));
                        let topPos = cameraPos.clone().add(topDir.clone().multiplyScalar(topDis));
                        let rightPos = cameraPos.clone().add(rightDir.clone().multiplyScalar(rightDis));
     
    
                        let tempTopDir = topPos.clone().sub(centerPos).normalize();
                        let tempRightDir = rightPos.clone().sub(centerPos).normalize();
    
                        let X = rightPos.clone().distanceTo(centerPos);
                        let Y = topPos.clone().distanceTo(centerPos);
    
                        let x = this.projectVector(boxCenter,centerPos,tempRightDir.clone());
                        let y = this.projectVector(boxCenter,centerPos,tempTopDir.clone());
    
                        //在框选范围内
                        if(x<= X && y <= Y){
                            //node.visible = false;
                            highlightObj.push(node);
                        }
                    }
                })
            }
            if(this.highlightCB) this.highlightCB(highlightObj);
        }
    
    
        /**
         * 计算向量vec1在向量vec2上的投影长度
         */
        projectVector(pos1,pos2,dir){
            let angle = pos1.clone().sub(pos2).angleTo(dir);
            let dis = pos1.clone().distanceTo(pos2) * Math.cos(angle);
            return Math.abs(dis);
        }
    
    }
    export { SelectArea }
    

    参考

    Threejs 官方BVH里的一个案例

    PS:后面才发现threejs官方出了一个框选的案例。。。

    展开全文
  • threejs demo

    2021-01-12 04:25:10
    【实例简介】threejs入门博客http://blog.csdn.net/u010588262/article/details/79570436的配套demo,演示地址:https://www.hugeoyzy.top/threejs/src/demo1.htmlhttps://www.hugeoyzy.top/threejs/src/demo2.html...

    【实例简介】

    threejs入门博客http://blog.csdn.net/u010588262/article/details/79570436的配套demo,演示地址:

    https://www.hugeoyzy.top/threejs/src/demo1.html

    https://www.hugeoyzy.top/threejs/src/demo2.html

    【实例截图】

    【核心代码】

    threejsdemo

    └── threejsdemo

    ├── src

    │   ├── css

    │   │   ├── base.css

    │   │   ├── images

    │   │   │   ├── ui-bg_flat_75_ffffff_40x100.png

    │   │   │   ├── ui-bg_highlight-soft_75_cccccc_1x100.png

    │   │   │   ├── ui-icons_222222_256x240.png

    │   │   │   ├── ui-icons_454545_256x240.png

    │   │   │   └── ui-icons_888888_256x240.png

    │   │   ├── index.css

    │   │   ├── info.css

    │   │   └── jquery-ui.css

    │   ├── demo1.html

    │   ├── demo2.html

    │   ├── fonts

    │   │   ├── droid

    │   │   │   ├── droid_sans_bold.typeface.json

    │   │   │   ├── droid_sans_mono_regular.typeface.json

    │   │   │   ├── droid_sans_regular.typeface.json

    │   │   │   ├── droid_serif_bold.typeface.json

    │   │   │   ├── droid_serif_regular.typeface.json

    │   │   │   ├── NOTICE

    │   │   │   └── README.txt

    │   │   ├── gentilis_bold.typeface.json

    │   │   ├── gentilis_regular.typeface.json

    │   │   ├── helvetiker_bold.typeface.json

    │   │   ├── helvetiker_regular.typeface.json

    │   │   ├── LICENSE

    │   │   ├── optimer_bold.typeface.json

    │   │   ├── optimer_regular.typeface.json

    │   │   ├── README

    │   │   └── ttf

    │   │   └── kenpixel.ttf

    │   ├── images

    │   │   ├── A-button.png

    │   │   ├── B-button.png

    │   │   ├── checkerboard.jpg

    │   │   ├── Chrome.png

    │   │   ├── cloud.png

    │   │   ├── crate.gif

    │   │   ├── crate.png

    │   │   ├── DarkSea-xneg.jpg

    │   │   ├── DarkSea-xpos.jpg

    │   │   ├── DarkSea-yneg.jpg

    │   │   ├── DarkSea-ypos.jpg

    │   │   ├── DarkSea-zneg.jpg

    │   │   ├── DarkSea-zpos.jpg

    │   │   ├── dawnmountain-xneg.png

    │   │   ├── dawnmountain-xpos.png

    │   │   ├── dawnmountain-yneg.png

    │   │   ├── dawnmountain-ypos.png

    │   │   ├── dawnmountain-zneg.png

    │   │   ├── dawnmountain-zpos.png

    │   │   ├── diamond.png

    │   │   ├── Dice-Blue-1.png

    │   │   ├── Dice-Blue-2.png

    │   │   ├── Dice-Blue-3.png

    │   │   ├── Dice-Blue-4.png

    │   │   ├── Dice-Blue-5.png

    │   │   ├── Dice-Blue-6.png

    │   │   ├── dirt-512.jpg

    │   │   ├── disc.png

    │   │   ├── down-A.png

    │   │   ├── down-B.png

    │   │   ├── down-C.png

    │   │   ├── earth-clouds.png

    │   │   ├── earth-day.jpg

    │   │   ├── earth-index-shifted-gray.png

    │   │   ├── earth-outline-shifted-gray.png

    │   │   ├── earth-specular.jpg

    │   │   ├── earth-topo.jpg

    │   │   ├── explosion.jpg

    │   │   ├── fluffy.png

    │   │   ├── glow.png

    │   │   ├── grass-512.jpg

    │   │   ├── heightmap.png

    │   │   ├── icon-close-16.png

    │   │   ├── icon-close-24.png

    │   │   ├── icon-close-48.png

    │   │   ├── icon-info.png

    │   │   ├── lava.jpg

    │   │   ├── left-A.png

    │   │   ├── left-B.png

    │   │   ├── left-C.png

    │   │   ├── moondust-xneg.png

    │   │   ├── moondust-xpos.png

    │   │   ├── moondust-yneg.png

    │   │   ├── moondust-ypos.png

    │   │   ├── moondust-zneg.png

    │   │   ├── moondust-zpos.png

    │   │   ├── moon.jpg

    │   │   ├── nebula-xneg.png

    │   │   ├── nebula-xpos.png

    │   │   ├── nebula-yneg.png

    │   │   ├── nebula-ypos.png

    │   │   ├── nebula-zneg.png

    │   │   ├── nebula-zpos.png

    │   │   ├── raindrop2flip.png

    │   │   ├── raindrop2.png

    │   │   ├── raindropflip.png

    │   │   ├── raindrop.png

    │   │   ├── redball.png

    │   │   ├── right-A.png

    │   │   ├── right-B.png

    │   │   ├── right-C.png

    │   │   ├── rock-512.jpg

    │   │   ├── room.jpg

    │   │   ├── run.png

    │   │   ├── sand-512.jpg

    │   │   ├── smoke512.png

    │   │   ├── smokeparticle.png

    │   │   ├── snow-512.jpg

    │   │   ├── snowflake.png

    │   │   ├── spark.png

    │   │   ├── spikey.png

    │   │   ├── SquareBlue.png

    │   │   ├── SquareGreen.png

    │   │   ├── square-O.png

    │   │   ├── square-plus.png

    │   │   ├── square.png

    │   │   ├── SquareRed.png

    │   │   ├── square-thick.png

    │   │   ├── square-X.png

    │   │   ├── SquareYellow.png

    │   │   ├── star.png

    │   │   ├── triangles.png

    │   │   ├── up-A.png

    │   │   ├── up-B.png

    │   │   ├── up-C.png

    │   │   ├── uvgrid01.jpg

    │   │   ├── uvgrid02.jpg

    │   │   ├── uvgrid03.jpg

    │   │   ├── water512.jpg

    │   │   ├── water.jpg

    │   │   ├── world.jpg

    │   │   ├── xbox-controller-FPS.png

    │   │   ├── X-button.png

    │   │   ├── xneg.png

    │   │   ├── xpos.png

    │   │   ├── Y-button.png

    │   │   ├── yneg.png

    │   │   ├── ypos.png

    │   │   ├── zneg.png

    │   │   └── zpos.png

    │   ├── js

    │   │   ├── CSS3DRenderer.js

    │   │   ├── DAT.GUI.min.js

    │   │   ├── Detector.js

    │   │   ├── effects

    │   │   │   └── AnaglyphEffect.js

    │   │   ├── FlatMirror.js

    │   │   ├── gamepad.js

    │   │   ├── gamepad_no_images.js

    │   │   ├── GamepadState.js

    │   │   ├── gamepad_uncompressed.js

    │   │   ├── info.js

    │   │   ├── jquery-1.9.1.js

    │   │   ├── jquery-ui.js

    │   │   ├── KeyboardState.js

    │   │   ├── leap.js

    │   │   ├── loaders

    │   │   │   ├── DDSLoader.js

    │   │   │   ├── MTLLoader.js

    │   │   │   └── OBJLoader.js

    │   │   ├── MarchingCubesData.js

    │   │   ├── OrbitControls.js

    │   │   ├── OrbitControls-Touch.js

    │   │   ├── parser.js

    │   │   ├── ParticleEngineExamples.js

    │   │   ├── ParticleEngine.js

    │   │   ├── peer.js

    │   │   ├── polyhedra.js

    │   │   ├── Pool.js

    │   │   ├── postprocessing

    │   │   │   ├── BloomPass.js

    │   │   │   ├── DotScreenPass.js

    │   │   │   ├── EffectComposer.js

    │   │   │   ├── FilmPass.js

    │   │   │   ├── MaskPass.js

    │   │   │   ├── RenderPass.js

    │   │   │   ├── SavePass.js

    │   │   │   ├── ShaderPass.js

    │   │   │   └── TexturePass.js

    │   │   ├── RequestAnimationFrame.js

    │   │   ├── ShaderParticleEmitter.js

    │   │   ├── ShaderParticleGroup.js

    │   │   ├── shaders

    │   │   │   ├── AdditiveBlendShader.js

    │   │   │   ├── BasicShader.js

    │   │   │   ├── BleachBypassShader.js

    │   │   │   ├── BlendShader.js

    │   │   │   ├── BokehShader.js

    │   │   │   ├── BrightnessContrastShader.js

    │   │   │   ├── ColorCorrectionShader.js

    │   │   │   ├── ColorifyShader.js

    │   │   │   ├── ConvolutionShader.js

    │   │   │   ├── CopyShader.js

    │   │   │   ├── DOFMipMapShader.js

    │   │   │   ├── DotScreenShader.js

    │   │   │   ├── EdgeShader2.js

    │   │   │   ├── EdgeShader.js

    │   │   │   ├── FilmShader.js

    │   │   │   ├── FocusShader.js

    │   │   │   ├── FresnelShader.js

    │   │   │   ├── FXAAShader.js

    │   │   │   ├── HorizontalBlurShader.js

    │   │   │   ├── HorizontalTiltShiftShader.js

    │   │   │   ├── HueSaturationShader.js

    │   │   │   ├── KaleidoShader.js

    │   │   │   ├── LambertToon.js

    │   │   │   ├── LuminosityShader.js

    │   │   │   ├── MirrorShader.js

    │   │   │   ├── NormalMapShader.js

    │   │   │   ├── RGBShiftShader.js

    │   │   │   ├── SepiaShader.js

    │   │   │   ├── SSAOShader.js

    │   │   │   ├── TriangleBlurShader.js

    │   │   │   ├── UnpackDepthRGBAShader.js

    │   │   │   ├── VerticalBlurShader.js

    │   │   │   ├── VerticalTiltShiftShader.js

    │   │   │   └── VignetteShader.js

    │   │   ├── ShaderWater.js

    │   │   ├── Stats.js

    │   │   ├── SubdivisionModifier.js

    │   │   ├── Three90.js

    │   │   ├── ThreeCSG.js

    │   │   ├── ThreeDebug.js

    │   │   ├── THREEx.FullScreen.js

    │   │   ├── THREEx.KeyboardState.js

    │   │   ├── THREEx.WindowResize.js

    │   │   ├── topology.js

    │   │   ├── TrackballControls.js

    │   │   └── Tween.js

    │   ├── objs

    │   │   ├── container.mtl

    │   │   ├── container.obj

    │   │   └── male02

    │   │   ├── 01_-_Default1noCulling.dds

    │   │   ├── 01_-_Default1noCulling.JPG

    │   │   ├── male-02-1noCulling.dds

    │   │   ├── male-02-1noCulling.JPG

    │   │   ├── male02_dds.mtl

    │   │   ├── male02.mtl

    │   │   ├── male02.obj

    │   │   ├── orig_02_-_Defaul1noCulling.dds

    │   │   ├── orig_02_-_Defaul1noCulling.JPG

    │   │   └── readme.txt

    │   └── util.js

    └── threejsdemo.iml

    15 directories, 235 files

    展开全文
  • Threejs2017年6月6日15:06Stats:stats.setMode(1);参数为0的时候,表示显示的是FPS界面,参数为1的时候,表示显示的是MS界面。Stats的begin和end函数本质上是在统计代码执行的时间和帧数,然后用公式fps=帧数/时间,...

    Threejs

    2017年6月6日

    15:06

    Stats:

    stats.setMode(1);参数为0的时候,表示显示的是FPS界面,参数为1的时候,表示显示的是MS界面。Stats的begin和end函数本质上是在统计代码执行的时间和帧数,然后用公式fps=帧数/时间,就能够得到FPS。MS表示渲染一帧需要的毫秒数,这个数字是越小越好。再次点击又可以回到FPS视图中。

    stats.domElement.style.position = 'absolute';stats的domElement表示绘制的目的地(DOM)

    stats.domElement.style.left = '0px'

    document.body.appendChild( stats.domElement );

    stats.begin();代码前调用begin,代码执行后调用end(),能够统计出这段代码执行的平均帧数。

    stats.end();

    stats.update();

    renderer :

    new THREE.WebGLRenderer();声明渲染器renderer

    new THREE.WebGLDeferredRenderer();处理复杂光的延迟渲染器

    new THREE.CanvasRenderer();

    new THREE.WebGLDeferredRenderer({

    width: window.innerWidth,

    height: window.innerHeight,

    scale: 1,

    antialias: true,

    tonemapping: THREE.FilmicOperator,

    brightness: 2.5

    });

    renderer.setSize(width, height);设置渲染器的大小为窗口的内宽度,也就是内容区的宽度.

    renderer.setClearColor(0xFFFFFF,1.0);

    renderer.shadowMapEnabled = true;允许阴影射

    renderer.render( scene, camera, renderTarget, forceClear ),renderTarget:渲染的目标,默认是渲染到前面定义的render变量中forceClear:每次绘制之前都将画布的内容给清除,即使自动清除标志autoClear为false,也会清除。

    requestAnimationFrame(render);循环渲染.

    camera :

    new THREE.PerspectiveCamera( fov, aspect, near, far ),camera.fov=45,类似于物体和camera的距离,值越小物体越近就越大,aspect实际窗口的纵横比,near不要设置为负值声明透视相机

    new THREE.OrthographicCamera( left, right, top, bottom, near, far ),声明正交相机,定义一个视景体

    camera.position= new THREE.Vector3(0,0,0);        camera.position.x=0;camera的xyz坐标位置

    camera.up = new THREE.Vector3(0,1,0);        camera.up.x = 0;,camera的坐标系,y轴向上,即右手坐标系

    camera.lookAt({x : 0, y : 0, z : 0 });或者camera.lookAt(scene.position);,camera面向的位置

    camera.updateProjectionMatrix();

    geometry:

    new THREE.Geometry();声明几何物体.

    new THREE.PlaneGeometry( 500, 300, 1, 1 );平面的四边形

    new THREE.CircleGeometry(radius,segments,thetastarts,thetalength)平面圆

    new THREE.RingGeometry

    new THREE.ShapeGeometry()平面塑形

    new THREE.Shape();           learning-threejs-master\chapter-05

    THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments )         widthSegments:宽度分段份数,heightSegments:高度分段份数,depthSegments:长度分段份数

    new THREE.SphereGeometry(4, 20, 20);圆

    new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded, thetaStart, thetaLength)声明圆柱体

    new THREE.ConvexGeometry().凸面体

    new THREE.IcosahedronGeometry()正20面体

    new THREE.DodecahedronGeometry()

    new THREE.LatheGeometry()扫描体

    new THREE.OctahedronGeometry()正八面体

    new THREE.ParametricGeometry(THREE.ParametricGeometries.mobius3d, 20, 10)

    new THREE.TorusKnotGeometry()环面纽结,可以画万花筒或者花

    new THREE.TetrahedronGeometry()正四面体,锥形

    new THREE.TorusGeometry(3, 1, 10, 10)圆环

    new THREE.TubeGeometry(3, 1, 10, 10)管状几何体

    new THREE.ExtrudeGeometry(3, 1, 10, 10)拉伸几何体

    new THREE.ParamtericGeometry(3, 1, 10, 10)创建几何体

    new THREE.CubeGeometry(width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, sides)

    new THREETextGeometry(3, 1, 10, 10)文字几何体

    geometry.clone()

    geometry.vertices=vertices;

    geometry.faces=faces;

    geometry.computeCentroids();

    geometry.mergeVertices();

    geometry.vertices[0].uv = new THREE.Vector2(0,0);

    geometry.receiveShadow = true;接受并且显示阴影

    geometry.castShadow = true;投射阴影

    geometry.vertices.push(new THREE.Vector3(  100, 0, -100 )),在几何物体中加入一个点,几何体里面有一个vertices变量,可以用来存放点。

    geometry.geometry.parameters.height;某物体的参数,高度

    geometry.colors.push(color1,color2)

    geometry.geometry.parameters.widthSegments;

    geometry.geometry.parameters.heightSegments;

    color :

    new THREE.Color( 0x444444 )声明颜色变量

    material :

    new THREE.MeshLambertMaterial( { color:0xFFFFFF} );兰伯特材质。在没有light的情况下,任何颜色的material都是黑色的。Lambert材质表面会在所有方向上均匀地散射灯光,这就会使颜色看上去比较均匀。Lambert材质会受环境光的影响,呈现环境光的颜色,与材质本身颜色关系不大。物体在环境光影响下,最终表现出来的颜色的向量值,应该是环境光颜色向量和物体本身颜色向量的向量积。在渲染程序中,它是表面各可视属性的结合,这些可视属性是指表面的色彩、纹理、光滑度、透明度、反射率、折射率、发光度等。

    new THREE.LineBasicMaterial( parameters ),Parameters是一个定义材质外观的对象,它包含多个属性来定义材质,这些属性是:Color:线条的颜色,用16进制来表示,默认的颜色是白色。Linewidth:线条的宽度,默认时候1个单位宽度。Linecap:线条两端的外观,默认是圆角端点,当线条较粗的时候才看得出效果,如果线条很细,那么几乎看不出效果。Linejoin:两个线条的连接点处的外观,默认是“round”,表示圆角。VertexColors:定义线条材质是否使用顶点颜色,这是一个boolean值。意思是,线条各部分的颜色会根据顶点的颜色来进行插值。Fog:定义材质的颜色是否受全局雾效的影响。定义一种线条的材质

    new THREE.LineDashedMaterial( parameters )

    new THREE.MeshLambertMaterial({map: textureGrass});

    new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),                                                                        new THREE.MeshFaceMaterial(mats);

    new THREE.MeshPhongMaterial({color: 0xffffff, specular: 0xffffff, shininess: 200});

    var material = newTHREE.MeshToonMaterial( {

    map: imgTexture,

    bumpMap: imgTexture,

    bumpScale: bumpScale,

    color: diffuseColor,

    specular: specularColor,

    reflectivity: beta,

    shininess: specularShininess,

    envMap: alphaIndex% 2 === 0 ? null: reflectionCube

    } );

    meshMaterial.opacity

    meshMaterial.visible

    meshMaterial.ambient = new THREE.Color

    meshMaterial.emissive = new THREE.Color

    meshMaterial.specular = new THREE.Color

    meshMaterial.shininess

    meshMaterial.side = THREE.FrontSide;

    meshMaterial.needsUpdate

    meshMaterial.color.setStyle

    meshMaterial.metal = e;

    meshMaterial.wrapAround = e;

    meshMaterial.wrapRGB.x = e;

    mesh :

    new THREE.Mesh( geometry,material);该基础材质不会对场景中的光源产生反应

    mesh.position(x,y,z),mesh的xyz坐标位置

    THREE.SceneUtils.createMultiMaterialObject(ground,

    [new THREE.MeshBasicMaterial({wireframe: true, overdraw: true, color: 000000}),

    new THREE.MeshBasicMaterial({color: 0x00ff00, transparent: true, opacity: 0.5}

    )

    ]);支持mesh使用多种材质

    Mesh.geometry.vertices=

    Mesh.geometry.verticesNeedUpdate=

    Mesh.geometry.computeFaceNormals();

    Mesh.translateX(number);移动

    light

    new THREE.Light ( hex )        hex是一个16进制的颜色值

    new THREE.THREE.SpotLight( hex, intensity, distance, angle, exponent,visible )        distance光源可以照多远,,Angle:聚光灯着色的角度,用弧度作为单位,这个角度是和光源的方向形成的角度。exponent:光源模型中,衰减的一个参数,越大衰减约快。聚光灯

    new THREE.AreaLight(),区域光

    new THREE.DirectionaLight(hex, intensity ),方向光,一组没有衰减的平行的光线,类似太阳光的效果。

    new THREE.AmbientLight( hex ),hex是一个16进制的颜色值,环境光。环境光并不在乎物体材质的color属性,而是ambient属性

    new THREE.PointLight( color, intensity, distance ),Color:光的颜色Intensity:光的强度,默认是1.0,就是说是100%强度的灯光,distance:光的距离,从光源所在的位置,经过distance这段距离之后,光的强度将从Intensity衰减为0。 默认情况下,这个值为0.0,表示光源强度不衰减。点光源

    New HemisphereLight(groudColor,color,intensity)半球光

    New LensFlare(texture,size,distance,blending,color)镜头炫光

    light.position.set(0, 0,300);光源的xyz坐标

    light.castShadow = true;投射阴影

    light.visible = !e;移除该光源

    Light.color=;可以改变光源的颜色

    在Three.js中,能形成阴影的光源只有THREE.DirectionalLight与THREE.SpotLight;而相对地,能表现阴影效果的材质只有THREE.LambertMaterial与THREE.PhongMaterial。因而在设置光源和材质的时候,一定要注意这一点。

    Scene:

    new THREE.Scene();声明一个场景

    scene.background = new THREE.Color().setHSL( 0.51, 0.6, 0.6 );

    scene.background = newTHREE.CubeTextureLoader()//天空盒1

    .setPath('textures/cube/Park3Med/')

    .load( ['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] );

    var path = "textures/cube/Park2/";//天空盒2var format = '.jpg';var urls =[

    path+ 'posx' + format, path + 'negx' +format,

    path+ 'posy' + format, path + 'negy' +format,

    path+ 'posz' + format, path + 'negz' +format

    ];var textureCube = newTHREE.CubeTextureLoader().load( urls );

    textureCube.format=THREE.RGBFormat;

    scene= newTHREE.Scene();

    scene.background= textureCube;

    scene.add(mesh);

    scene.add(light);

    scene.remove(lastObject);溢出某个物体

    scene.children.length;场景内物体的个数

    scene.traverse(function),传递过来的function将在每一个object上面执行一次,也可以使用for循环

    Scene.getChildByName(name)

    Scene.overrideMaterial=new        THREE.MeshBasicMaterial({map:texture});场景中全部物体使用该材质

    Scene.fog=new THREE.Fog();添加雾化效果

    TWEEN:

    new TWEEN.Tween( mesh.position),动画引擎实现动画效果,声明

    new TWEEN.Tween( mesh.position)  .to( { x: -400 }, 3000 ).repeat( Infinity ).start();TWEEN.Tween的构造函数接受的是要改变属性的对象,这里传入的是mesh的位置。Tween的任何一个函数返回的都是自身,所以可以用串联的方式直接调用各个函数。to函数,接受两个参数,第一个参数是一个集合,里面存放的键值对,键x表示mesh.position的x属性,值-400表示,动画结束的时候需要移动到的位置。第二个参数,是完成动画需要的时间,这里是3000ms。repeat( Infinity )表示重复无穷次,也可以接受一个整形数值,例如5次。

    TWEEN.update();在渲染函数中去不断的更新Tween,这样才能够让mesh.position.x移动位置

    line:

    new THREE.Line( geometry, material, THREE.LinePieces );第一个参数是几何体geometry,里面包含了2个顶点和顶点的颜色。第二个参数是线条的材质,或者是线条的属性,表示线条以哪种方式取色。第三个参数是一组点的连接方式

    group:

    new THREE.Group();group.add(sphere); group.add(cube);

    texture:

    THREE.Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy )        "Image:这是一个图片类型,基本上它有ImageUtils来加载,如下代码

    var image = THREE.ImageUtils.loadTexture(url);

    Mapping:是一个THREE.UVMapping()类型,它表示的是纹理坐标。

    wrapS:表示x轴的纹理的回环方式,就是当纹理的宽度小于需要贴图的平面的宽度的时候,平面剩下的部分应该以何种方式贴图的问题。

    wrapT:表示y轴的纹理回环方式。magFilter和minFilter表示过滤的方式,这是OpenGL的基本概念,不设置的时候,它会取默认值。

    format:表示加载的图片的格式,这个参数可以取值THREE.RGBAFormat,RGBFormat等。THREE.RGBAFormat表示每个像素点要使用四个分量表示,分别是红、绿、蓝、透明来表示。RGBFormat则不使用透明,也就是说纹理不会有透明的效果。

    type:表示存储纹理的内存的每一个字节的格式,是有符号,还是没有符号,是整形,还是浮点型。不过这里默认是无符号型(THREE.UnsignedByteType)。

    anisotropy:各向异性过滤。使用各向异性过滤能够使纹理的效果更好,但是会消耗更多内存、CPU、GPU时间。"

    texture.wrapS = THREE.RepeatWrapping;

    texture.wrapT = THREE.RepeatWrapping;

    texture.repeat.set(4, 4);

    texture.needsUpdate = true;

    grid:

    new THREE.GridHelper( 1000, 50 );边长为1000,大网格中有小网格,小网格的边长是50.

    grid.setColors( 0x0000ff, 0x808080 );网格线的颜色一头是0x0000ff,另一头是0x808080。线段中间的颜色取这两个颜色的插值颜色。

    Rotation  :

    new THREE.Euler();旋转中心在立方体的中心

    mesh.rotateX(0.01);

    mesh.rotateY(0.01);

    mesh.rotateZ(0.01);

    UglifyJS:压缩工具

    Helper:

    坐标轴AxisHelper      :  new THREE.AxisHelper(20);  scene.add(axes);

    法向量ArrowHelper

    new THREE.ArrowHelper(

    face.normal,

    centroid,

    2,

    0x3333FF,

    0.5,

    0.5);

    cube.add(arrow);

    datGUI:

    new dat.GUI() ;用来添加用户界面

    gui.add(controls, 'rotationSpeed', 0, 0.5);,controls是控制的变量,rotationspeed是属性之一,0--0.5是取值变化范围

    var controls = new function () {

    this.rotationSpeed = 0.02;

    this.bouncingSpeed = 0.03;

    };

    var gui = new dat.GUI();

    gui.add(controlsFunction, 'name', 0, 0.5);//取值范围

    gui.add(controls, 'numberOfObjects').listen();监听并显示

    f1 = gui.addFolder('Vertices ' + (i + 1));

    f1.add(controlPoints[i], 'x', -10, 10);

    gui.add(controls, 'disableSpotlight').onChange(function (e) {

    spotLight.visible = !e;

    });

    ASCII文本画

    new THREE.AsciiEffect(renderer);

    effect.setSize(width,height)

    $("div").append(effect.domElement)

    effect.render(scene,renderer)

    普通雾化效果Fog

    new THREE.Fog(color,near,far)

    new THREE.FogExp2(color,浓度)

    粒子系统:

    new THREE.SpriteMaterial();

    new THREE.Sprite(material);

    new THREE.SpriteCanvasMaterial()

    new THREE.ParticleBasicMaterial();

    new THREE.Particle(material);

    new THREE.PointCloudMaterial({size: 4, vertexColors: true, color: 0xffffff});

    new THREE.PointCloud(geom, material);

    轨道控件:

    控制object的方向,能让其随着鼠标的方向转动

    声明:new THREE.OrbitControls(camera);(render的时候,orbit.update()即可;)

    飞行控件:

    new THREE.FlyControls()

    翻滚控件:

    new THREE.RollControls()

    轨迹球控件:

    new THREE.TrackballControls

    路径控件

    new THREE.PathControls()

    文件系统:

    new THREE.FileLoader();

    定义投影仪(r85版本里面貌似被淘汰了)

    new THREE.Projector();

    在某个position位置向场景中发射一束光线

    new THREE.Raycaster()

    时钟控件:

    new THREE.Clock();可以精确的计算出上次调用后经过的时间

    骨骼动画

    new THREE.SkinnedMesh(geometry,mat).bones[];带有蒙皮的网格对象

    THREE.AnimationHandler.add(geometry.animation)注册动画

    newTHREE.Animation(mesh, model.animation);定义动画

    newTHREE.SkeletonHelper(mesh);SkeletonHelper可以用线显示出骨架,帮助我们调试骨架,可有可无

    PosTProcessing

    var clearPass = newTHREE.ClearPass();var clearMaskPass = newTHREE.ClearMaskPass();var maskPass1 = new THREE.MaskPass( scene1, camera );

    var outputPass = new THREE.ShaderPass( THREE.CopyShader );

    THREEJS基本功能一览表

    Camera

    OrthographicCamera

    PerspectiveCamera

    Core(核心对象)

    BufferGeometry

    Clock(用来记录时间)

    EventDispatcher

    Face3

    Face4

    Geometry

    Object3D

    Projector

    Raycaster(计算鼠标拾取物体时很有用的对象)

    Lights(光照)

    Light

    AmbientLight

    AreaLight

    DirectionalLight

    HemisphereLight

    PointLight

    SpotLight

    Loaders(加载器,用来加载特定文件)

    Loader

    BinaryLoader

    GeometryLoader

    ImageLoader

    JSONLoader

    LoadingMonitor

    SceneLoader

    TextureLoader

    Materials(材质,控制物体的颜色、纹理等)

    Material

    LineBasicMaterial

    LineDashedMaterial

    MeshBasicMaterial

    MeshDepthMaterial

    MeshFaceMaterial

    MeshLambertMaterial

    MeshNormalMaterial

    MeshPhongMaterial

    PointCloudMaterial(ParticleBasicMaterial)

    SpriteCanvasMaterial(ParticleCanvasMaterial)

    ParticleDOMMaterial

    ShaderMaterial

    SpriteMaterial

    MeshStandardMaterial:

    MeshPhysicalMaterial

    Math(和数学相关的对象)

    Box2

    Box3

    Color

    Frustum

    Math

    Matrix3

    Matrix4

    Plane

    Quaternion

    Ray

    Sphere

    Spline

    Triangle

    Vector2

    Vector3

    Vector4

    Objects(物体)

    Bone

    Line

    LOD

    Mesh(网格,最常用的物体)

    MorphAnimMesh

    PointCloud(ParticleSystem)

    Ribbon

    SkinnedMesh

    Sprite

    Renderers(渲染器,可以渲染到不同对象上)

    CanvasRenderer

    WebGLRenderer(使用WebGL渲染,这是本书中最常用的方式)

    WebGLDefferedRenderer

    WebGLRenderTarget

    WebGLRenderTargetCube

    WebGLShaders(着色器,在最后一章作介绍)

    Renderers/Renderables

    RenderableFace3

    RenderableFace4

    RenderableLine

    RenderableObject

    RenderableParticle

    RenderableVertex

    Scenes(场景)

    Fog

    FogExp2

    Scene

    Textures(纹理)

    CompressedTexture

    DataTexture

    Texture

    Extras

    FontUtils

    GeometryUtils

    ImageUtils

    SceneUtils

    Extras/Animation

    Animation

    AnimationHandler

    AnimationMorphTarget

    KeyFrameAnimation

    Extras/Cameras

    CombinedCamera

    CubeCamera

    Extras/Core

    Curve

    CurvePath

    Gyroscope

    Path

    Shape

    Extras/Geometries(几何形状)

    CircleGeometry

    ConvexGeometry

    CubeGeometry

    CylinderGeometry

    ExtrudeGeometry

    IcosahedronGeometry

    LatheGeometry

    OctahedronGeometry

    ParametricGeometry

    PlaneGeometry

    PolyhedronGeometry

    ShapeGeometry

    SphereGeometry

    TetrahedronGeometry

    TextGeometry

    TorusGeometry

    TorusKnotGeometry

    TubeGeometry

    Extras/Helpers

    ArrowHelper

    AxisHelper

    BoxHelper

    CameraHelper

    DirectionalLightHelper

    FaceNormalHelper

    GridHelper

    HemisphereLightHelper

    PointLightHelper

    PolarGridHelper

    RectAreaLightHelper

    SkeletonHelper

    SpotLightHelper

    VertexNormalsHelper

    Extras/Objects

    ImmediateRenderObject

    LensFlare

    MorphBlendMesh

    Extras/Renderers/Plugins

    DepthPassPlugin

    LensFlarePlugin

    ShadowMapPlugin

    SpritePlugin

    Extras/Shaders

    ShaderFlares

    ShaderSprite

    展开全文
  • threejs纹理

    2020-12-23 07:06:54
    光照贴图 环境贴图 环境贴图是使用上下左右前后六张图或者一张全景图来模拟真实的环境,threejs会将这些图片渲染成无缝的环境盒子,例子可看【threejs-cubeMap例子】,其中貌似真实的环境,球的反光效果,都是用这...
  • 最新版cesium集成threejs

    2021-12-08 15:14:14
    cesium集成thressjs,完成地球加载three模型,并且同步。
  • threejs粒子效果

    2021-11-26 11:37:01
    threejs粒子效果有两种方法:THREE.Particle和THREE.ParticleSytem,THREE.Sprite。本案例中的粒子系统就是通过Sprite类来实现的。 初始化基本配置 首先定义基本的用到的,通常包括容器,相机,场景,渲染器,性能...
  • threejs一些基础

    2021-05-12 01:54:31
    导入js包场景对象-scene几何对象-Geometry材质-material网格对象-mesh(对象,材质)光源-Light摄像机-cameracamera.lookAt相机看的方向渲染器-rendererdocument.body.appendChild(renderer.domElement); //body元素中...
  • 引子最近,忽然想起曾在 WebGL 基础系列 文章中立下 flag:“后续还打算出 《ThreeJS 源码剖析》 系列”(特意翻出原话 ),项目忙了一阵后,便决定开始写此系列,更新周期不固定,毕竟项目排期“天晓得”。...
  • threejs

    2021-08-23 11:04:37
    vue集成Threejs 1.需要的依赖: npm i three --save npm i imports-loader exports-loader --save-dev npm i import-three-examples --save-dev 2.webpack的配置: const ThreeExamples = require('import-three-...
  • ThreeJs 认识纹理

    2020-12-23 07:06:55
    一、前言这篇文章,我们主要来了解一下 ThreeJs 中纹理相关的知识。渲染一个 3D 物体时,网格 Mesh 决定了这个物体的形状态,如一个球,一辆车,一个人等。而纹理决定了这个物体的表面具体长什么样子。一个球包上一...
  • 使用内置摄像头生成的深度图,超出像素深度的位置在阴影中,在渲染期间内部计算 参考文档一 ———— Threejs光源对象 参考文档二 ———— HemisphereLight和AmbientLight 区别 参考文档三 ———— Threejs官方...
  • 该示例使用的是 r95版本Three.js库。利用A*算法实现寻路、导航功能。添加坐标轴。 效果图如下: 2,主要说明 引入A*算法astar.js <script type="text/javascript" src="libs/astar.js"></script&...
  • ThreeJS后期处理

    2021-12-13 08:39:21
    threejs的后期处理通道包提供了各种强大的效果,有了这些效果会大大降低代码难度,并且可以直接使用内置的着色器包,避免了复杂的着色器代码编写。后期处理通道一般都按顺序执行,后加入的会覆盖前面的通道。 如...
  • 1、ThreeJS的常见几何体 BufferGeometry和Geometry有什么不同? 如果你想简单理解BufferGeometry和Geometry有什么不同,就是两者的数据结构不同,缓冲类型几何体BufferGeometry相比普通几何体Geometry性能更好。...
  • 准备一张地图,创建一个球体并进行贴图,把地理位置经纬度转换成threejs的世界坐标,并进行标注。 创建地球,部分代码如下: // 创建地球 半径100 function createEarth() { var earthGeo = new THREE....
  • 原标题:实战:用 threejs 创建一个地球提示:讲座前端大型免费公开课讲座教程从零基础学前端教程,都在这~上个月底,在朋友圈看到一个号称“这可能是地球上最美的h5”的分享,点进入后发现这个h5还很别致,思考了...
  • threejs优化之3D模型压缩(gltf-pipeline,采用draco压缩算法)
  • threejs使用

    2020-12-31 12:16:30
    threejs使用threejs的一个小demoHTMLcode threejs的一个小demo 这是一个小得demo,应为要加载3D模型文件,所以用threejs加载了stl类型文件,如图 话不多说,直接上文件,请各位为大佬看过以后,帮忙处处注意,模型...
  • vue + threejs 实现3d装车

    2021-07-23 09:34:52
    npm install threejs -D 引用threejs import * as THREE from 'three' // 鼠标控制器 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' // obj模型 import { OBJLoader } from '...
  • 外部模型格式Threejs支持了许多格式的3D模型导入,包括*.obj、 *.sea、*.3mf 、*.amf、*.sea、*.pmd、*.json等。这里主要讲解一下obj模型的导入,及将obj文件转成文件更小的json格式导入。导入obj模型3Dmax格式转换...
  • var material = new THREE.MeshPhongMaterial(); var sphereMesh = new THREE.Mesh(sphereGeometry, material) scene.add(sphereMesh); var shaderMaterial = new THREE.ShaderMaterial( { vertexS
  • threejs基础示例

    2021-03-13 06:31:54
    "> body> <script src="lib/three.js">script> <script src="lib/SceneUtils.js">script> <script src="lib/stats.min.js">script> <script src="lib/dat.gui.min.js">script> <script> //这里就是三维的代码写入 ...
  • threejs实现汽车展览

    2021-10-23 22:31:39
    1:通过threejs加载模型 2:定位车门 打标记点 然后写开门动画 3:使用点写灯光特效 4:编辑内饰和车身材质,使用法向贴图做出磨砂效果 7:使用全景模拟反光效果,如果后视镜也想这样的话 可以使用动态全景的...
  • 通过Three.js的相机控件OrbitControls.js可以对Threejs的三维场景进行缩放、平移、旋转操作,本质上改变的并不是场景,而是相机的参数,通过前面的学习应该知道,相机的位置角度不同,同-个场景的渲染效果是不一样,...
  • threejs中深度与透明

    2020-12-20 23:23:38
    threejs 的日常开发中,我们经常会遇到关于深度、透明一些渲染问题。这里我们就来简单的做下讲解,希望能帮助大家绕开一些常见的坑。深度我们来了解下 webgl 中的深度到底是怎么回事儿,首先 webgl 中,深度会...
  • THREEJS中的3D(动画)模型

    千次阅读 2020-12-24 19:13:27
    在模型上的面(三角形)如下图 至此,整个无动画模型的基础数据格式我们都了解了,threejs内有多种加载器,但是,最后threejs要解析的就是这样的json格式数据。 当然,对于这些数据,我们能手动修改的地方不多,如果...
  • 关于threejs灯光的使用

    2021-08-19 12:15:23
    ThreeJS中有几种光源,去模拟现实环境。最常见的四种分别为: 环境光( AmbientLight ):笼罩在整个空间无处不在的光 点光源( PointLight ):向四面八方发射的单点光源 聚光灯( SpotLight ):发射出锥形状的光, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,203
精华内容 24,881
关键字:

threejs