본문 바로가기

WebGL

WebGL Fundamentals > Using 2 or More Textures

https://webglfundamentals.org/webgl/lessons/webgl-2-textures.html

 

WebGL Using 2 or More Textures

How to use 2 or more textures in WebGL

webglfundamentals.org

https://github.com/Myoungmin/WebGL_Fundamentals

 

GitHub - Myoungmin/WebGL_Fundamentals: WebGL 학습 프로젝트

WebGL 학습 프로젝트. Contribute to Myoungmin/WebGL_Fundamentals development by creating an account on GitHub.

github.com

 

 

Using 2 or More Textures

URL 배열을 로드하고 이미지 배열을 생성하는 함수를 구성하여 2개의 이미지를 로딩할 수 있도록 설정한다.

function loadImages(urls, callback) {
  var images = [];
  var imagesToLoad = urls.length;
 
  // 이미지 로딩이 끝날 때마다 호출
  var onImageLoad = function() {
    --imagesToLoad;
    // 모든 이미지가 로드되면 콜백 호출
    if (imagesToLoad == 0) {
      callback(images);
    }
  };
 
  for (var ii = 0; ii < imagesToLoad; ++ii) {
    var image = loadImage(urls[ii], onImageLoad);
    images.push(image);
  }
}

2개의 텍스처를 사용하도록 셰이더를 수정

<script id="fragment-shader-2d" type="x-shader/x-fragment">
precision mediump float;
 
// 텍스처
uniform sampler2D u_image0;
uniform sampler2D u_image1;
 
// 정점 셰이더에서 전달된 텍스처 좌표
varying vec2 v_texCoord;
 
void main() {
   vec4 color0 = texture2D(u_image0, v_texCoord);
   vec4 color1 = texture2D(u_image1, v_texCoord);
   gl_FragColor = color0 * color1;
}
</script>

2개의 WebGL 텍스처 객체를 생성

  // 2개의 텍스처 생성
  var textures = [];
  for (var ii = 0; ii < 2; ++ii) {
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
 
    // 어떤 크기의 이미지도 렌더할 수 있도록 매개변수 설정
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
 
    // 텍스처에 이미지 업로드
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, images[ii]);
 
    // 텍스처 배열에 텍스처 추가
    textures.push(texture);
  }

각 샘플러에서 사용할 텍스처 유닛을 셰이더에 알려준다.

텍스처 유닛이란 텍스처에 대한 레퍼런스 배열이다.

 

  // 샘플러 위치 탐색
  var u_image0Location = gl.getUniformLocation(program, "u_image0");
  var u_image1Location = gl.getUniformLocation(program, "u_image1");
 
  //...
 
  // 함께 렌더링할 텍스처 유닛 설정
  gl.uniform1i(u_image0Location, 0);  // 텍스처 유닛 0
  gl.uniform1i(u_image1Location, 1);  // 텍스처 유닛 1

텍스처를 각각의 텍스처 유닛에 할당

  // 특정 텍스처를 사용하도록 각각의 텍스처 유닛 설정
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, textures[0]);
  gl.activeTexture(gl.TEXTURE1);
  gl.bindTexture(gl.TEXTURE_2D, textures[1]);

 

 

텍스처 유닛

모든 텍스처 함수는 "활성 텍스처 유닛"에서 작동한다.

"활성 텍스처 유닛"은 작업하려는 텍스처 유닛의 전역 변수이다.

각 텍스처 유닛은 TEXTURE_2D, TEXTURE_CUBE_MAP  2가지 대상을 가진다. 

모든 텍스처 함수는 현재 활성 텍스처 유닛에서 지정된 대상과 함께 작동한다.

 

자바스크립트로 WebGL을 구현한다면 다음과 같을 것이다.

 

var getContext = function() {
  var textureUnits = [
    { TEXTURE_2D: ??, TEXTURE_CUBE_MAP: ?? },
    { TEXTURE_2D: ??, TEXTURE_CUBE_MAP: ?? },
    { TEXTURE_2D: ??, TEXTURE_CUBE_MAP: ?? },
    { TEXTURE_2D: ??, TEXTURE_CUBE_MAP: ?? },
    { TEXTURE_2D: ??, TEXTURE_CUBE_MAP: ?? },
    //...
  ];
  var activeTextureUnit = 0;
 
  var activeTexture = function(unit) {
    // "unit enum"을 인덱스로 변환
    var index = unit - gl.TEXTURE0;
    // 활성 텍스처 유닛 설정
    activeTextureUnit = index;
  };
 
  var bindTexture = function(target, texture) {
    // 활성 텍스처 유닛의 대상에 대한 텍스처 설정
    textureUnits[activeTextureUnit][target] = texture;
  };
 
  var texImage2D = function(target, ... args ...) {
    // 활성 텍스처 유닛의 현재 텍스처에서 texImage2D 호출
    var texture = textureUnits[activeTextureUnit][target];
    texture.image2D(...args...);
  };
 
  // WebGL API 반환
  return {
    activeTexture: activeTexture,
    bindTexture: bindTexture,
    texImage2D: texImage2D,
  }
};

셰이더는 인덱스를 텍스처 유닛으로 가져온다.

 gl.uniform1i(u_image0Location, 0);  // 텍스처 유닛 0
 gl.uniform1i(u_image1Location, 1);  // 텍스처 유닛 1

한 가지 유의해야할 점은, 유니폼을 사용할 때 텍스처 유닛에 대한 인덱스를 사용하지만, gl.activeTexture를 호출할 때는 특수 상수 gl.TEXTURE0, gl.TEXTURE1 등을 전달해야 한다.

  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, textures[0]);
  gl.activeTexture(gl.TEXTURE1);
  gl.bindTexture(gl.TEXTURE_2D, textures[1]);

아래와 같이 1을 증가시켜 전달할 수도 있다.

  gl.activeTexture(gl.TEXTURE0 + 0);
  gl.bindTexture(gl.TEXTURE_2D, textures[0]);
  gl.activeTexture(gl.TEXTURE0 + 1);
  gl.bindTexture(gl.TEXTURE_2D, textures[1]);

반복문을 사용할 수도 있다.

for (var ii = 0; ii < 2; ++ii) {
    gl.activeTexture(gl.TEXTURE0 + ii);
    gl.bindTexture(gl.TEXTURE_2D, textures[ii]);
}

 

 

 

 

 

 

https://myoungmin.github.io/WebGL_Fundamentals/

 

WebGL_Fundamentals

WebGL이란? WebGL은 Web Graphics Library의 약자로 웹상에서 2D 및 3D 그래픽을 렌더링하기 위한 로우 레벨 Javascript API. 학습내용 블로그 정리

myoungmin.github.io

 

'WebGL' 카테고리의 다른 글

WebGL Fundamentals > Rendering to a Texture  (0) 2022.07.08
WebGL Fundamentals > Cross Origin Images  (0) 2022.07.08
WebGL Fundamentals > Data Textures  (0) 2022.07.08
WebGL Fundamentals > WebGL Textures  (0) 2022.07.07
WebGL Fundamentals > Scene Graph  (0) 2022.07.06