본문 바로가기
Shader CG

01. RayMarhcing - Rendering Sphere

by SimonLee 2024. 7. 31.

ray marching 생성한 구

위 그림은 2차원이 아닙니다. ^ ~ ^  3차원임

 

vec2 uv = ( fragCoord - 0.5 * iResolution.xy ) / iResolution.y;

fragCoord 값은 해상도 값 기준 좌표이다.  ( 0 < x , y < 1920 )

화면 중심이 원점이고 가로 세로 종횡비를 맞춰주는 코드를 먼저 적용한다.

 

RayMarhcing 기법으로 스피어를 렌더링 한다.

RayMarching 에 대해서 모르시면 아래 Reference를 참고하자.

RayMarching 특징은

1) 각 픽셀마다 ray를 생성해서 해당 ray의 길이를 줄이거나 늘려서 렌더링 할 물체의 표면의 위치를 찾는 것이다.

2) 카메라가 보이지 않는 부분은 그리지 않는다. 

 

카메라 좌표 = ro, 픽셀의 광선 = rd

vec3 rd = normalize(vec3(uv, -1)); // ray direction

이 부분이 가장 핵심인데, 아래 코드의 의미를 정확하게 알아야 한다.

원점에서 모든 uv 좌표로 뻗어나가는 ray 벡터이다. 

 

이 파란색 ray가 원점 중심이니 ro를 더하게 되면,

카메라 렌즈 위치에서 물체쪽으로 뻗어나가는 ray 가 완성된다 .!!

ray를 카메라 광선이라 칭한다.

< 좌표계 x = 좌/우, y = 상/하, z = 앞/뒤 >

 

카메라 광선은 depth 만큼 각 스텝마다 증가 또는 감소하게 된다.

이 부분이 처음에 이해하기 어려운데 아래 내용을 생각해보면서 직접 그리면서 이해해야 한다.

 

카메라 좌표는 z = 5 에 있다.

물체의 중심은 원점에 (z = 0) 있다.

 

카메라 좌표에서 각 픽셀 마다 각 픽셀의 광선방향으로 적당히 증가시켜 해당 지점을 점으로 찍어보자.

해당 지점과 원점과의 거리를 계산해보면 픽셀마다 거리가 다르다는 것을 이해해야 한다.

 

해당 지점과 원점과의 거리에서 원의 반지름을 빼주게 되면,

값이 0이면, 구해진 픽셀이 원의 표면이라는 것을 이해를 해야한다.

 

sdSphere() 의 리턴 값

- depth == 0 물체의 표면을 찾은 경우, 광선 확산 중단.

- depth < 0 물체에 닿지 않는 경우, 광선 확산 계속 진행.
- depth > 100 물체가 카메라 뷰에 없는 경우, 광선 확산 중단.

 

float d = sdSphere(p, 1.);

depth += d;

뎁스에 카메라와 계산된 좌표의 거리를 증감 해나간다.

광선이 표면에 닿게 되면 d 값이 0과 근접하게 나오기 때문에 확산을 할필요가 없다.

d값이 앱실론 값보다 작게 되면 확산을 중단하자.

 

픽셀 ray의 물체가 닿지 않는 곳이라면 d 값이 계속 커져서 MAX_DIST를 넘게 된다.

이때는 ray marching을 중단시켜 주면 된다. ^^  

const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;

float sdSphere(vec3 p, float r )
{
  return length(p) - r;
}

float rayMarch(vec3 ro, vec3 rd, float start, float end) {
  float depth = start;

  for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
    vec3 p = ro + depth * rd;
    float d = sdSphere(p, 1.);
    depth += d;
    if (d < PRECISION || depth > end) break;
  }

  return depth;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;

  vec3 col = vec3(0);
  vec3 ro = vec3(0, 0, 5); // ray origin that represents camera position
  vec3 rd = normalize(vec3(uv, -1)); // ray direction

  float d = rayMarch(ro, rd, MIN_DIST, MAX_DIST); // distance to sphere

  if (d > MAX_DIST) {
    col = vec3(0.6); // ray didn't hit anything
  } else {
    col = vec3(0, 0, 1); // ray hit something
  }

  // Output to screen
  fragColor = vec4(col, 1.0);
}

'Shader CG' 카테고리의 다른 글

03. RayMarhcing - Rendering Many Object  (0) 2024.08.02
02. RayMarhcing - Shading Sphere  (0) 2024.08.01
3D Scenes With Ray Marching  (0) 2024.06.27
2.7 Noise - 영혼이 빠져나감  (0) 2023.08.28
2.6 나이테 Noise  (0) 2023.08.19