본문 바로가기
Shader CG

04. RayMarching - Rotation

by SimonLee 2024. 8. 4.

 

오늘은 도형을 몇가지 추가하고 도형의 움직임의 대해서 알아본다.

아래 참조 사이트에 들어가면 SDF 함수로 도형의 코드가 잘 나와있다.

 

구 렌더링에 이어서 사각형 렌더링의 함수는 sdBox 이다.

오리지널 사각형 렌더링 코드에서 offset 파라메터와, color 파라메터만 추가했다.

 

사각형의 sdBox 코드를 구현했으면, sdBox를 sdScene에 적용해보자.

여러 개의 도형의 거리를 구해서 그중 가장 가까운 픽셀의 색과 거리를 리턴하는 함수 closer() 부분을 잘 보면된다.

 

회전 함수는 회전 행렬을 구해서 정점과 곱해주면 된다.

Move, Roatation, Scale 3가지가 있지만 여기서는 회전 행렬만 구한다.

회전 행렬은 잘 나와있으니, 다른 사이트에서도 참고하면 된다.

 

 

회전 행렬 >

// Rotation matrix around the X axis.
mat3 rotateX(float theta) {
    float c = cos(theta);
    float s = sin(theta);
    return mat3(
        vec3(1, 0, 0),
        vec3(0, c, -s),
        vec3(0, s, c)
    );
}

// Rotation matrix around the Y axis.
mat3 rotateY(float theta) {
    float c = cos(theta);
    float s = sin(theta);
    return mat3(
        vec3(c, 0, s),
        vec3(0, 1, 0),
        vec3(-s, 0, c)
    );
}

// Rotation matrix around the Z axis.
mat3 rotateZ(float theta) {
    float c = cos(theta);
    float s = sin(theta);
    return mat3(
        vec3(c, -s, 0),
        vec3(s, c, 0),
        vec3(0, 0, 1)
    );
}

 

회전 행렬을 구했다면,

각 도형 생성하는 함수에서 거리를 구하기 전 정점에 회전 행렬을 곱해주면 된다.

 

회전 행렬 곱하기 전, 좌표에 offset을 더하면 물체의 초기 위치를 설정한다.

회전 행렬 곱하기 후, 좌표에 offset을 더하면, 회전 축으로 설정 되어 축 기준 회전을 한다.

 

전체 코드 >> 

좌측 구의  회전 축을 x + offset 만큼 두고 y 축 회전을 하고

우측 직사각육면체의 회전 축을 물체의 중심으로 두고 y 축 회전을 한다.

둘 차이를 보자.

 

#define EPSILON 0.0001
#define STEP 255
#define START_DEPTH 0.
#define END_DEPTH 100.

#define BACKGROUND_COLOR vec3(0.15, 0.1, 0.1)
#define SPHERE_COLOR vec3(1., 0.5, 0)

struct Surface {
    float dist;
    vec3 color;
};

// Rotation matrix around the X axis.
mat3 rotateX(float theta) {
    float c = cos(theta);
    float s = sin(theta);
    return mat3(
        vec3(1, 0, 0),
        vec3(0, c, -s),
        vec3(0, s, c)
    );
}

// Rotation matrix around the Y axis.
mat3 rotateY(float theta) {
    float c = cos(theta);
    float s = sin(theta);
    return mat3(
        vec3(c, 0, s),
        vec3(0, 1, 0),
        vec3(-s, 0, c)
    );
}

// Rotation matrix around the Z axis.
mat3 rotateZ(float theta) {
    float c = cos(theta);
    float s = sin(theta);
    return mat3(
        vec3(c, -s, 0),
        vec3(s, c, 0),
        vec3(0, 0, 1)
    );
}

// Identity matrix.
mat3 identity() {
    return mat3(
        vec3(1, 0, 0),
        vec3(0, 1, 0),
        vec3(0, 0, 1)
    );
}

Surface closer(Surface a, Surface b) {
    if (a.dist < b.dist) return a;
    return b;
}

Surface sdSphere(vec3 p, float r, vec3 offset, vec3 color) {
    Surface s;
    p = (p - offset) * rotateY(iTime) + offset;
    s.dist = length(p) - r;
    s.color = color;
    return s;
}

Surface sdBox( vec3 p, vec3 b, vec3 offset, vec3 color)
{
    Surface s;
    p = (p - offset) * rotateY(iTime);
    vec3 q = abs(p) - b;
    s.dist = length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
    s.color = color;
    return s;
}

Surface sdFloor(vec3 p) {
    Surface s;
    s.dist = length(vec3(0., p.y + 1.2, 0)); //s.dist = p.y + 1.;
    s.color = vec3(1. + 0.7 * mod(floor(p.x) + floor(p.z), 2.));
    return s;
}

Surface sdScene(vec3 p) {
    Surface sphereA = sdSphere(p, 1., vec3(-2, 0, 0), SPHERE_COLOR);
    Surface box = sdBox(p, vec3(1.), vec3(2,0,0), vec3(0.4,0.5,1.));
 
    Surface floor = sdFloor(p);
    
    Surface s = closer(sphereA, floor);
    s = closer(s, box);
    return s;
}

vec3 calcNormal(in vec3 p) {
    vec2 e = vec2(1.0, -1.0) * 0.0005; // epsilon
    return normalize(
      e.xyy * sdScene(p + e.xyy).dist +
      e.yyx * sdScene(p + e.yyx).dist +
      e.yxy * sdScene(p + e.yxy).dist +
      e.xxx * sdScene(p + e.xxx).dist);
}

Surface rayMarch(float s, float e, vec3 ro, vec3 rd) {
    float dist = s;
    Surface last;
    
    for (int i=0; i<STEP; i++) {
        vec3 p = ro + rd * dist;
        last = sdScene(p);
        dist += last.dist;
        if (dist < EPSILON || dist > e) break;
    }
    
    last.dist = dist;
    return last;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    vec3 col = BACKGROUND_COLOR;
    vec3 ro = vec3(0, 0, 5);
    vec3 rd = normalize(vec3(uv, -1));
    vec3 lightPos = vec3(0, 20, 0);

    Surface surface = rayMarch(START_DEPTH, END_DEPTH, ro, rd);
    
    if (surface.dist < END_DEPTH) {
        vec3 p = ro + rd * surface.dist;
        vec3 lightDi = normalize(lightPos - p);
        vec3 normal = calcNormal(p);
        float diffuse = clamp(dot(lightDi, normal), 0.3, 1.);
        col = (diffuse * surface.color * 0.7) + (0.3 * BACKGROUND_COLOR);
    }
    fragColor = vec4(col,1.0);
}

 

 

Reference

https://iquilezles.org/articles/distfunctions/

 

Inigo Quilez

Articles on computer graphics, math and art

iquilezles.org

https://inspirnathan.com/posts/54-shadertoy-tutorial-part-8

 

 

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

06. RayMarching - 퐁 라이팅 모델  (0) 2024.08.08
05. RayMarching - Camera move  (0) 2024.08.05
03. RayMarhcing - Rendering Many Object  (0) 2024.08.02
02. RayMarhcing - Shading Sphere  (0) 2024.08.01
01. RayMarhcing - Rendering Sphere  (0) 2024.07.31