이전 챕터에서 다룬 Rotation 을 사용하여 카메라의 원점을 이동해보고
방향을 회전 시켜보자.
카메라 원점을 값을 변경해보자.
계속 증가하는 iTime(시간)을 sin, cos 함수에 넣고 각각 x, y에 넣게 되면 ,
원을 그리면서 카메라가 이동을 하게 한다.
mouse x, y 좌표를 -0.5 ~ 0.5로 remap 한 뒤,
그 값을 rotation 공식에 theta를 넣어 회전 행렬을 만들자.
회전 행렬을 vec3 rd에 곱해주게 되면
카메라 광선 방향이 마우스의 좌표에 따라 회전을 하게 된다.
x의 값은 y 회전할 때 사용하게 하고, y 값은 x 회전할때 사용하게 한다.
아래 그림처럼 y 회전은 Yaw, x 회전은 Pitch로 정의 된다.
전체 코드 >
struct Surface {
float d;
vec3 col;
int id;
};
// 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 sdSphere(vec3 p, float r, vec3 offset, vec3 col, int id)
{
Surface s;
p -= offset;
s.d = length(p) - r;
s.col = col;
s.id = id;
return s;
}
Surface sdBox(vec3 p, vec3 b, vec3 offset, vec3 color, int id)
{
Surface s;
p -= offset;
vec3 q = abs(p) - b;
s.d = length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
s.col = color;
s.id = id;
return s;
}
Surface sdFloor(vec3 p, vec3 color, int id) {
Surface s;
s.d = length(vec3(0, p.y + 1., 0));
s.col = vec3(.5 + mod(floor(p.x) + floor(p.z), 2.) * 0.7);
s.id = id;
return s;
}
Surface merge(Surface a, Surface b) {
if (a.id == 0) return b;
if (b.id == 0) return a;
if (a.d < b.d) return a;
return b;
}
Surface sdScene(vec3 p) {
Surface box = sdBox(p, vec3(1.), vec3(-2,0,0), vec3(0.4,0.5,1.), 1);
Surface floor = sdFloor(p, vec3(0), -1);
Surface sphere = sdSphere(p, 1., vec3(2, 0, 0), vec3(1,0,0), 1);
Surface rst;
rst = merge(rst, floor);
rst = merge(rst, box);
rst = merge(rst, sphere);
return rst;
}
Surface rayMarch(float start, float end, vec3 ro, vec3 rd) {
float dist = start;
Surface s;
for (int i=0; i<255; i++) {
vec3 p = ro + rd * dist;
s = sdScene(p);
dist += s.d;
if (dist < 0.001 || dist > end) break;
}
s.d = dist;
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).d +
e.yyx * sdScene(p + e.yyx).d +
e.yxy * sdScene(p + e.yxy).d +
e.xxx * sdScene(p + e.xxx).d);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
vec2 mouse = iMouse.xy / iResolution.xy - 0.5;
vec3 background = vec3(0.2);
vec3 col = background;
const float PI = 3.141592;
vec3 ro = vec3(sin(iTime), cos(iTime)+ 3., 5);
vec3 lightPos = vec3(0, 10, 0);
vec3 rd = normalize(vec3(uv, -1));
mat3 yrot = rotateY(-mouse.x);
mat3 xrot = rotateX(mouse.y);
rd *= xrot * yrot;
float start = 0.; float end = 100.;
Surface s = rayMarch(start, end, ro, rd);
if (s.d < 100.) {
if (s.id > 0) {
vec3 p = ro + rd * s.d;
vec3 normal = calcNormal(p);
vec3 lightDi = normalize(lightPos - p);
float diffuse = clamp(dot(normal, lightDi), 0.3, 1.);
col = s.col * diffuse * 0.7 + background * 0.2;
}
else {
col = s.col;
}
}
fragColor = vec4(col,1.0);
}
Reference
https://inspirnathan.com/posts/55-shadertoy-tutorial-part-9
'Shader CG' 카테고리의 다른 글
07. RayMarching - Frenel effect (0) | 2024.08.10 |
---|---|
06. RayMarching - 퐁 라이팅 모델 (0) | 2024.08.08 |
04. RayMarching - Rotation (0) | 2024.08.04 |
03. RayMarhcing - Rendering Many Object (0) | 2024.08.02 |
02. RayMarhcing - Shading Sphere (0) | 2024.08.01 |