three.js基础

1.三大组建

var scene = new THREE.Scene();  // 场景
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);// 透视相机

2.渲染器renderer

//注意,渲染器renderer的domElement元素,表示渲染器中的画布,所有的渲染都是画在domElement上的,所以这里的appendChild表示将这个domElement挂接在body下面,这样渲染的结果就能够在页面中显示了。
var renderer = new THREE.WebGLRenderer();   // 渲染器
renderer.setSize(window.innerWidth, window.innerHeight);    // 设置渲染器的大小为窗口的内宽度,也就是内容区的宽度
document.body.appendChild(renderer.domElement);

3.场景

//场景是所有物体的容器,如果要显示一个苹果,就需要将苹果对象加入场景中。
var scene = new THREE.Scene();


//将一个物体添加到场景中
var geometry = new THREE.CubeGeometry(1,1,1); 
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material); 
scene.add(cube);

//width:立方体x轴的长度 height:立方体y轴的长度 depth:立方体z轴的深度,也就是长度 想一想大家就明白,以上3个参数就能够确定一个立方体。
width:表示立方体的宽度。
height:表示立方体的高度。
depth:表示立方体的长度或者说深度吧。
widthSegments:宽度分段份数
heightSegments:高度分段份数
depthSegments:长度分段份数
-- CubeGeometry(width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, sides)

4.渲染器

//渲染应该使用渲染器,结合相机和场景来得到结果画面。实现这个功能的函数是
renderer.render(scene, camera);

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

5.渲染循环

渲染有两种方式:实时渲染和离线渲染 。
先看看离线渲染,想想《西游降魔篇》中最后的佛主,他肯定不是真的,是电脑渲染出来的,其画面质量是很高的,它是事先渲染好一帧一帧的图片,然后再把图片拼接成电影的。这就是离线渲染。如果不事先处理好一帧一帧的图片,那么电影播放得会很卡。CPU和GPU根本没有能力在播放的时候渲染出这种高质量的图片。
实时渲染:就是需要不停的对画面进行渲染,即使画面中什么也没有改变,也需要重新渲染。下面就是一个渲染循环:

requestAnimationFrame,这个函数就是让浏览器去执行一次参数中的函数,这样通过上面render中调用requestAnimationFrame()函数,requestAnimationFrame()函数又让rander()再执行一次,就形成了我们通常所说的游戏循环了。

function render() {
    cube.rotation.x += 0.1;
    cube.rotation.y += 0.1;
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

6.场景,相机,渲染器之间的关系

Three.js中的场景是一个物体的容器,开发者可以将需要的角色放入场景中,例如苹果,葡萄。同时,角色自身也管理着其在场景中的位置。

相机的作用就是面对场景,在场景中取一个合适的景,把它拍下来。

渲染器的作用就是将相机拍摄下来的图片,放到浏览器中去显示。他们三者的关系如下图所示:

实例

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style>canvas { width: 100%; height: 100% }</style>
    <script src="js/three.js"></script>
</head>
<body>
    <script>
        var scene = new THREE.Scene();
        
        var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
        
        var renderer = new THREE.WebGLRenderer();
        
        renderer.setSize(window.innerWidth, window.innerHeight);
        
        document.body.appendChild(renderer.domElement);
        //设置物体刻度尺寸
        var geometry = new THREE.CubeGeometry(10,20,10);
        var material = new THREE.MeshBasicMaterial({color: 'red'});
        var cube = new THREE.Mesh(geometry, material); scene.add(cube);
        //坐标系刻度
        camera.position.z = 100;
        function render() {
            requestAnimationFrame(render);
            //x轴旋转
            cube.rotation.x += 0.1;
            //Y轴旋转
            cube.rotation.y += 0.1;
            //Z轴旋转
            cube.rotation.z += 0.1;
            //渲染
            renderer.render(scene, camera);
        }
        render();
    </script>
</body>
</html>

7.在三维空间中的某一个点可以用一个坐标点来表示。一个坐标点由x,y,z三个分量构成。

THREE.Vector3 = function ( x, y, z ) {
    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
};

//现在来看看怎么定义个点,假设有一个点x=4,y=8,z=9。你可以这样定义它:
var point1 = new THREE.Vecotr3(4,8,9);

//另外你也可以使用set方法,代码如下:
var point1 = new THREE.Vector3();
point1.set(4,8,9);

8.几何体geometry

//几何体里面有一个vertices变量,可以用来存放点。
var geometry = new THREE.Geometry();

9.定义一种线条的材质,使用THREE.LineBasicMaterial类型来定义,它接受一个集合作为参数,其原型如下:

LineBasicMaterial( parameters )

Parameters是一个定义材质外观的对象,它包含多个属性来定义材质,这些属性是:

Color:线条的颜色,用16进制来表示,默认的颜色是白色。

Linewidth:线条的宽度,默认时候1个单位宽度。

Linecap:线条两端的外观,默认是圆角端点,当线条较粗的时候才看得出效果,如果线条很细,那么你几乎看不出效果了。

Linejoin:两个线条的连接点处的外观,默认是“round”,表示圆角。

VertexColors:定义线条材质是否使用顶点颜色,这是一个boolean值。意思是,线条各部分的颜色会根据顶点的颜色来进行插值。(如果关于插值不是很明白,可以QQ问我,QQ在前言中你一定能够找到,嘿嘿,虽然没有明确写出)。

Fog:定义材质的颜色是否受全局雾效的影响。

好了,介绍完这些参数,你可以试一试了,在课后,我们会展示不同同学的杰出作品。下面,接着上面的讲,我们这里使用了顶点颜色vertexColors: THREE.VertexColors,就是线条的颜色会根据顶点来计算。

var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );


//定义颜色
var color1 = new THREE.Color( 0x444444 ),color2 = new THREE.Color( 0xFF0000 );
//定义点的位置
var p1 = new THREE.Vector3( -100, 0, 100 );
var p2 = new THREE.Vector3( 100, 0, -100 );
geometry.vertices.push(p1);
geometry.vertices.push(p2);

//为4中定义的2个顶点,设置不同的颜色
//geometry中colors表示顶点的颜色,必须材质中vertexColors等于THREE.VertexColors 时,颜色才有效,如果vertexColors等于THREE.NoColors时,颜色就没有效果了。那么就会去取材质中color的值,这个很重要,大家一定记住。
geometry.colors.push( color1, color2 );

//定义线条,使用THREE.Line类,代码如下所示:
//第一个参数是几何体geometry,里面包含了2个顶点和顶点的颜色。第二个参数是线条的材质,或者是线条的属性,表示线条以哪种方式取色。第三个参数是一组点的连接方式,我们会在后面详细讲解。
var line = new THREE.Line( geometry, material, THREE.LinePieces );
//然后,将这条线加入到场景中,代码如下:
scene.add(line);

10.网格的坐标

//在x轴上定义两个点p1(-500,0,0),p2(500,0,0)。
geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );

这两个点决定了x轴上的一条线段,将这条线段复制20次,分别平行移动到z轴的不同位置,就能够形成一组平行的线段。

同理,将p1p2这条线先围绕y轴旋转90度,然后再复制20份,平行于z轴移动到不同的位置,也能形成一组平行线。

//经过上面的步骤,就能够得到坐标网格了。代码如下:
for ( var i = 0; i <-= 20; i ++ ) {

    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
    line.position.z = ( i * 50 ) - 500;
    scene.add( line );

    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
    line.position.x = ( i * 50 ) - 500;
    line.rotation.y = 90 * Math.PI / 180;   //  旋转90度
    scene.add( line );

}

11.性能检测

你现在可以自己写一段代码,来验证一下,你的程序的帧数了。
Stats到底做了什么事情呢?我们来分析一下。
1、setMode函数
参数为0的时候,表示显示的是FPS界面,参数为1的时候,表示显示的是MS界面。
2、stats的domElement
stats的domElement表示绘制的目的地(DOM),波形图就绘制在这上面。
3、begin
begin,在你要测试的代码前面调用begin函数,在你代码执行完后调用end()函数,这样就能够统计出这段代码执行的平均帧数了。

var stats = new Stats();
stats.setMode(1); // 0: fps, 1: ms
// 将stats的界面对应左上角
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
setInterval( function () {
    stats.begin();
    // 你的每一帧的代码
    stats.end();
}, 1000 / 60 );

//调用stats.update()函数来统计时间和帧数。代码如下
stats.update();

12.使用动画引擎Tween.js来创建动画

1.引入js
<-script src="../js/tween.min.js" data-ke-src="../js/tween.min.js"><-/script>

2.构件一个Tween对象,对Tween进行初始化,本例的代码是:
function initTween()
{
    new TWEEN.Tween( mesh.position)
            .to( { x: -400 }, 3000 ).repeat( Infinity ).start();
}
//to函数,接受两个参数,第一个参数是一个集合,里面存放的键值对,键x表示mesh.position的x属性,值-400表示,动画结束的时候需要移动到的位置。第二个参数,是完成动画需要的时间,这里是3000ms。
//repeat( Infinity )表示重复无穷次,也可以接受一个整形数值,例如5次。
//Start表示开始动画,默认情况下是匀速的将mesh.position.x移动到-400的位置。
//TWEEN.update()完成了让动画动起来到目标。如果不调用这个函数场景就不能动起来了。
function animation()
{
    renderer.render(scene, camera);
    requestAnimationFrame(animation);
    stats.update();
    TWEEN.update();
}



3.

13.正投影相机,正投影的构造函数如下所示:

1、 left参数
left:左平面距离相机中心点的垂直距离。从图中可以看出,左平面是屏幕里面的那个平面。

2、 right参数
right:右平面距离相机中心点的垂直距离。从图中可以看出,右平面是屏幕稍微外面一点的那个平面。

3、 top参数
top:顶平面距离相机中心点的垂直距离。上图中的顶平面,是长方体头朝天的平面。

4、 bottom参数
bottom:底平面距离相机中心点的垂直距离。底平面是头朝地的平面。

5、near参数
near:近平面距离相机中心点的垂直距离。近平面是左边竖着的那个平面。

6、far参数
far:远平面距离相机中心点的垂直距离。远平面是右边竖着的那个平面。

OrthographicCamera( left, right, top, bottom, near, far )

有了这些参数和相机中心点,我们这里将相机的中心点又定义为相机的位置。通过这些参数,我们就能够在三维空间中唯一的确定上图的一个长方体。这个长方体也叫做视景体。
投影变换的目的就是定义一个视景体,使得视景体外多余的部分裁剪掉,最终图像只是视景体内的有关部分。

//好了,看一个简单的例子:
var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
scene.add( camera );

这个例子将浏览器窗口的宽度和高度作为了视景体的高度和宽度,相机正好在窗口的中心点上。这也是我们一般的设置方法,基本上为了方便,我们不会设置其他的值。

14.透视投影相机

1、视角fov:这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,但是在180度的时候,往往物体很小,因为他在你的整个可视区域中的比例变小了。

2、近平面near:这个呢,表示你近处的裁面的距离。补充一下,也可以认为是眼睛距离近处的距离,假设为10米远,请不要设置为负值,Three.js就傻了,不知道怎么算了,

3、远平面far:这个呢,表示你远处的裁面,

4、纵横比aspect:实际窗口的纵横比,即宽度除以高度。这个值越大,说明你宽度越大,那么你可能看的是宽银幕电影了,如果这个值小于1,那么可能你看到的是如下的图中的LED屏幕了。

//透视投影相机的构造函数如下所示:

PerspectiveCamera( fov, aspect, near, far )

//好了,看看下面一个简单的例子:
var camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add( camera );
  1. 光源基类
    //在Threejs中,光源用Light表示,它是所有光源的基类。它的构造函数是:
THREE.Light ( hex )

//它有一个参数hex,接受一个16进制的颜色值。例如要定义一种红色的光源,我们可以这样来定义
Var redLight = new THREE.Light(0xFF0000);

1.环境光用THREE.AmbientLight来表示,它的构造函数如下所示:

THREE.AmbientLight( hex )
//它仍然接受一个16进制的颜色值,作为光源的颜色。环境光将照射场景中的所有物体,让物体显示出某种颜色。环境光的使用例子如下所示:
var light = new THREE.AmbientLight( 0xff0000 );
scene.add( light );

//只需要将光源加入场景,场景就能够通过光源渲染出好的效果来了。

2.点光源:由这种光源放出的光线来自同一点,且方向辐射自四面八方。例如蜡烛放出的光,萤火虫放出的光。

//点光源用PointLight来表示,它的构造函数如下所示:
PointLight( color, intensity, distance )

这个类的参数稍微复杂一些,我们花点时间来解释一下:
Color:光的颜色
Intensity:光的强度,默认是1.0,就是说是100%强度的灯光,
distance:光的距离,从光源所在的位置,经过distance这段距离之后,光的强度将从Intensity衰减为0。 默认情况下,这个值为0.0,表示光源强度不衰减。

3.聚光灯的构造函数是:

THREE.SpotLight( hex, intensity, distance, angle, exponent )

函数的参数如下所示:

Hex:聚光灯发出的颜色,如0xFFFFFF
Intensity:光源的强度,默认是1.0,如果为0.5,则强度是一半,意思是颜色会淡一些。和上面点光源一样。
Distance:光线的强度,从最大值衰减到0,需要的距离。 默认为0,表示光不衰减,如果非0,则表示从光源的位置到Distance的距离,光都在线性衰减。到离光源距离Distance时,光源强度为0.
Angle:聚光灯着色的角度,用弧度作为单位,这个角度是和光源的方向形成的角度。
exponent:光源模型中,衰减的一个参数,越大衰减约快。

16.绘制网格

1、var helper = new THREE.GridHelper( 1000, 50 )这一行,生成了一个网格模型,边长为1000,大网格中有小网格,小网格的边长是50.

2、网格线的颜色一头是0x0000ff,另一头是0x808080。线段中间的颜色取这两个颜色的插值颜色。

function initGrid(){
    // 网格的边长是1000,每个小网格的边长是50
    var helper = new THREE.GridHelper( 1000, 50 );
    helper.setColors( 0x0000ff, 0x808080 );
    scene.add( helper );
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 挺好的的发卡机哦哦开发鄂温克
    37度先生阅读 142评论 0 1
  • 非暴力沟通的目的不是为了改变他人来迎合我们。相反,非暴力沟通重视每个人的需要,它的目的是帮助我们在诚实和倾听的基础...
    巴山小羊儿阅读 4,230评论 0 1
  • 2018年4月24日 星期二 多云转晴 今天下班刚到家,女儿就跟我说:“妈妈,以后我的作业我写完先自...
    周李扬阅读 116评论 0 0