본문 바로가기

WebGL

WebGL Fundamentals > Spot Lighting

https://webglfundamentals.org/webgl/lessons/webgl-3d-lighting-spot.html

 

WebGL 3D - Spot Lighting

How to implement spot lights 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

 

 

WebGL : Spot Lighting

Point 조명은 한 지점에서 모든 방향으로 진행하는 빛을 가진다고 생각한다.

Point 조명에서 스포트라이트의 방향을 선택하여 일부만 비춘다고 생각하면 스포트라이트를 만들 수 있다.

 

스포트라이트를 만들기 위해서는 광원에서 스포트라이트의 방향을 선택한다.

스포트라이트의 방향을 만들고 나면, 

빛이 진행하는 모든 방향에 대해 해당 방향과 우리가 선택한 스포트라이트 방향의 스칼라곱을 구할 수 있다.

임의의 임계값을 정하고 해당 임계값 내에 있다면 빛나게 된다. 

해당 임계값 내에 없다면 빛나지 않는다.

 

 

 

스포트라이트의 방향인 direction, 스포트라이트가 비추는 제한 각도 limit를 설정한다.

임계값으로 dot limit를 계산하고, 임계값의 코사인을 구한다.

각 광선의 방향과 스포트라이트의 방향의 스칼라곱이 dot limit를 초과하면 조명을 비추는 영역으로 계산한다.

셰이더에서 조건문을 제거하기 위해 step이라 불리는 GLSL 함수 사용

2개의 값을 받는데 두 번째 값이 첫 번째 값보다 크거나 같으면 1.0을 반환하고, 그 외에는 0을 반환한다.

자바스크립트에서 작성한 모습

function step(a, b) {
   if (b >= a) {
       return 1;
   } else {
       return 0;
   }
}

스포트라이트의 경계자연스럽게 흐려지게 만들기

경계가 딱 끊어지지 않게 만들려면 1개 대신 2개의 임계값을 사용하고 그 사이를 1과 0사이로 보간하면 된다.

내부 임계값 안에 있다면 1을 사용하고, 외부 임계값 바깥에 있다면 0을 사용한다.

 

GLSL smoothstep 함수로 내부 임계값과 외부 임계값을 적용하면,

Hermite interpolation을 사용하여 0에서 1사이의 값을 반환한다.

lowerBound와 upperBound의 사이에서 오른쪽 이미지처럼 보간한다.

선형보간을 한다면 왼쪽 이미지와 같은 결과를 얻는다.

 

 

주의해야할 점은 u_innerLimit과 u_outerLimit이 같으면 limitRange는 0.0이 된다는 사실이다.

limitRange로 나누는 연산을 실행하는데 이 값이 0이 되면 정의되지 않은 동작을 야기하므로,

자바스크립트에서 u_innerLimit가 u_outerLimit와 같지 않다는 것을 확인해야한다.

내부 임계값과 외부 임계값 적용

  // Hermite interpolation을 사용하여 0에서 1사이의 값을 반환
  float inLight = smoothstep(u_outerLimit, u_innerLimit, dotFromDirection);

Fragment Shader에서 스포트라이트 적용하기

<!-- fragment shader -->
<script  id="fragment-shader-3d" type="x-shader/x-fragment">
precision mediump float;

// 정점 셰이더에서 전달된다.
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform vec4 u_color;
uniform float u_shininess;
uniform vec3 u_lightDirection;
uniform float u_innerLimit;          // in dot space
uniform float u_outerLimit;          // in dot space

void main() {
  // v_normal은 베링이기 때문에 보간되므로 단위 벡터가 아닙니다.
  // 정규화하면 다시 단위 벡터가 됩니다.
  vec3 normal = normalize(v_normal);

  vec3 surfaceToLightDirection = normalize(v_surfaceToLight);
  vec3 surfaceToViewDirection = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);

  float dotFromDirection = dot(surfaceToLightDirection,
                               -u_lightDirection);
  // 두 임계값을 적용하여 조명을 비추는 영역을 계산한다.
  // 스포트라이트 안에 있다면 "inLight"는 1이 되고 아니라면 0이 된다.
  // GLSL smoothstep 함수는 Hermite interpolation을 사용한다.
  float inLight = smoothstep(u_outerLimit, u_innerLimit, dotFromDirection);
  float light = inLight * dot(normal, surfaceToLightDirection);
  float specular = inLight * pow(dot(normal, halfVector), u_shininess);

  gl_FragColor = u_color;

  // 색상 부분(알파 제외)에만 광량 곱하기
  gl_FragColor.rgb *= light;

  // 반사율 더하기
  gl_FragColor.rgb += specular;
}
</script>

 

 

 

 

 

 

 

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

 

WebGL_Fundamentals

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

myoungmin.github.io