Threejs, 紋理是怎么映射到模型上的

下面代碼是通過 threejs ,繪制一個地球的程序。

  // 加載紋理
  const autumnTexture = new TextureLoader().load(autumn)
  // 渲染器
  const renderer = new WebGL1Renderer({ canvas })
  // 透視投影相機
  const camera = new PerspectiveCamera(60, canvas.width / canvas.height, 1, 2000)
  camera.position.set(
    settings.cameraX,
    settings.cameraY,
    7
  );
  camera.lookAt(0, 0, 0)
  
  camera.updateMatrixWorld();
  // 場景
  const scene = new Scene()
  {
    // 光源
    const color = 0xffffff
    const intensity = 1
    const light = new DirectionalLight(color, intensity)
    light.position.set(-1, 2, 4)

    const ambient = new AmbientLight(0xffffff, 0.2);
    scene.add(ambient)
    scene.add(light)
  }

  // 球
  const sphereGeometry = new SphereGeometry(1.5, 64, 32)
  // 材質
  const material = new MeshBasicMaterial({
    map: autumnTexture
  })
  const mesh = new Mesh(sphereGeometry, material);

  mesh.position.set(2, 3, 4);
  scene.add(mesh)
   renderer.render(scene, camera)
image.png

執(zhí)行上面的代碼,就會在畫布上生成一個地球?,F(xiàn)在我們就來分析下threejs 是怎么一步一步將地球紋理影射到球體上的。

當程序運行執(zhí)行 WebGLRender 的 render 函數(shù),首先我們就以渲染場景的 球為例,會根據(jù)球體配置的 材質去生成一個 WebGLProgram 對象,并根據(jù)傳入Mesh 的材質去內置材質中獲取相應的 著色器代碼(排除 ShaderMaterial 等自定義材質),根據(jù)材質設置相應的著色器變量。
當成功編譯并創(chuàng)建了 WebGLProgram 對象后,就會通過程序對象生成一個 WebGLUniform 對象,通過WebGLUniform 的構造函數(shù)可以知道,通過訪問當前程序對象的激活的uniforms 變量,獲取所有可訪問的 uniform, 并通過 parseUniform 方法生成相應的 unifrom 的setter 函數(shù)。(WebGLUniform 對象有一個seq 變量,存儲的是當前函數(shù)對象的所有SingleUniform or PureArrayUniform 的實例數(shù)組)

  class WebGLUniform {
    constructor( gl, program ) {

        this.seq = [];
        this.map = {};

        const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );

        for ( let i = 0; i < n; ++ i ) {

            const info = gl.getActiveUniform( program, i ),
                addr = gl.getUniformLocation( program, info.name );

            parseUniform( info, addr, this );

        }

    }
}

當執(zhí)行 WebGLRender 的setProgram 方法,會調用 WebGLUniform 的upload 方法將所有的uniforms 變量寫入著色器,至此所有 的準備功能完成。
在upload 方法中會根據(jù)相應 的setter 寫入?yún)?shù)。

由于我們這里討論的是threejs 怎么將紋理映射上模型的,所以我們重點關注的是紋理的寫入。
當threejs 在上一步生成紋理寫入函數(shù) setValueT1

// case 0x8b5e: // SAMPLER_2D
// case 0x8d66: // SAMPLER_EXTERNAL_OES
// case 0x8dca: // INT_SAMPLER_2D
// case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
// case 0x8b62: // SAMPLER_2D_SHADOW
// return setValueT1;
// Single texture (2D / Cube)

// 執(zhí)行這個setValueT1 函數(shù)會 執(zhí)行WebGLTexture 對象的 setTexture2D 方法,將紋理 單元綁定到當前程序對象上()
// state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
function setValueT1( gl, v, textures ) {

    const cache = this.cache;
    const unit = textures.allocateTextureUnit();

    if ( cache[ 0 ] !== unit ) {

        gl.uniform1i( this.addr, unit );
        cache[ 0 ] = unit;

    }

    textures.setTexture2D( v || emptyTexture, unit );

}

當?shù)谝淮螆?zhí)行著色器渲染紋理 ,WebGLTexture 中 uploadTexture 會將配置在texture 中的數(shù)據(jù)調用 state.texImage2D 方法(等價執(zhí)行gl.textImage2D方法),將數(shù)據(jù)寫入相應 的紋理單元。至此所有紋理配置結束。正式進入場景的渲染,調用 gl.drawArray or gl.drawElement 方法執(zhí)行著色器。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容