생성 된 형상에 대한 표면 법선을 계산하는 방법


12

호출 코드의 입력을 기반으로 3D 모양을 생성하는 클래스가 있습니다. 입력은 길이, 깊이, 호 등과 같은 것입니다. 내 코드는 형상을 완벽하게 생성하지만 표면 법선을 계산할 때 문제가 발생합니다. 불이 켜지면, 계산중인 잘못된 표면 법선으로 인해 모양이 매우 기괴합니다. 모든 연구에서 수학이 정확하다고 생각합니다. 기술이나 방법에 문제가있는 것 같습니다.

높은 수준에서 생성 된 모양의 표면 법선을 프로그래밍 방식으로 계산하는 방법은 무엇입니까? 내 코드에 iOS에서 Swift / SceneKit을 사용하고 있지만 일반적인 대답은 좋습니다.

모양을 나타내는 두 개의 배열이 있습니다. 하나는 모양을 구성하는 꼭짓점을 나타내는 3D 점의 배열입니다. 다른 배열은 꼭짓점을 삼각형으로 매핑하는 첫 번째 배열의 인덱스 목록입니다. 그 데이터를 가져 와서 모양의 조명을 돕는 표면 법선 세트 인 세 번째 배열을 생성해야합니다. ( SCNGeometrySourceSemanticNormalSceneKit` 참조 )

정점 및 색인 목록은 클래스의 입력에 따라 항상 다르므로 표면 법선을 사전 계산하거나 하드 코딩 할 수 없습니다.


더 많은 상황이 필요합니다. 파라 메트릭 표면에 대한 분석 법선을 계산하려고합니까? 암시 적 표면? 아니면 일반 삼각형 메쉬에서 법선을 계산 하시겠습니까? 또는 다른 것?
Nathan Reed

감사합니다. 자세한 내용을 추가했습니다. 귀하의 질문에 대답하려면 일반 삼각형 메쉬에서 법선을 계산해야합니다. 입력에 따라 메시가 다르다는 것이 분명합니다. 내 모양은 3D 화살표입니다. 예를 들어 두 가지 다른 형태 (예 : 방사형 및 선형)의 스크린 샷이 있습니다. 클래스는 요청에 따라 메시의 너비, 깊이, 길이, 호 및 반지름을 변경합니다. cl.ly/image/3O0P3X3N3d1d 이 문제를 해결하려는 저의 잘못된 시도로 인해 나타나는 이상한 조명을 볼 수 있습니다.
macinjosh

3
짧은 버전은 다음과 같습니다. 각 정점 법선은 해당 정점에 닿는 모든 삼각형의 법선의 합으로 계산됩니다. 그러나 이렇게하면 모든 것이 매끄러 워 지므로이 모양에는 적합하지 않을 수 있습니다. 나중에 전체 답변으로 확장하려고 노력할 것입니다.
Nathan Reed

내가 가고 싶은 것은 매끄 럽습니다!
macinjosh

4
대부분의 경우 정점 위치를 분석적으로 계산하면 법선을 분석적으로 계산할 수도 있습니다. 파라 메트릭 표면의 경우 법선은 두 그래디언트 벡터의 교차 곱입니다. 삼각형 법선의 평균을 계산하는 것은 근사치이며 종종 시각적으로 품질이 훨씬 떨어집니다. 답변을 게시했지만 이미 SO ( stackoverflow.com/questions/27233820/… ) 에 대한 자세한 예를 게시했으며 여기에서 복제 된 내용을 원하는지 확실하지 않습니다.
Reto Koradi

답변:


10

당신은 단순히 완전히 부드러운 결과를 원하지 않습니다. Nathan Reed의 주석 처리 방법 : "정점을 향하도록 각 정점을 계산하고, 합산하고, 합을 정규화하십시오." 그러나 여기서는 중요하지 않습니다. 거부 절을 추가하여 해당 방법을 사용할 수 있습니다.

이 경우 특정 부품이 특정 다른 부품에 대해 부드럽게 처리되지 않기를 원할뿐입니다. 선택적인 딱딱한 가장자리를 원합니다. 예를 들어 평평한 상단과 하단은 각 평평한 영역과 마찬가지로 측면의 삼각형 스트립과 분리되어 있습니다.

우리가 추구하는 이미지

이미지 1 : 원하는 결과.

사실상, 곡선 영역의 꼭짓점 만 평균화하려고합니다. 다른 모든 삼각형은 삼각형만으로 만드는 법선을 사용할 수 있습니다. 따라서 메쉬를 다른 영역없이 처리되는 9 개의 개별 영역으로 생각하는 것이 좋습니다.

메쉬 및 법선 표시]

이미지 2 : 메쉬 구조와 법선을 보여주는 이미지.

1 차 정점 법선에서 특정 각도를 벗어난 법선을 포함하지 않음으로써이를 자동으로 추론 할 수 있습니다. 의사 코드 :

For vertex in faceVertex:
    normal = vertex.normal
    For adjVertex in adjacentVertices:
        if anglebetween(vertex.normal, adjVertex.normal )  < treshold:
            normal += adjVertex.normal
    normal = normalize(normal)

그것은 작동하지만 별도의 평면이 다르게 작동한다는 것을 이해하기 때문에 생성 시이 모든 것을 피할 수 있습니다. 따라서 구부러진 면만 일반적인 방향 병합이 필요합니다. 실제로 기본 수학 모양에서 직접 계산할 수 있습니다.


10

생성 된 모양에 대한 법선을 계산하는 세 가지 방법이 주로 있습니다.

분석 법선

경우에 따라 법선을 생성하기에 표면에 대한 충분한 정보가 있습니다. 예를 들어, 구에있는 점의 법선은 계산하기가 쉽지 않습니다. 간단히 말해서 함수의 미분을 알면 정상도 알 수 있습니다.

분석 법선을 사용할 수있을 정도로 케이스가 좁 으면 정확도면에서 최상의 결과를 얻을 수 있습니다. 이 기술은 확장 성이 좋지 않습니다. 분석 법선을 사용할 수없는 경우도 처리해야하는 경우 일반적인 경우를 처리하고 분석법을 삭제하는 기술을 유지하는 것이 더 쉬울 수 있습니다.

정점 법선

두 벡터의 교차 곱은 속한 평면에 수직 인 벡터를 제공합니다. 따라서 삼각형의 법선을 얻는 것은 간단합니다.

vec3 computeNormal(vec3 a, vec3 b, vec3 c)
{
    return normalize(crossProduct(b - a, c - a));
}

또한, 위의 예에서 교차 곱의 길이는 abc 내부 영역에 비례합니다 . 따라서 여러 삼각형이 공유하는 정점에서 평활 된 법선은 교차 곱을 합산하고 마지막 단계로 정규화하여 각 삼각형의 면적에 가중치를 부여하여 계산할 수 있습니다.

vec3 computeNormal(vertex a)
{
    vec3 sum = vec3(0, 0, 0);
    list<vertex> adjacentVertices = getAdjacentVertices(a);
    for (int i = 1; i < adjacentVertices; ++i)
    {
        vec3 b = adjacentVertices[i - 1];
        vec3 c = adjacentVertices[i];
        sum += crossProduct(b - a, c - a);
    }
    if (norm(sum) == 0)
    {
        // Degenerate case
        return sum;
    }
    return normalize(sum);
}

쿼드로 작업하는 경우 사용할 수있는 좋은 트릭이 있습니다 : 쿼드 abcd의 경우 사용 crossProduct(c - a, d - b)하면 쿼드가 실제로 삼각형 인 경우를 잘 처리합니다.

Iñigo quilez는 주제에 관한 짧은 기사를 작성했습니다 : 메시의 영리한 정규화 , n면 다각형의 법선 및 면적 .

부분 도함수의 법선

부분 미분으로부터 프래그먼트 셰이더에서 법선을 계산할 수 있습니다. 스크린 공간에서 수행되는 것을 제외하고는 수학이 동일합니다. Angelo Pesce의이 기사는 기술을 설명합니다 : 법선없는 법선 .


1
아티스트가 법선을 제공하는 네 번째 방법이 있습니다.)
joojaa

@ joojaa : 나는 당신이 일반지도를 참조한다고 가정합니까? 그렇지 않으면 수동으로 작성된 법선에 대해 들어 본 적이 없습니다.
Julien Guertault

1
아니요, 수동으로 작성된 법선. 때로는 아티스트 모델보다 노멀이 어떻게 동작해야하는지 아티스트가 더 많이 알게되는 경우가 있습니다. 법선이 기본 계산에서 나온 것으로 가정하면 계산 엔진에 약간 문제가있는 경우가 있습니다. 그러나 확실히 일어나고 수학적 모델링에서 많은 시간을 절약 할 수 있습니다.
joojaa

1
이들은 때때로 "명시 적 법선"(3ds max 및 maya 용어)이라고도합니다.
Dusan Bosnjak 'pailhead'8
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.