광선 행진 파트 2: DE 운영 및 CSG

17923 단어 graphicstutorial
레이 마칭에 대한 이전 게시물에서 레이 마칭이 무엇이며 GLSL에서 레이 마칭을 기본적으로 구현하는 방법에 대해 이야기했습니다. 아직 읽지 않았다면 코드를 재사용할 것이기 때문에 이 코드를 따라하기 전에 최소한 훑어보는 것이 좋습니다.




이 부분에서는 더 많은 거리 추정기와 이러한 거리 추정기를 조작하는 몇 가지 작업을 추가하고 DE를 더 복잡한 장면으로 결합하는 방법을 배웁니다.

더 이상 고민하지 않고 시작하겠습니다!

모양을 결합하는 방법을 배움으로써 간단하게 시작해 봅시다. 아시다시피 합집합, 차집합, 교집합의 3가지 기본 부울 연산이 있습니다.


하지만 이를 활용하려면 여러 개체를 추가하는 방법이 필요합니다. 이를 위해 하나 이상의 DE를 사용할 수 있는 장면 DE를 만들 수 있습니다. 먼저 우리는 그것에 대한 함수를 만듭니다. 지금은 구체만 있을 것입니다.

// IMPORTANT: In Shadertoy this MUST be put after both the DEs and the operators. idk if it's the same for normal OpenHL
float sceneDE(vec3 pos) {
    return sphereDE(pos, vec3(0,0,0), 1.0);
}

그런 다음 march() 함수에서 다음 줄을 찾습니다(다른 변수 이름을 사용했을 수 있음).

float _distance = sphereDE(current_pos, vec3(0.0), 1.0);
sceneDE()를 사용하도록 변경합니다.

float _distance = sceneDE(current_pos);

이제 부울 함수를 만들 준비가 되었습니다.

Union이 가장 간단하므로 시작하겠습니다. 새 함수opUnion를 만듭니다.

// a and b are interchangeable
float opUnion(float a, float b) {
    return min(a,b);
}

자세히 보면 이 기능은 기본적으로 그냥 min() 이라는 것을 알 수 있습니다. 우리가 이 함수를 정의하는 유일한 이유는 코드를 더 이해하기 쉽게 하기 위해서입니다.
이제 sceneDE()에 추가하여 사용해 볼 수 있습니다!

float sceneDE(vec3 pos) {
    return opUnion(
        sphereDE(pos, vec3(0,1,1), 1.0),
        sphereDE(pos, vec3(0,0,0), 1.0)
    );
}

제대로 했다면 바로 옆에 두 개의 구체가 보일 것입니다!

다음으로 차이 연산자를 추가해 보겠습니다. 이번에는 max() 함수를 사용합니다.

// a and b are NOT interchangeable
float opDiff(float a, float b) {
    return max(-a, b);
}

차이 연산자를 사용하도록 조정sceneDE():

float sceneDE(vec3 pos) {
    return opDiff(
        sphereDE(pos, vec3(0,-1,-0.5), 1.0),
        sphereDE(pos, vec3(0,0,0), 1.0)
    );
}

마지막으로 교차 연산자를 추가할 수 있습니다. 노조와 마찬가지로 매우 간단합니다.

// a and b are interchangeable
float opIntersect(float a, float b) {
    return max(a,b);
}

그리고 그것을 사용하십시오:

float sceneDE(vec3 pos) {
    return opIntersect(
        sphereDE(pos, vec3(0,-1,-0.5), 1.0),
        sphereDE(pos, vec3(0,0,0), 1.0)
    );
}

이제 세 가지 기본 부울 연산자가 있습니다! Here's a shader showcasing all three of them.

지금까지 우리는 장면을 만들기 위해 구만 사용했습니다. 제 생각에는 우리가 다른 DE를 가져와서 양념을 칠 때가 된 것 같습니다. this page(raymarching에 대한 나의 참조 참조)을 보면 구 다음 DE는 상자에 대한 DE입니다. 그러나 상자에 대한 또 다른 상자도 있지만 옵션으로 모서리가 둥글게 되어 있습니다. 유연성을 위해 다음 중 하나를 사용합니다.

// Original from here: https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
float roundBoxDE( vec3 p, vec3 b, float r) {
    vec3 q = abs(p) - b;
    return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0) - r;
}

번역이 내장되어 있지 않으므로 번역 작업을 수행합니다.

vec3 opTranslate(vec3 pos, vec3 moves) {
    return pos - moves;
}

괜찮은! 이제 장면 DE에서 이 모든 것을 사용할 수 있습니다.

float sceneDE(vec3 pos) {
    float u = opUnion(
        sphereDE(pos, vec3(-2.5,-1,-0.5), 1.0),
        roundBoxDE(opTranslate(pos, vec3(-2.5, -1.0, -1.5)), vec3(0.75,0.75,0.75), 0.0)
    );
    float d = opDiff(
        sphereDE(pos, vec3(0,-1,-0.5), 1.0),
        roundBoxDE(opTranslate(pos, vec3(0.0, 0.0, 0.0)), vec3(1.0,1.0,1.0), 0.0)
    );
    float i = opIntersect(
        sphereDE(pos, vec3(2.5,-1,-0.5), 1.0),
        roundBoxDE(opTranslate(pos, vec3(3.0, -0.0, 0.7)), vec3(1.0,1.0,1.0), 0.0)
    );
    return min(u,min(d,i));
}

Here's what it should look like!
다시 말하지만, 손가락이 너무 피곤하고 다른 할 일이 있어서 여기서는 생략하겠습니다.

좋은 웹페이지 즐겨찾기