GLSL 레이마칭으로 지형 그리기
15469 단어 GLSL
지형을 그리려면 레이를 조금씩 앞으로 이동하여 레이의 위치가 지형 높이보다 낮아지면 레이와 지형의 교차점으로 만듭니다.
지형을 생성하는 함수는 다음과 같이 되어 평면 좌표를 입력으로 하여 높이를 출력합니다.
여기에서는, 다른 주파수의 사인파를 복수 중첩한 것으로 지형을 만들고 있습니다.
float terrain(in vec2 p) {
p *= 0.2;
float height = 0.0;
float amp = 1.0;
for (int i = 0; i < 10; i++) {
height += amp * sin(p.x) * sin(p.y);
amp *= 0.5;
p *= 2.07;
}
return height * 5.0; // 適当な値で高さをスケール
}
레이를 진행해 가는 처리는 다음과 같습니다.
루프 처리 중, 이전의 terrain 함수로부터 높이를 취득해, 레이의 위치와 지형의 거리를 계산합니다.
만약 거리가 일정 이하가 되었을 경우는 교차한 것으로 간주하여 루프 처리를 중단합니다. 그렇지 않은 경우 거리를 기준으로 레이를 진행합니다.
여기서 주의해야 하는 것은 거리는 레이의 진행 방향과 지형의 거리가 아니라 어디까지나 y축 방법과의 거리라는 것입니다. 그 때문에, 절벽 절벽과 같은 높이가 급격하게 바뀌는 지형에서는 노이즈가 눈에 띄게 된다고 생각합니다.
여기에서는, 1 미만의 값을 거리에 걸쳐 신중하게 레이를 진행시키도록 하고 있습니다.
const float tmax = 100.0;
float raymarch(in vec3 origin, in vec3 direction) {
float t = 0.0;
for (int i = 0; i < 64; i++) {
vec3 p = origin + t * direction;
float height = terrain(p.xz);
float distance = p.y - height;
if(distance < 0.02 || t > tmax) {break;}
t += 0.2 * distance; // 適当な値で距離を小さくする
}
return t;
}
법선은 다음과 같이 레이마칭에서 자주 사용되는 수치 차이로 구할 수 있습니다.
vec3 normal(in vec2 p) {
float epsilon = 0.02;
return normalize(vec3(
terrain(p + vec2(epsilon, 0.0)) - terrain(p - vec2(epsilon,0.0)),
2.0 * epsilon,
terrain(p +vec2(0.0, epsilon)) - terrain(p - vec2(0.0, epsilon))
));
}
법선을 바탕으로 컬러링을 하면 이렇게 됩니다.
모든 코드와 움직이는 곳은 아래에서 확인할 수 있습니다.
h tp // glsl씨 d보 x. 이 m/E #44275.0
여기서부터는 세세한 테크닉적인 이야기를 합니다.
raymarch 함수 중 레이와 지형의 교차 판정에 다음 식을 사용했습니다.
if(distance < 0.02 || t > tmax) {break;}
이것을 이하와 같이
distance
if(distance < 0.001 * t || t > tmax) {break;}
마찬가지로, 법선의 계산에서도 다음과 같이 교차점의
t
를 건네주는 것으로, 가까운 곳만큼 세세한 계산을 실시하도록 할 수 있습니다.vec3 normal(in vec2 p, float t) {
float epsilon = 0.001 * t;
return normalize(vec3(
terrain(p + vec2(epsilon, 0.0)) - terrain(p - vec2(epsilon,0.0)),
2.0 * epsilon,
terrain(p +vec2(0.0, epsilon)) - terrain(p - vec2(0.0, epsilon))
));
}
다른 기술로는 다음과 같이 교점을 이전 단계의 값으로 보간하여 보다 정확한
t
값을 구하는 방법이 있습니다.const float tmax = 100.0;
float raymarch(in vec3 origin, in vec3 direction) {
float t = 0.0;
float step = 0.0;
float lastdistance = 0.0;
for (int i = 0; i < 64; i++) {
vec3 p = origin + t * direction;
float height = terrain(p.xz);
float distance = p.y - height;
if(distance < 0.02) {
t += step * distance / (lastdistance - distance);
break;
}
if (t > tmax) {break;}
step = 0.2 * distance;
t += step;
lastdistance = distance;
}
return t;
}
자세한 내용은 다음 사이트에서 설명합니다.
지형의 라이팅은 이하의 링크처의 내용이 참고가 됩니다.
h tp // w w. 가자 → 에 s. 오 rg / w w / 아 rc c ぇ s / 오우 t 드 rs ぃ gh 짱 g / 오 t 드 rs ぃ gh 짱 g. htm
Reference
이 문제에 관하여(GLSL 레이마칭으로 지형 그리기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/aa_debdeb/items/2b73848b019fcca70668텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)