ThreeJS(WebGL)如何使用UV座標貼圖,實現UV旋轉偏移?

ThreeJS是WebGL的一種前端框架,UV座標的原理是一樣的。

前置知識

WebGL紋理

如果對WebGL有興趣,可以去看WebGL貼材質這篇文章簡單瞭解下。

紋理座標系統

uv其實就是紋理座標,因爲xyz已經被頂點座標佔用了,所以uvw就用來表示紋理座標。它時候貼圖影射到模型表面的依據,把表面的點與平面上的像素對應起來,一般取值在0~1;
u:圖片在顯示器水平的座標
v:垂直方向
w:垂直於顯示器表面
一般情況只是在表面貼圖,就涉及不到w,所以常稱爲uv。

ThreeJS紋理貼圖

使用紋理對象貼圖

ThreeJS本身做了封裝,貼圖十分方便,如果大家英文好可以直接去官網,嫌麻煩也可以在中文網站上直接查看教程或對象方法。(⚠️以下非完整代碼)

    const w=h=64,textureW=textureH=64;
    var geometry = new THREE.PlaneBufferGeometry(w, h); //矩形平面
    // TextureLoader創建一個紋理加載器對象,可以加載圖片作爲幾何體紋理
    var textureLoader = new THREE.TextureLoader();
    // 執行load方法,加載紋理貼圖成功後,返回一個紋理對象Texture
    textureLoader.load('./p.jpg', function (texture) {
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      // texture.repeat.set(2, 2);
      var material = new THREE.MeshLambertMaterial({
        map: texture, //設置顏色貼圖屬性值
      }); //材質對象Material
    var mesh = new THREE.Mesh(geometry, material); //網格模型對象Mesh
    scene.add(mesh); //網格模型添加到場景中

    //紋理貼圖加載成功後,調用渲染函數執行渲染操作
    render();

紋理對象Texture本身是有UV旋轉偏移方法的,但是如果調整紋理UV,用本身自帶方法就需要頻繁重新貼圖。
在這裏插入圖片描述

UV座標與頂點座標的關係

原始貼圖是這樣:
在這裏插入圖片描述

它的紋理座標和頂點座標對應情況,它們是一一對應的,大概是這個樣子
在這裏插入圖片描述
如果按上圖所說,修改UV座標就會變成這樣:
在這裏插入圖片描述

UV旋轉偏移

我們明白UV座標是怎麼回事,就可以開始旋轉、偏移了。

  1. 通過旋轉和偏移的值構建一個矩陣,如果矩陣知識還不熟悉,可以看這篇文章複習下,我是用ThreeJS自帶的矩陣庫,因爲它只有三維和四維的,所以我把uv座標寫成了三維,即齊次座標;
  2. 通過取得BufferGeometry的頂點座標,再去計算原始的UV座標。不過要注意的只有是或繼承BufferGeometry的對象才能取得uv、position信息;
  3. 最後通過矩陣轉換每一點UV座標,設置爲BufferGeometry的UV。
      //geometry可以通過mesh對象取得,pos是保存頂點座標的數組
      let pos = geometry.getAttribute("position").array;

      
      let uv = [];
      const startP = [pos[0],pos[1]];
      //UV偏移不能太大,一般在0到1之間
      const offsetU = 0.05,offsetV = 0.02,rotation = Math.PI/4;
      let m = new THREE.Matrix3();
      m.setUvTransform( -offsetU, -offsetV, 1, 1, rotation, 0, 0 );
      
      //取得正常情況下的UV座標
      for (let index = 0; index*3 < pos.length; index++) {
        if(index === 0) uv.push(...[0,0,1]);
        else{
          const currentP = [pos[index*3],pos[index*3+1]]
          uv.push(...[Math.abs((currentP[0]-startP[0])/w),Math.abs((currentP[1]-startP[1])/h),1]);
        }
      }

      let uvAttr = new THREE.BufferAttribute(new Float32Array(uv) , 3) ;
      uvAttr = m.applyToBufferAttribute (uvAttr);
      geometry.attributes.uv = uvAttr;

就這麼簡單的代碼就可以實現UV旋轉偏移,但是我們一般會把它封裝成函數,通過頁面上的Input調整offsetU, offsetV,rotation的值。上面幾行的代碼,效果就是這樣啦:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章