본문 바로가기
Shader CG

09. RayMarching - SD Operation

by SimonLee 2024. 8. 12.

도형들의 여러가지 연산 방법들의 대해서 정의 한다.

 

필요할때 마다 찾아서 사용하면 좋을 듯 하다

 

1) 도형 1, 도형 2를 합쳐서 출력.

float opUnion(float d1, float d2) {
  return min(d1, d2);
}

 

2) 도형 1, 도형 2를 부드럽게 합쳐서 출력.

float opSmoothUnion(float d1, float d2, float k) {
  float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
  return mix( d2, d1, h ) - k*h*(1.0-h);
}

 

3) 도형 1, 도형 2의 공통 부분만 출력

float opIntersection(float d1, float d2) {
  return max(d1, d2);
}

 

4) 도형 1, 도형 2의 공통 부분을 부드럽게 출력

float opSmoothIntersection(float d1, float d2, float k) {
  float h = clamp( 0.5 - 0.5*(d2-d1)/k, 0.0, 1.0 );
  return mix( d2, d1, h ) + k*h*(1.0-h);
}

 

5) 도형 2 에서 도형 1 부분을 뺀 영역을 출력

float opSubtraction(float d1, float d2) {
  return max(-d1, d2);
}

 

6) 도형 2에서 도형 1부분을 뺀 영역을 부드럽게 출력

float opSmoothSubtraction(float d1, float d2, float k) {
  float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );
  return mix( d2, -d1, h ) + k*h*(1.0-h);
}

 

7) 도형 1에서 도형 2을 뺀 영역을 출력

float opSubtraction2(float d1, float d2) {
  return max(d1, -d2);
}

 

8) 도형 1에서 도형 2를 뺀 영역을 부드럽게 출력

float opSmoothSubtraction2(float d1, float d2, float k) {
  float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );
  return mix( d1, -d2, h ) + k*h*(1.0-h);
}

 

9) +x, -x 값으로 대칭한 도형을 렌더링

float opSymX(vec3 p, float r, vec3 o)
{
  p.x = abs(p.x);
  return sdSphere(p, r, o);
}

 

10) +x, -x, +z, -z 값으로 대칭한 도형 여러개 렌더링

float opSymXZ(vec3 p, float r, vec3 o)
{
  p.xz = abs(p.xz);
  return sdSphere(p, r, o);
}

 

11) 도형을 c 간격으로 반복해서 출력

float opRep(vec3 p, float r, vec3 o, vec3 c)
{
  vec3 q = mod(p+0.5*c,c)-0.5*c;
  return sdSphere(q, r, o);
}

 

12) 도형을 반복해서 출력, c 는 도형 간격, l 은 반복하는 횟수

float opRepLim(vec3 p, float r, vec3 o, float c, vec3 l)
{
  vec3 q = p - c * clamp(round(p/c),-l,l);
  return sdSphere(q, r, o);
}

 

13) 도형의 외형을 변화

float opDisplace(vec3 p, float r, vec3 o)
{
  float d1 = sdSphere(p, r, o);
  float d2 = sin(p.x)*sin(p.y)*sin(p.z) * cos(iTime);
  return d1 + d2;
}

 

 

전체 코드 >

const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;
const float EPSILON = 0.0005;
const float PI = 3.14159265359;
const vec3 COLOR_BACKGROUND = vec3(.741, .675, .82);
const vec3 COLOR_AMBIENT = vec3(0.42, 0.20, 0.1);
float scene(vec3 p);

mat3 cameraTransform(vec3 cameraPos, vec3 lookat) {
  vec3 cd = normalize(lookat - cameraPos);
  vec3 cr = cross(vec3(0, 1, 0), cd);
  vec3 cu = cross(cd, cr);
  return mat3(-cr, cu, -cd);
}


mat2 rotate2d(float theta) {
  float s = sin(theta), c = cos(theta);
  return mat2(c, -s, s, c);
}

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

float opUnion(float d1, float d2) {
  return min(d1, d2);
}

float opSmoothUnion(float d1, float d2, float k) {
  float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
  return mix( d2, d1, h ) - k*h*(1.0-h);
}

float opIntersection(float d1, float d2) {
  return max(d1, d2);
}

float opSmoothIntersection(float d1, float d2, float k) {
  float h = clamp( 0.5 - 0.5*(d2-d1)/k, 0.0, 1.0 );
  return mix( d2, d1, h ) + k*h*(1.0-h);
}

float opSubtraction(float d1, float d2) {
  return max(-d1, d2);
}

float opSmoothSubtraction(float d1, float d2, float k) {
  float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );
  return mix( d2, -d1, h ) + k*h*(1.0-h);
}

float opSubtraction2(float d1, float d2) {
  return max(d1, -d2);
}

float opSmoothSubtraction2(float d1, float d2, float k) {
  float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );
  return mix( d1, -d2, h ) + k*h*(1.0-h);
}

float opSymX(vec3 p, float r, vec3 o)
{
  p.x = abs(p.x);
  return sdSphere(p, r, o);
}

float opSymXZ(vec3 p, float r, vec3 o)
{
  p.xz = abs(p.xz);
  return sdSphere(p, r, o);
}

float opRep(vec3 p, float r, vec3 o, vec3 c)
{
  vec3 q = mod(p+0.5*c,c)-0.5*c;
  return sdSphere(q, r, o);
}

float opRepLim(vec3 p, float r, vec3 o, float c, vec3 l)
{
  vec3 q = p - c * clamp(round(p/c),-l,l);
  return sdSphere(q, r, o);
}

float opDisplace(vec3 p, float r, vec3 o)
{
  float d1 = sdSphere(p, r, o);
  float d2 = sin(p.x)*sin(p.y)*sin(p.z) * cos(iTime);
  return d1 + d2;
}

float rayMarch(vec3 ro, vec3 rd) {
  float d = MIN_DIST;
  for (int i=0; i<MAX_MARCHING_STEPS; i++) {
    vec3 p = ro + rd * d;
    float depth = scene(p);
    d += depth;
    if (d < PRECISION || d > MAX_DIST) break;
  }
  return d;
}

vec3 calcNormal(vec3 p) {
  vec2 e = vec2(1, -1) * EPSILON;
  return normalize(
    e.xyy * scene(p + e.xyy) +
    e.yxy * scene(p + e.yxy) +
    e.yyx * scene(p + e.yyx) +
    e.xxx * scene(p + e.xxx));
}

float scene(vec3 p) {
  float d1 = sdSphere(p, 1., vec3(0, -1, 0));
  float d2 = sdSphere(p, 0.75, vec3(0, 1., 0));
  //return d1;
  //return d2;
  //return opUnion(d1, d2);
  //return opSmoothUnion(d1, d2, 0.2);
  //return opIntersection(d1, d2);
  //return opSmoothIntersection(d1, d2, 0.2);
  //return opSubtraction(d1, d2);
  //return opSmoothSubtraction(d1, d2, 0.2);
  //return opSubtraction2(d1, d2);
  //return opSmoothSubtraction2(d1, d2, 0.2);
  //return opSymX(p, 1., vec3(1, 0, 0));
  //return opSymXZ(p, 1., vec3(1, 0, 1));
  //return opRep(p, .6, vec3(0.), vec3(10));
  //return opRepLim(p, 0.5, vec3(0), 2., vec3(1., 0, 0));
  return opDisplace(p, 1., vec3(0));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = (fragCoord - 0.5*iResolution.xy)/iResolution.y;
  vec3 col = vec3(0);
  vec3 ro = vec3(0, 0.4, 5);
  vec3 lp = vec3(0);
  vec3 rd = normalize(vec3(uv, -1)) * cameraTransform(ro, lp);
  vec3 lightPos = vec3(0, 10., 0);
  
  float depth = rayMarch(ro, rd);
  
  if (depth < MAX_DIST) {
    vec3 p = ro + rd * depth;
    vec3 lightDirection = normalize(lightPos - p);
    vec3 normal = calcNormal(p);
    float diffuse = clamp(dot(normal, lightDirection), 0.3, 1.);
    
    float dif = clamp(dot(normal, lightDirection), 0., 1.) * 0.5 + 0.5;
    col = vec3(dif) + COLOR_AMBIENT;
  }
  else {
    col = COLOR_BACKGROUND;
  }
  
  fragColor = vec4(col,1.0);
  
}

 

 

Reference

https://inspirnathan.com/posts/60-shadertoy-tutorial-part-14

 

Shadertoy Tutorial Part 14 - SDF Operations

Learn how to draw complex shapes and scenes in Shadertoy!

inspirnathan.com

 

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

11. RayMarching - Snow man  (0) 2024.08.14
10. RayMarching - Cube map  (0) 2024.08.13
08. RayMarching - Shadow  (0) 2024.08.10
07. RayMarching - Frenel effect  (0) 2024.08.10
06. RayMarching - 퐁 라이팅 모델  (0) 2024.08.08