Bagaimana Anda menjadikan primitif sebagai gambar rangka di OpenGL?
Bagaimana Anda menjadikan primitif sebagai gambar rangka di OpenGL?
Jawaban:
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.
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);
Dengan asumsi konteks yang kompatibel maju dalam OpenGL 3 dan yang lebih tinggi, Anda dapat menggunakan glPolygonMode
seperti 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_LINES
dengan 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.
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.
Cara termudah adalah menggambar primitif sebagai GL_LINE_STRIP
.
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
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:
layout (line_strip, max_vertices=3) out;
kelayout (points, max_vertices=3) out;
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.
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
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_FAN
dan GL_TRIANGLES
menggambar 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.