threejs - 4 - 物體

:)


簡介

在三維空間中的物體是由點(diǎn)、線、面組成的

  • 點(diǎn): 三維空間中的一個點(diǎn)(包含x , y ,z)
  • 線:兩個點(diǎn)就能確定一條直線(包含起點(diǎn)和終點(diǎn))晓猛,多個點(diǎn)可以繪制一條折線
  • 面:三個點(diǎn)就可以確定一個面(暫時(shí)理解成WebGL里面僅僅支持 三角形的繪制)
  • 三維物體:多個面組合起來就可以構(gòu)成一個三維物體

不管是點(diǎn) 访敌、線還是面,里面的坐標(biāo)點(diǎn)都叫頂點(diǎn)着倾。可以給不同的頂點(diǎn)設(shè)置不同的顏色燕少,這個過程叫著色(看不懂的話有個概念就行卡者,頂點(diǎn) + 顏色 = 三維物體)


點(diǎn)

  • 定義點(diǎn)的位置(x,y客们,z)崇决,ThreeJs中使用 THREE.Vector3 來存儲三維坐標(biāo)信息
    // 定義了三個坐標(biāo)信息  (0, 0, 0) (1, 1, 0)  (2, 2, 0)
    var p1 = new THREE.Vector3(0,0,0);
    var p2 = new THREE.Vector3(1,1,0);
    var p3 = new THREE.Vector3(2,2,0);
  • 定義一個存儲這些點(diǎn)的容器(可以簡單理解成GPU為了提高繪制的效率,會一次性的讀取所有的點(diǎn)底挫,所以需要一個容器來存儲所有的點(diǎn)信息)恒傻,ThreeJs里面使用 THREE.Geometry 來存儲點(diǎn)的信息
    // 定義存儲點(diǎn)的容器
    var pointsG = new THREE.Geometry();
    pointsG.vertices.push(p1, p2, p3);
  • 定義點(diǎn)的顯示樣式(不懂不要緊,樣式后面會詳解建邓。簡單理解就是點(diǎn)的顏色盈厘,大小)
    // 定義點(diǎn)的顏色是紅色 大小是0.1
    var pointsM = new THREE.PointsMaterial({
        color: 0xff0000, size: 0.1
    });
  • 繪制點(diǎn)ThreeJs中 THREE.Points 這個類會將定義好的頂點(diǎn)涝缝,使用點(diǎn)的方式繪制出來
    // 使用點(diǎn)的方式繪制定義好的頂點(diǎn) 并添加到場景中
    var points = new THREE.Points(pointsG, pointsM);
    scene.add(points);

這里的points可以指定顯示在場景的位置扑庞,而points里面定義的頂點(diǎn)是相對于場景位置的點(diǎn)

  • 點(diǎn)繪制小結(jié)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="three.min.js"></script>
</head>
<body>
    <div id="container"></div>
</body>
<script>
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);

    // 定義了三個坐標(biāo)信息  (0, 0, 0) (1, 1, 0)  (2, 2, 0)
    var p1 = new THREE.Vector3(0,0,0);
    var p2 = new THREE.Vector3(1,1,0);
    var p3 = new THREE.Vector3(2,2,0);

    // 定義存儲點(diǎn)的容器
    var pointsG = new THREE.Geometry();
    pointsG.vertices.push(p1, p2, p3);

    // 定義點(diǎn)的顏色是紅色 大小是0.1
    var pointsM = new THREE.PointsMaterial({
        color: 0xff0000, size: 0.1
    });

    // 使用點(diǎn)的方式繪制定義好的頂點(diǎn) 并添加到場景中
    var points = new THREE.Points(pointsG, pointsM);
    scene.add(points);

    camera.position.set(5, 5, 5);
    camera.lookAt(new THREE.Vector3(0,0,0));

    document.getElementById("container").appendChild(renderer.domElement);

    function run() {
        renderer.render(scene, camera);
        requestAnimationFrame(run);
    }

    run();
</script>
</html>

  • 至少兩個頂點(diǎn)構(gòu)成了一條線譬重。線的繪制流程和點(diǎn)類似,定義頂點(diǎn)罐氨,設(shè)置樣式臀规,添加到場景
  • 定義線經(jīng)過的頂點(diǎn)
    // 定義線經(jīng)過的頂點(diǎn)
    var p1 = new THREE.Vector3(1,0,0);
    var p2 = new THREE.Vector3(1,1,0);
    var p3 = new THREE.Vector3(2,2,0);
    var p4 = new THREE.Vector3(2,1,0);
  • 定義存儲點(diǎn)的容器
    // 定義存儲點(diǎn)的容器
    var pointsG = new THREE.Geometry();
    pointsG.vertices.push(p1, p2, p3, p4);

  • 設(shè)置線的樣式(樣式相關(guān)后面專門講)
    // 設(shè)置線的樣式
    var lineM = new THREE.LineBasicMaterial({color: 0xff0000});
  • 使用THREE.Line將點(diǎn)用線的方式連接起來
    // 折線
    var line = new THREE.Line(pointsG, lineM);
    scene.add(line);
  • 使用THREE.LineLoop繪制封閉的線
    // 封閉的線
    var line = new THREE.LineLoop(pointsG, lineM);
    scene.add(line);
  • 使用THREE.LineSegments繪制線段(會將點(diǎn)進(jìn)行兩輛組合,就會生成多個線段)
    // 繪制線段
    var line = new THREE.LineSegments(pointsG, lineM);
    scene.add(line);
  • 線的繪制模式有三種栅隐,折線(Line)塔嬉、密封的線(LineLoop)、線段(兩兩一組的線段租悄,LineSegments

  • 線的繪制代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="three.min.js"></script>
</head>
<body>
    <div id="container"></div>
</body>
<script>
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);

    // 定義線經(jīng)過的頂點(diǎn)
    var p1 = new THREE.Vector3(1,0,0);
    var p2 = new THREE.Vector3(1,1,0);
    var p3 = new THREE.Vector3(2,2,0);
    var p4 = new THREE.Vector3(2,1,0);

    // 定義存儲點(diǎn)的容器
    var pointsG = new THREE.Geometry();
    pointsG.vertices.push(p1, p2, p3, p4);

    // 設(shè)置線的樣式
    var lineM = new THREE.LineBasicMaterial({color: 0xff0000});

    // 繪制線段
    var line = new THREE.LineSegments(pointsG, lineM);
    scene.add(line);

    camera.position.set(5, 5, 5);
    camera.lookAt(new THREE.Vector3(0,0,0));

    document.getElementById("container").appendChild(renderer.domElement);

    function run() {
        renderer.render(scene, camera);
        requestAnimationFrame(run);
    }

    run();
</script>
</html>

  • 繪制平面的套路和繪制線和點(diǎn)的套路有一些區(qū)別
  • 定義這個平面上的頂點(diǎn)
    // 定義平面上的頂點(diǎn)
    var vertices = [
        new THREE.Vector3(0,0,0),
        new THREE.Vector3(1,2,0),
        new THREE.Vector3(2,2,0),
    ];
  • 處理存放頂點(diǎn)的容器
    // 定義存儲點(diǎn)的容器
    var geo = new THREE.Geometry();
    geo.vertices = vertices;

這里我們雖然定義了頂點(diǎn)谨究,但是還沒有告訴ThreeJs怎么通過這些頂點(diǎn)來構(gòu)成平面。這里可能有些疑惑泣棋,我都已經(jīng)定義好了平面上的頂點(diǎn)了胶哲,為啥不能直接根據(jù)頂點(diǎn)生成平面?原因是在于三維空間中的物體是由很多很多平面構(gòu)成的潭辈,平面于平面之間的頂點(diǎn)會有重合鸯屿,如果直接用頂點(diǎn)的話會有很多重復(fù)的頂點(diǎn)定義。

  • 定義怎么通過頂點(diǎn)構(gòu)成平面把敢,ThreeJs里面通過 THREE.Face3 這個類來定義平面
    // 定義平面
    geo.faces = [
        new THREE.Face3(2,1,0) // 這里的 2 , 1, 0 指的是vertices定義的頂點(diǎn)的下標(biāo)
    ];

上面定義了一個平面寄摆,THREE.Face3(2,1,0) 這個里面的 2 指的是 vertices 里面下標(biāo)為2的頂點(diǎn),1 指的是下標(biāo)為1的頂點(diǎn)修赞,0 指的是下標(biāo)為0的頂點(diǎn)婶恼。 2,1柏副,0 的順序也是有說法的(GPU為了提高渲染效率勾邦,默認(rèn)僅僅渲染逆時(shí)針方向的平面,如果你寫成了 0割择,1检痰,2 就可能渲染不出來)

  • 設(shè)置平面的樣式(具體什么意思后面專門講)
    // 設(shè)置平面的樣式
    var meshM = new THREE.MeshBasicMaterial({color: 0xffff00});
  • 生成平面,使用的是ThreeJs里面的 THREE.Mesh
    // 繪制平面
    var mesh = new THREE.Mesh(geo, meshM);
  • 平面繪制代碼
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="three.min.js"></script>
</head>
<body>
    <div id="container"></div>
</body>
<script>
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);

    // 定義平面上的頂點(diǎn)
    var vertices = [
        new THREE.Vector3(0,0,0),
        new THREE.Vector3(1,2,0),
        new THREE.Vector3(2,2,0),
    ];

    // 定義存儲點(diǎn)的容器
    var geo = new THREE.Geometry();
    geo.vertices = vertices;
    // 定義平面
    geo.faces = [
        // 定義了一個平面
        new THREE.Face3(2,1,0) // 這里的 2 , 1, 0 指的是vertices定義的頂點(diǎn)的下標(biāo)
    ];

    // 設(shè)置平面的樣式
    var meshM = new THREE.MeshBasicMaterial({color: 0xff0000});

    // 繪制平面
    var mesh = new THREE.Mesh(geo, meshM);
    scene.add(mesh);

    camera.position.set(5, 5, 5);
    camera.lookAt(new THREE.Vector3(0,0,0));

    document.getElementById("container").appendChild(renderer.domElement);

    function run() {
        renderer.render(scene, camera);
        requestAnimationFrame(run);
    }

    run();
</script>
</html>

三維物體

  • 多個平面組合起來就是三維物體锨推,所以套路就是定義很多頂點(diǎn),按照頂點(diǎn)組成很多平面(注意:只能是三角形哈公壤,所以要渲染一個矩形的話就需要兩個三角形拼接起來)换可。
  • 這里就直接給代碼
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="three.min.js"></script>
</head>
<body>
    <div id="container"></div>
</body>
<script>
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);

    // 立方體的8個頂點(diǎn)
    var vertices = [
        new THREE.Vector3(1, 1, 1), //v0
        new THREE.Vector3(-1, 1, 1), //v1
        new THREE.Vector3(-1, -1, 1), //v2
        new THREE.Vector3(1, -1, 1), //v3
        new THREE.Vector3(1, -1, -1), //v4
        new THREE.Vector3(1, 1, -1), //v5
        new THREE.Vector3(-1, 1, -1), //v6
        new THREE.Vector3(-1, -1, -1) //v7
    ];

    // 定義存儲點(diǎn)的容器
    var geo = new THREE.Geometry();
    geo.vertices = vertices;
    // 定義立方體的各個平面,
    // 立方體的每個面都是一個正方形厦幅,正方形需要兩個三角形沾鳄,所以定義了12個Face3
    geo.faces = [
        // 定義了一個平面
        new THREE.Face3(0,1,2),
        new THREE.Face3(0,2,3),
        new THREE.Face3(0,3,4),
        new THREE.Face3(0,4,5),
        new THREE.Face3(1,6,7),
        new THREE.Face3(1,7,2),
        new THREE.Face3(6,5,4),
        new THREE.Face3(6,4,7),
        new THREE.Face3(5,6,1),
        new THREE.Face3(5,1,0),
        new THREE.Face3(3,2,7),
        new THREE.Face3(3,7,4)
    ];

    // 設(shè)置平面的樣式
    var meshM = new THREE.MeshBasicMaterial({color: 0xff0000});

    // 繪制平面
    var mesh = new THREE.Mesh(geo, meshM);
    scene.add(mesh);

    camera.position.set(5, 5, 5);
    camera.lookAt(new THREE.Vector3(0,0,0));

    document.getElementById("container").appendChild(renderer.domElement);

    function run() {
        renderer.render(scene, camera);
        requestAnimationFrame(run);
    }

    run();
</script>
</html>

threejs - 1 - 介紹&入門
threejs - 2 - 相機(jī)
threejs - 3 - 場景刷新
threejs - 4 - 物體
[threejs - 5 - 材質(zhì)]
[threejs - 6 - 燈光]
[threejs - 7 - 相機(jī)進(jìn)階]
[threejs - 8 - 物體進(jìn)階]
[threejs - 9 - 粒子系統(tǒng)]
[threejs - 10 - 模型加載]
[threejs - 11 - GLSL]
[threejs - 12 - 著色器]

End.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市确憨,隨后出現(xiàn)的幾起案子译荞,更是在濱河造成了極大的恐慌瓤的,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吞歼,死亡現(xiàn)場離奇詭異圈膏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)篙骡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門稽坤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人糯俗,你說我怎么就攤上這事尿褪。” “怎么了得湘?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵杖玲,是天一觀的道長。 經(jīng)常有香客問我淘正,道長摆马,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任跪帝,我火速辦了婚禮今膊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伞剑。我一直安慰自己斑唬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布黎泣。 她就那樣靜靜地躺著恕刘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抒倚。 梳的紋絲不亂的頭發(fā)上褐着,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機(jī)與錄音托呕,去河邊找鬼含蓉。 笑死,一個胖子當(dāng)著我的面吹牛项郊,可吹牛的內(nèi)容都是我干的馅扣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼着降,長吁一口氣:“原來是場噩夢啊……” “哼差油!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起任洞,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蓄喇,失蹤者是張志新(化名)和其女友劉穎发侵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妆偏,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刃鳄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了楼眷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铲汪。...
    茶點(diǎn)故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖罐柳,靈堂內(nèi)的尸體忽然破棺而出掌腰,到底是詐尸還是另有隱情,我是刑警寧澤张吉,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布齿梁,位于F島的核電站,受9級特大地震影響肮蛹,放射性物質(zhì)發(fā)生泄漏勺择。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一伦忠、第九天 我趴在偏房一處隱蔽的房頂上張望省核。 院中可真熱鬧,春花似錦昆码、人聲如沸气忠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旧噪。三九已至,卻和暖如春脓匿,著一層夾襖步出監(jiān)牢的瞬間淘钟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工陪毡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留米母,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓毡琉,卻偏偏與公主長得像爱咬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子绊起,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評論 2 356