Bagaimana Anda menjadikan primitif sebagai gambar rangka di OpenGL?

220

Bagaimana Anda menjadikan primitif sebagai gambar rangka di OpenGL?


sumber
2
Lebih spesifik pada versi OpenGL yang Anda gunakan.
Vertexwahn
Dengan ModernGL Anda dapat dengan mudah menggunakan atribut wireframe dari kelas Context
Szabolcs Dombi
gunakan GL_LINES untuk menggambar gambar rangka
oxine

Jawaban:

367
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

untuk menghidupkan,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

untuk kembali normal.

Perhatikan bahwa hal-hal seperti pemetaan tekstur dan pencahayaan masih akan diterapkan ke garis rangka gambar jika diaktifkan, yang bisa terlihat aneh.


sumber
2
Aku suka kamu. 4 lagi.
Jo So
37

Dari http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/ogladv/tut5

// Turn on wireframe mode
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);

// Draw the box
DrawBox();

// Turn off wireframe mode
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
John Millikin
sumber
75
membuat dua panggilan itu mubazir. gunakan GL_FRONT_AND_BACK
shoosh
6
Sebagai tambahan untuk komentar @ shoosh, Buku Merah menyatakan bahwa GL_FRONT dan GL_BACK telah ditinggalkan dan dihapus dari OpenGL 3.1 dan lebih tinggi. Sekarang, Anda masih dapat menggunakannya melalui ekstensi kompatibilitas, tetapi jika Anda memiliki pilihan antara kompatibel maju dan kompatibel mundur, saya akan merekomendasikan pergi untuk yang pertama.
Fouric
1
Tautan dalam jawaban ini mengembalikan 404.
Ondrej Slinták
1
@ OndrejSlinták Sudah diperbaiki sekarang.
MaxiMouse
24

Dengan asumsi konteks yang kompatibel maju dalam OpenGL 3 dan yang lebih tinggi, Anda dapat menggunakan glPolygonModeseperti yang disebutkan sebelumnya, tetapi perhatikan bahwa garis dengan ketebalan lebih dari 1px sekarang tidak digunakan lagi. Jadi, sementara Anda bisa menggambar segitiga sebagai bingkai kawat, mereka harus sangat tipis. Di OpenGL ES, Anda dapat menggunakan GL_LINESdengan batasan yang sama.

Dalam OpenGL adalah mungkin untuk menggunakan geometri shader untuk mengambil segitiga masuk, membongkar mereka dan mengirimkannya untuk rasterisasi sebagai paha depan (pasangan segitiga benar-benar) meniru garis tebal. Cukup sederhana, sungguh, kecuali bahwa shader geometri terkenal karena penskalaan kinerja yang buruk.

Yang dapat Anda lakukan sebagai gantinya, dan apa yang juga akan berfungsi di OpenGL ES adalah menggunakan fragmen shader. Pikirkan menerapkan tekstur segitiga kawat-bingkai ke segitiga. Kecuali bahwa tidak diperlukan tekstur, itu dapat dihasilkan secara prosedural. Tapi cukup bicara, mari kita kode. Shader fragmen:

in vec3 v_barycentric; // barycentric coordinate inside the triangle
uniform float f_thickness; // thickness of the rendered lines

void main()
{
    float f_closest_edge = min(v_barycentric.x,
        min(v_barycentric.y, v_barycentric.z)); // see to which edge this pixel is the closest
    float f_width = fwidth(f_closest_edge); // calculate derivative (divide f_thickness by this to have the line width constant in screen-space)
    float f_alpha = smoothstep(f_thickness, f_thickness + f_width, f_closest_edge); // calculate alpha
    gl_FragColor = vec4(vec3(.0), f_alpha);
}

Dan vertex shader:

in vec4 v_pos; // position of the vertices
in vec3 v_bc; // barycentric coordinate inside the triangle

out vec3 v_barycentric; // barycentric coordinate inside the triangle

uniform mat4 t_mvp; // modeview-projection matrix

void main()
{
    gl_Position = t_mvp * v_pos;
    v_barycentric = v_bc; // just pass it on
}

Di sini, koordinat barycentric sederhana (1, 0, 0), (0, 1, 0)dan (0, 0, 1)untuk tiga simpul segitiga (urutannya tidak terlalu penting, yang membuat pengemasan menjadi strip segitiga berpotensi lebih mudah).

Kerugian yang jelas dari pendekatan ini adalah ia akan memakan beberapa koordinat tekstur dan Anda perlu memodifikasi array vertex Anda. Bisa diselesaikan dengan shader geometri yang sangat sederhana tapi saya masih curiga ini akan lebih lambat daripada hanya memberi makan GPU dengan lebih banyak data.

babi
sumber
Saya pikir ini tampak menjanjikan, namun ini tampaknya tidak berfungsi dalam kapasitas apa pun dengan OpenGL 3.2 (non-ES). Meskipun mungkin saya mengacaukan sesuatu, saya bermain-main dengan ini cukup lama dan tidak yakin bagaimana ini bahkan dimaksudkan untuk digunakan. Setiap informasi lebih lanjut tentang apa yang ingin Anda render dengan shader ini akan sangat membantu; Saya tidak melihat bagaimana selain pengisian akan menghasilkan sesuatu yang bermanfaat, tetapi itu bahkan tidak berhasil mengingat bahwa nilai alpha dari gl_FragColor tampaknya sepenuhnya diabaikan di OpenGL 3.2 ...
user1167662
2
Tentu saja. Anda dapat merujuk pada implementasi seseorang dari ide yang sama di stackoverflow.com/questions/7361582/… .
babi
1
Masalah yang saya alami ketika mencoba menggunakan implementasi yang Anda sarankan adalah, saya pikir, bahwa shader tidak akan pernah menggambar di luar objek yang akan diuraikan. Oleh karena itu ini akan menggambar garis besar objek yang diuraikan? Dengan kata lain, garis besar akan murni terkandung dalam objek asli yang akan ditarik?
user1167662
1
@ BrunoLevy Anda bisa mendapatkan tambahan yang terkoordinasi di webGL, bukan? Jika Anda beruntung, Anda mungkin bisa mendapatkan koordinat tersebut dari texcoords jika Anda memiliki model yang sangat sederhana tetapi Anda hanya perlu menambahkan koordinat baru. Akan terlalu bagus jika berhasil tanpanya :). Yang Anda butuhkan adalah untuk melewatkan skalar tunggal per titik (dan kemudian memperluasnya menjadi 3-vektor dalam vertex shader).
babi
2
Ah, sekarang saya mengerti ... f_width () adalah teman saya, dalam hal ini. Terima kasih
Neil Gatenby
5

Jika Anda menggunakan pipa tetap (OpenGL <3.3) atau profil kompatibilitas yang dapat Anda gunakan

//Turn on wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

//Draw the scene with polygons as lines (wireframe)
renderScene();

//Turn off wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

Dalam hal ini Anda dapat mengubah lebar garis dengan memanggil glLineWidth

Kalau tidak, Anda perlu mengubah mode poligon di dalam metode menggambar Anda (glDrawElements, glDrawArrays, dll) dan Anda mungkin berakhir dengan beberapa hasil kasar karena data vertex Anda adalah untuk segitiga dan Anda menghasilkan garis. Untuk hasil terbaik, pertimbangkan untuk menggunakan Geometri shader atau membuat data baru untuk kerangka gambar.

Zaphyk
sumber
3

Cara termudah adalah menggambar primitif sebagai GL_LINE_STRIP.

glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
Hochester
sumber
tidak jika itu adalah sekelompok GL_TRIANGLES: Anda akan mendapatkan garis di antara mereka. Di OpenGL 1.x atau legacy Anda menggunakan glPolygonMode. Di OpenGL terbaru Anda bermain dengan shader geometri.
Fabrice NEYRET
Ini adalah cara kuno dalam melakukan hal-hal yang perlu ditinggalkan.
Benny Mackney
2

Di Modern OpenGL (OpenGL 3.2 dan lebih tinggi), Anda bisa menggunakan Geometry Shader untuk ini:

#version 330

layout (triangles) in;
layout (line_strip /*for lines, use "points" for points*/, max_vertices=3) out;

in vec2 texcoords_pass[]; //Texcoords from Vertex Shader
in vec3 normals_pass[]; //Normals from Vertex Shader

out vec3 normals; //Normals for Fragment Shader
out vec2 texcoords; //Texcoords for Fragment Shader

void main(void)
{
    int i;
    for (i = 0; i < gl_in.length(); i++)
    {
        texcoords=texcoords_pass[i]; //Pass through
        normals=normals_pass[i]; //Pass through
        gl_Position = gl_in[i].gl_Position; //Pass through
        EmitVertex();
    }
    EndPrimitive();
}

Pemberitahuan:

LMD
sumber
1

Anda dapat menggunakan pustaka glut seperti ini:

  1. untuk bola:

    glutWireSphere(radius,20,20);
    
  2. untuk Silinder:

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  3. untuk Cube:

    glutWireCube(1.5);
    
H.Mohcen
sumber
0

Cara yang baik dan sederhana untuk menggambar garis anti-alias pada target render non-alias adalah menggambar persegi empat dengan lebar 4 piksel dengan tekstur 1x4, dengan nilai saluran alfa dari {0., 1., 1., 0.} , dan gunakan pemfilteran linear dengan memetakan mip. Ini akan membuat garis-garis tebal 2 piksel, tetapi Anda dapat mengubah tekstur untuk ketebalan yang berbeda. Ini lebih cepat dan lebih mudah daripada perhitungan barymetric.

Peter Soltesz
sumber
0

gunakan fungsi ini: void glPolygonMode (wajah GLenum, mode GLenum);

wajah: Menentukan poligon yang berlaku mode. bisa menjadi GL_FRONT untuk sisi depan poligon dan GL_BACK untuk punggungnya dan GL_FRONT_AND_BACK untuk keduanya.

mode: Tiga mode didefinisikan dan dapat ditentukan dalam mode:

GL_POINT: Simpul poligon yang ditandai sebagai awal dari batas batas digambarkan sebagai titik.

GL_LINE: Tepi batas poligon diambil sebagai segmen garis. (target Anda)

GL_FILL: Bagian dalam poligon terisi.

PS: glPolygonMode mengontrol interpretasi poligon untuk rasterisasi dalam pipa grafis.

untuk informasi lebih lanjut lihat halaman referensi OpenGL di grup khronos: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml

omar ghannou
sumber
-1

Jika OpenGL ES 2.0 yang Anda hadapi, Anda dapat memilih salah satu dari konstanta mode undian

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, untuk menggambar garis,

GL_POINTS (jika Anda hanya perlu menggambar simpul), atau

GL_TRIANGLE_STRIP,, GL_TRIANGLE_FANdan GL_TRIANGLESmenggambar segitiga yang diisi

sebagai argumen pertama untuk Anda

glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)

atau

glDrawArrays(GLenum mode, GLint first, GLsizei count) panggilan.

Pemenang
sumber