iT邦幫忙

0

如何用three.js繪製一個四面填充不同材質的正四面體?

  • 分享至 

  • xImage

這個問題我想了蠻久但還是想不太出來 = =
我一開始想的做法還蠻簡單,就是單純的用coneGeometry 去做出來一個正四面體

但是寫到最後才發覺 cone實際只有兩個面 = =... 所以沒辦法讓四個面填入不同的材質實例

有人知道要怎麼做嗎?

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
淺水員
iT邦大師 6 級 ‧ 2022-03-21 16:20:24
最佳解答

參考 BufferGeometry.groups

Split the geometry into groups, each of which will be rendered in a separate WebGL draw call. This allows an array of materials to be used with the bufferGeometry.

const geometry = new THREE.TetrahedronGeometry();
for (let i = 0; i < 4; ++i) {
    geometry.addGroup(
        i * 3, //start : Integer, 從第幾個點開始
        3,     //count : Integer, 每 3 個點為一組
        i      //materialIndex : Integer, 使用第幾個 material
    );
}

//材質
const materials = [
    new THREE.MeshPhysicalMaterial({ color: 0xff0000 }),
    new THREE.MeshPhysicalMaterial({ color: 0x00ff00 }),
    new THREE.MeshPhysicalMaterial({ color: 0x0000ff }),
    new THREE.MeshPhysicalMaterial({ color: 0xffff00 }),
];

// .Mesh 的第二個參數可以是陣列,geometry 需要用 addGroup 分群
const tetrahedron = new THREE.Mesh(geometry, materials);
scene.add(tetrahedron);
看更多先前的回應...收起先前的回應...
Mizok iT邦新手 3 級 ‧ 2022-03-25 19:39:28 檢舉

nice try :D

Mizok iT邦新手 3 級 ‧ 2022-03-25 19:43:21 檢舉

但我記得這樣做還是會有個問題, 就是材質會出現拉伸跟鏡射的狀況

Mizok iT邦新手 3 級 ‧ 2022-03-25 19:47:42 檢舉

主要是因為three.js 的tetra geo 的頂點似乎不止四個, 實際console geometry.attribute.position.array出來發現有出來發現座標有12 組, 也就是長度36 的陣列

(下列這行是錯誤的描述, 20220329更正)
如果單純的用for loop去 iterate, 會出現頂點抓錯的狀況

Mizok iT邦新手 3 級 ‧ 2022-03-25 19:48:59 檢舉
Mizok iT邦新手 3 級 ‧ 2022-03-28 01:33:44 檢舉

後來自己又嘗試了一下, 用內建的tetra, 需要自己再重新定義 uv array一次, 如果不重新定義uv, 那材質就會出現拉伸/鏡射的問題

Mizok iT邦新手 3 級 ‧ 2022-03-28 10:48:48 檢舉

我有把我自己定義tetra uv的作法寫在上面提到的stackoverflow 問題上面, 實際參考文獻可以看
https://www.twblogs.net/a/5eef515933cbe858769e6bd4

淺水員 iT邦大師 6 級 ‧ 2022-03-28 11:11:56 檢舉

謝謝提供那麼多資訊,我再看一下

淺水員 iT邦大師 6 級 ‧ 2022-03-29 17:14:02 檢舉

謝謝分享,我稍微整理一下:

  1. 關於 36 個數值的問題,是因為一個面有 3 個點,而每個點要有 3 數值(對應到 x,y,z),所以合計 4面 * 3(點/面) * 3(數值/點) = 36 個數值。
  2. 因為使用者貼圖時,想要的圖片的座標映射方式不同,所以直接照他預設的方式去貼,圖片會變形。解決方式是自己設定一下 uv 的值。
Mizok iT邦新手 3 級 ‧ 2022-03-29 19:37:51 檢舉

對, 我前面回的"會出現頂點抓錯的狀況"其實是寫錯了, 正確應該是頂點並沒有抓錯, 但是uv跟使用者預想的不一樣

Mizok iT邦新手 3 級 ‧ 2022-03-29 19:40:50 檢舉

我猜原因有可能是因為內建的Tetra 本身是從Cylinder(或什麼別的東西) 演化過來的

淺水員 iT邦大師 6 級 ‧ 2022-03-29 21:20:56 檢舉

我看了一下原始碼 TetrahedronGeometry 實際上是一個 PolyhedronGeometry

PolyhedronGeometry 預設的貼圖方式,可以想像成:

  1. 在 PolyhedronGeometry 外有一個大的球體
  2. Texture 類似世界地圖那樣貼到這個球體上(y軸為南北極,赤道在xz平面上)
  3. 當從原點往某頂點 P 作一條射線,會與球體相交於點 P',此時把 P 的 uv 設定為 P' 的uv。
Mizok iT邦新手 3 級 ‧ 2022-03-30 20:27:57 檢舉

感覺有點像極座標?

淺水員 iT邦大師 6 級 ‧ 2022-03-31 17:57:01 檢舉

大概是這樣
https://ithelp.ithome.com.tw/upload/images/20220331/20112943ZbyKWmBFGl.png

Mizok iT邦新手 3 級 ‧ 2022-04-05 18:07:44 檢舉

哦哦, 懂XD

0
jason71708
iT邦新手 3 級 ‧ 2022-03-22 10:35:02

我昨天看到這題也有興趣查了很久...

結果繪了個四不像的東西XD

https://ithelp.ithome.com.tw/upload/images/20220322/20123889cnEMVnTzv0.png

/*
* Add Object
*/

    const geometry = new THREE.TetrahedronGeometry(2, 0)
    const position = geometry.attributes.position.clone();
    const material = new THREE.MeshBasicMaterial({
      vertexColors: THREE.FaceColors,
    });
    const colors = [];
    const color = new THREE.Color();
    for ( let i = 0; i < position.count; i ++ ) {
      const z =  Math.random() * 0.2;
      position.setZ( i, z );
      const s = z * 5; // values  in the range [0,1]
      color.setHSL( s, s, s );
      colors.push( color.r, color.g, color.b );
    }
    geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
    const tetrahedron = new THREE.Mesh(geometry, material)
    scene.add(tetrahedron)

沒想到解法是像 淺水員 回答的這麼簡單/images/emoticon/emoticon01.gif

我要發表回答

立即登入回答