Cách tính định mức bề mặt cho hình học được tạo


12

Tôi có một lớp tạo hình dạng 3D dựa trên các đầu vào từ mã gọi. Các đầu vào là những thứ như chiều dài, độ sâu, cung, v.v ... Mã của tôi tạo ra hình học một cách hoàn hảo, tuy nhiên tôi đang gặp rắc rối khi tính toán các quy tắc bề mặt. Khi được thắp sáng, hình dạng của tôi có màu sắc / kết cấu rất kỳ quái từ các quy tắc bề mặt không chính xác đang được tính toán. Từ tất cả các nghiên cứu của tôi, tôi tin rằng toán học của tôi là chính xác, có vẻ như có gì đó không đúng với kỹ thuật hoặc phương pháp của tôi.

Ở mức độ cao, làm thế nào để người ta đi lập trình tính toán các quy tắc bề mặt cho một hình dạng được tạo ra? Tôi đang sử dụng Swift / SceneKit trên iOS cho mã của mình nhưng một câu trả lời chung chung là ổn.

Tôi có hai mảng đại diện cho hình dạng của tôi. Một là một mảng các điểm 3D đại diện cho các đỉnh tạo nên hình dạng. Mảng khác là một danh sách các chỉ mục của mảng đầu tiên ánh xạ các đỉnh thành hình tam giác. Tôi cần lấy dữ liệu đó và tạo ra một mảng thứ 3 là một tập hợp các quy tắc bề mặt hỗ trợ cho việc chiếu sáng của hình dạng. (xem SCNGeometrySourceSemanticNormaltrong CảnhKit` )

Danh sách các đỉnh và chỉ mục luôn khác nhau tùy thuộc vào các đầu vào của lớp vì vậy tôi không thể tính toán trước hoặc mã cứng các quy tắc bề mặt.


Cần thêm bối cảnh. Bạn đang cố gắng để tính toán các tiêu chuẩn phân tích cho một bề mặt tham số? Một bề mặt ngầm? Hay bạn muốn tính toán các quy tắc từ một lưới tam giác chung? Hay cái gì khác?
Nathan Reed

Cảm ơn, tôi đã thêm chi tiết. Để trả lời câu hỏi của bạn, tôi cần tính toán các quy tắc từ một lưới tam giác chung. Mặc dù rõ ràng là lưới là khác nhau tùy thuộc vào đầu vào. Hình dạng của tôi là một mũi tên 3D, như một ví dụ ở đây là một ảnh chụp màn hình của nó ở 2 dạng khác nhau (tức là xuyên tâm và tuyến tính). Lớp thay đổi chiều rộng, chiều sâu, chiều dài, cung và bán kính của lưới theo yêu cầu. cl.ly/image/3O0P3X3N3d1d Bạn có thể thấy ánh sáng kỳ lạ mà tôi đang có với những nỗ lực kém cỏi của mình trong việc giải quyết điều này.
macinjosh

3
Phiên bản ngắn là: tính toán mỗi đỉnh bình thường là tổng bình thường của các giá trị chuẩn của tất cả các tam giác chạm vào nó. Tuy nhiên, điều này sẽ làm cho mọi thứ trơn tru, có thể không phải là những gì bạn muốn cho hình dạng này. Tôi sẽ cố gắng mở rộng thành một câu trả lời đầy đủ sau.
Nathan Reed

Mịn màng là những gì tôi đang đi!
macinjosh

4
Trong hầu hết các trường hợp, nếu bạn tính toán các vị trí đỉnh một cách phân tích, bạn cũng có thể tính toán các chỉ tiêu phân tích. Đối với một bề mặt tham số, các thông số là sản phẩm chéo của hai vectơ gradient. Tính trung bình của các quy tắc tam giác chỉ là một xấp xỉ và thường dẫn đến chất lượng trực quan kém hơn nhiều. Tôi sẽ đăng câu trả lời, nhưng tôi đã đăng một ví dụ chi tiết về SO ( stackoverflow.com/questions/27233820/ mẹo ) và tôi không chắc liệu chúng tôi có muốn sao chép nội dung ở đây không.
Reto Koradi

Câu trả lời:


9

Bạn chỉ đơn giản là không muốn kết quả hoàn toàn trơn tru. Trong khi phương pháp nhận xét của Nathan Reed: "Tính toán từng đỉnh để đối mặt bình thường, tính tổng chúng, chuẩn hóa tổng", nói chung hoạt động đôi khi thất bại một cách ngoạn mục. Nhưng điều đó không quan trọng ở đây, chúng ta có thể sử dụng phương pháp đó bằng cách thêm một mệnh đề từ chối vào nó.

Trong trường hợp này, bạn chỉ muốn các phần nhất định không được làm mịn so với các phần khác. Bạn muốn chọn cạnh cứng. Vì vậy, ví dụ trên cùng và dưới cùng là hình dạng dải tam giác ở bên cạnh, như là mỗi khu vực phẳng.

Hình ảnh chúng tôi đang theo dõi

Hình 1 : Kết quả bạn muốn.

Trong thực tế, bạn chỉ muốn trung bình các đỉnh của khu vực cong, tất cả những người khác có thể sử dụng bình thường họ có được hình dạng tam giác của họ một mình. Vì vậy, bạn nên nghĩ về lưới là 9 vùng riêng biệt được xử lý mà không có các vùng khác.

Hiển thị lưới và quy tắc]

Hình 2 : Hình ảnh hiển thị cấu trúc lưới và các thông số.

Bạn chắc chắn có thể tự động suy luận điều này bằng cách không bao gồm các quy tắc nằm ngoài góc nhất định từ các đỉnh chính bình thường. Mã giả:

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

Điều đó hoạt động, nhưng bạn có thể đơn giản tránh tất cả những điều này tại thời điểm tạo vì bạn hiểu rằng các mặt phẳng riêng biệt đang hoạt động khác nhau. Vì vậy, chỉ có các cạnh cong cần hợp nhất hướng bình thường. Và trên thực tế, bạn có thể chỉ cần trực tiếp tính toán chúng từ hình dạng toán học cơ bản.


9

Tôi thấy chủ yếu là ba cách tính chuẩn cho một hình dạng được tạo.

Phân tích chuẩn

Trong một số trường hợp, bạn có đủ thông tin về bề mặt để tạo các quy tắc. Ví dụ, bình thường của bất kỳ điểm nào trên một hình cầu là tầm thường để tính toán. Nói một cách đơn giản, khi bạn biết đạo hàm của hàm, bạn cũng biết bình thường.

Nếu trường hợp của bạn đủ hẹp để cho phép bạn sử dụng các tiêu chuẩn phân tích, họ có thể sẽ cho kết quả tốt nhất về độ chính xác. Kỹ thuật này không mở rộng quá tốt: nếu bạn cũng cần xử lý các trường hợp không thể sử dụng quy tắc phân tích, có thể dễ dàng hơn để giữ kỹ thuật xử lý trường hợp chung và loại bỏ hoàn toàn phân tích.

Định mức Vertex

Tích chéo của hai vectơ cho vectơ vuông góc với mặt phẳng mà chúng thuộc về. Vì vậy, nhận được bình thường của một hình tam giác là đơn giản:

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

Hơn nữa, trong ví dụ trên, chiều dài của sản phẩm chéo tỷ lệ thuận với diện tích bên trong abc . Vì vậy, việc làm mịn bình thường ở một đỉnh được chia sẻ bởi một số hình tam giác có thể được tính bằng cách tính tổng các sản phẩm chéo và chuẩn hóa như bước cuối cùng, do đó, cân trọng lượng của mỗi tam giác theo diện tích của nó.

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);
}

Nếu bạn đang làm việc với quads, có một mẹo hay mà bạn có thể sử dụng: đối với quad abcd , hãy sử dụng crossProduct(c - a, d - b)và nó sẽ xử lý các trường hợp độc đáo trong đó quad thực tế là một hình tam giác.

Iñigo quilez đã viết một vài bài viết ngắn về chủ đề: bình thường hóa thông minh của một lưới , và bình thường và diện tích của đa giác n mặt .

Định mức từ các dẫn xuất một phần

Định mức có thể được tính toán trong shader mảnh từ các đạo hàm riêng. Toán học phía sau là như nhau, ngoại trừ lần này nó được thực hiện trong không gian màn hình. Bài viết này của Angelo Pesce mô tả kỹ thuật: Normals không có quy tắc .


1
Có một cách thứ tư, nghệ sĩ cung cấp quy tắc;)
joojaa

@joojaa: Tôi cho rằng bạn đang đề cập đến bản đồ bình thường? Tôi chưa bao giờ nghe nói về các quy tắc tác giả thủ công khác.
Julien Guertault

1
Không, thủ công tác giả bình thường. Đôi khi điều đó xảy ra rằng nghệ sĩ của bạn biết nhiều hơn về cách hành xử bình thường so với các mô hình lập trình viên làm. Đôi khi có một chút vấn đề đối với các công cụ tính toán nếu họ cho rằng các quy tắc xuất phát từ các tính toán cơ bản. Nhưng chắc chắn nó xảy ra và bạn tiết kiệm rất nhiều thời gian trong mô hình toán học.
joojaa

1
Đôi khi chúng được gọi là "quy tắc rõ ràng" (thuật ngữ 3ds max và maya).
Dusan Bosnjak 'pailhead'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.