cara terbaik untuk menghitung vertex normals dari daftar Triangle


8

hai saya seorang pemula yang lengkap di bidang computergraphics, mohon maaf jika ini jawaban yang bodoh. Saya mencoba membuat mesin 3d sederhana dari awal, lebih untuk tujuan pendidikan daripada untuk penggunaan nyata.

untuk saat ini saya hanya menghitung wajah normal. lewat sini:

saya punya objek Permukaan dengan di dalam daftar Segitiga. saya menghitung normals di dalam kelas Triangle, dengan cara ini:

triangle.computeFaceNormals() {
    Vec3D u = v1.sub(v3)
    Vec3D v = v1.sub(v2)
    Vec3D normal = Vec3D.cross(u,v)
    normal.normalized()
    this.n1 = this.n2 = this.n3 = normal
}

dan saat membangun permukaan:

t = new Triangle(v1,v2,v3)
t.computeFaceNormals()
surface.addTriangle(t)

dan saya pikir ini adalah cara terbaik untuk melakukan itu .. bukan?

sekarang .. ini berhasil, ok. tapi cahaya itu tidak dihaluskan. Saya mencoba menghitung juga vertex normals. (Saya sedang menguji mesin saya dengan permukaan tubolar jadi saya memiliki hampir semua titik dibagi dengan lebih dari satu segitiga)

Saya telah menemukan algoritma sederhana ini: flipcode vertex normal tapi .. hei algoritma ini memiliki .. kompleksitas eksponensial? (Jika ingatan saya tidak gagal latar belakang ilmu komputer saya ..) (bytheway .. itu memiliki 3 loop bersarang .. saya tidak berpikir itu cara terbaik untuk melakukannya ..)

ada saran?


Bahasa apa ini? Sepertinya saya tadalah hasil computeFaceNormals(yang tidak mengembalikan apa-apa), bukan segitiga.

itu pseudocode:) Anda benar dalam kode nyata saya juga "mengembalikan ini", maaf saya sudah diedit!
nkint

Jawaban:


6

"Best" sangat subyektif - ini akan melibatkan penimbangan apa yang Anda butuhkan dari algoritma versus inputnya, kompleksitas runtime, dan properti lainnya.

Oleh karena itu, baik pendekatan Anda maupun pendekatan FlipCode yang masuk akal dalam hal menghasilkan hasil yang dapat digunakan (Anda dapat dengan mudah menyalin 'wajah normals' Anda ke setiap titik, jika Anda tidak berbagi contoh titik sebenarnya antara segitiga, yang saya tidak jelas aktif dari kode Anda). Teknik-teknik lain termasuk bobot kontribusi masing-masing wajah normal dengan ukuran sudut yang dibuat dengan masing-masing wajah dibagi oleh vertex.

Anda benar karena pendekatan FlipCode tampak suboptimal seperti yang tertulis, tetapi bisa saja tidak ditentukan dengan baik: sedikit tidak jelas apakah ini bermaksud menyarankan loop kedua melintasi semua wajah dalam model, dibandingkan beberapa wajah yang berbagi simpul yang dimaksud. Jika Anda memiliki informasi adjacency untuk mengurangi ruang pencarian dari loop kedua, itu menjadi kurang menjadi perhatian. Tentu saja Anda mungkin tidak memiliki informasi kedekatan itu - ini adalah apa yang saya maksudkan dengan mempertimbangkan input apa yang Anda miliki untuk algoritma Anda.

Jika Anda tidak hanya ingin menyalin wajah normal ke dalam simpul, atau Anda berbagi simpul dan tidak ingin membaginya, Anda dapat:

foreach vertex:
   set vertex normal to (0,0,0)

foreach triangle:
   foreach vertex on that triangle:
      set vertex normal = normalize( vertex normal + face normal )

Ini mengasumsikan bahwa setiap segitiga sebenarnya mereferensikan masing-masing titik daripada menyimpan salinannya - saya tidak tahu bahasa apa yang Anda gunakan jadi saya tidak tahu apakah itu masalahnya atau tidak.


maaf inggris bukan lang pertama saya jadi mayebe saya sudah jelaskan dengan cara yang buruk apa yang saya inginkan .. saya belum vertex normals! saya sudah mengedit jawaban saya sedikit, semoga sekarang saya lebih jelas
nkint

Tidak apa-apa, saya mengerti Anda tidak memiliki vertex normals. Pseudocode yang saya sediakan akan menghitungnya untuk Anda dengan terlebih dahulu mengatur setiap simpul normal ke (0,0,0) dan kemudian merangkum normals wajah untuk setiap wajah yang disentuh simpul (dan tentu saja normalisasi ulang).

5
Anda seharusnya tidak menormalkan normals dengan cara ini. Anda harus menormalkan setelah semua penjumlahan di foreach lain. Jika ada misalnya 10 segitiga dengan normal yang sama, tetapi yang terakhir adalah berbeda (hasil normal harus hampir sama dengan normal dari 10 segitiga), maka Anda akan memiliki ini, ketika menjumlahkan yang terakhir: set vertex nromal = normalize (( 1,0,0) + (0,0,1)) dan itu adalah (0,5,0,0,5), yang salah. Saya harap saya tidak membingungkan Anda.
zacharmarz

7

Josh Petrie benar. Jika Anda ingin menghitung normals verteks, Anda harus mempertimbangkan kontribusi segitiga dengan sudut. Tetapi Anda dapat menggunakan solusi naif dan hanya menjumlahkan semua normals dari semua wajah di sekitar vertex.

Jadi, Anda hanya menghitung semua wajah normal dan menormalkannya. Kemudian atur semua vertex normals ke nol. Kemudian untuk setiap wajah (segitiga) tambahkan normalnya ke semua simpulnya. Kemudian normalisasikan semua vertex normals. Dan sudah selesai.

Itu tidak terlalu benar tetapi itu bisa cukup.

Dan perhitungan normal wajah Anda di atas - itu benar tetapi Anda harus sadar, di mana kepala normal. Itu bisa naik atau turun. Itu tergantung pada produk silang - AxB tidak sama dengan BxA - itu memberi Anda vektor yang berlawanan.


Poin bagus mengenai produk silang.

2

Mari kita asumsikan bahwa kita memiliki kubus yang terbuat dari 6 persegi panjang. Kita sudah tahu bahwa vertex normal untuk sebuah kubus bukan jumlah normal dari koneksi karena tepi yang tajam. Jika Anda membangun peta nilai titik dan itu normals vertex yang berbeda untuk sebuah kubus Anda berakhir dengan 3 normals untuk setiap titik.

Mempertahankan poin di atas dalam pikiran ini adalah bagaimana saya menghitung vertex normals (Saya telah mengujinya dan saya menggunakannya).

class Face{
    uint vert_indices[3];
    vec3 surface_normal;
    vec3 vertex_normal[3];
}

Setiap wajah melacak vertex normals untuk digunakan karena dua wajah mungkin berbagi verteks tidak berarti vertex normal akan sama untuk setiap wajah.

Mari kita asumsikan kita sedang mencoba menghitung titik normal untuk vert ketika rendering face2 .

vert dibagi oleh face0 , face1 , face2 , face3 dan face4 . Semua wajah di atas adalah tetangga dalam rangka dan face0 dan face4 connect untuk membentuk lingkaran.

Vertex normal untuk vert adalah jumlah dari semua rantai tetangga yang terhubung untuk menghadapi 2 dinormalisasi. Rantai berhenti jika sudut antara dua wajah bertetangga lebih dari 0,8 radian (sudut == arccos (crossProduct (faceA.surface_normal, faceB.surface_normal))).

jika sudut antara face0 dan face1 lebih dari 0,8 radian dan sudut antara face3 dan face4 lebih dari 0,8 radian dari titik normal untuk vert saat rendering face2 adalah menormalkan ( surfnormal1 + surfnormal2 + surfnormal3 ).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.