Làm thế nào để bạn kết xuất nguyên thủy dưới dạng khung lưới trong OpenGL?
Làm thế nào để bạn kết xuất nguyên thủy dưới dạng khung lưới trong OpenGL?
Câu trả lời:
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
để bật
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
để trở lại bình thường.
Lưu ý rằng những thứ như ánh xạ kết cấu và ánh sáng vẫn sẽ được áp dụng cho các dòng khung dây nếu chúng được bật, trông có vẻ lạ.
Từ 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);
Giả sử bối cảnh tương thích về phía trước trong OpenGL 3 trở lên, bạn có thể sử dụng glPolygonMode
như đã đề cập trước đó, nhưng lưu ý rằng các dòng có độ dày hơn 1px hiện không được dùng nữa. Vì vậy, trong khi bạn có thể vẽ các hình tam giác dưới dạng khung dây, chúng cần phải rất mỏng. Trong OpenGL ES, bạn có thể sử dụng GL_LINES
với cùng giới hạn.
Trong OpenGL, có thể sử dụng các shader hình học để lấy các hình tam giác đến, tháo rời chúng và gửi chúng cho rasterization dưới dạng hình tứ giác (cặp tam giác thực sự) mô phỏng các đường dày. Khá đơn giản, thực sự, ngoại trừ các shader hình học nổi tiếng với tỷ lệ hiệu suất kém.
Thay vào đó, những gì bạn có thể làm và những gì cũng sẽ hoạt động trong OpenGL ES là sử dụng tạo bóng mảnh . Hãy nghĩ đến việc áp dụng một kết cấu của tam giác khung dây cho tam giác. Ngoại trừ việc không có kết cấu là cần thiết, nó có thể được tạo ra theo thủ tục. Nhưng nói đủ rồi, hãy viết mã. Mảnh vỡ mảnh:
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);
}
Và shader đỉnh:
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
}
Ở đây, tọa độ barycentric chỉ đơn giản là (1, 0, 0)
, (0, 1, 0)
và (0, 0, 1)
trong ba đỉnh tam giác (thứ tự không quan trọng, mà làm cho bao bì thành dải tam giác có khả năng dễ dàng hơn).
Nhược điểm rõ ràng của phương pháp này là nó sẽ ăn một số tọa độ kết cấu và bạn cần sửa đổi mảng đỉnh của mình. Có thể được giải quyết bằng trình đổ bóng hình học rất đơn giản nhưng tôi vẫn nghi ngờ nó sẽ chậm hơn so với việc chỉ cung cấp cho GPU nhiều dữ liệu hơn.
Nếu bạn đang sử dụng đường ống cố định (OpenGL <3.3) hoặc cấu hình tương thích, bạn có thể sử dụng
//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);
Trong trường hợp này, bạn có thể thay đổi độ rộng đường bằng cách gọi glLineWidth
Nếu không, bạn cần thay đổi chế độ đa giác bên trong phương thức vẽ của bạn (glDrawElements, glDrawArrays, v.v.) và bạn có thể kết thúc với một số kết quả thô vì dữ liệu đỉnh của bạn là cho hình tam giác và bạn đang xuất ra các dòng. Để có kết quả tốt nhất, hãy xem xét sử dụng trình đổ bóng Hình học hoặc tạo dữ liệu mới cho khung dây.
Cách dễ nhất là vẽ các nguyên thủy như GL_LINE_STRIP
.
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
Trong OpenGL hiện đại (OpenGL 3.2 trở lên), bạn có thể sử dụng Shader Geometry cho việc này:
#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();
}
Thông báo:
layout (line_strip, max_vertices=3) out;
thànhlayout (points, max_vertices=3) out;
Một cách tốt và đơn giản để vẽ các đường chống răng cưa trên mục tiêu kết xuất không khử răng cưa là vẽ hình chữ nhật có chiều rộng 4 pixel với kết cấu 1x4, với các giá trị kênh alpha là {0., 1., 1., 0.} và sử dụng lọc tuyến tính với tắt ánh xạ mip. Điều này sẽ làm cho các đường kẻ dày 2 pixel, nhưng bạn có thể thay đổi kết cấu cho các độ dày khác nhau. Điều này nhanh hơn và dễ dàng hơn so với tính toán barymetric.
sử dụng chức năng này: void glPolygonMode (mặt GLenum, chế độ GLenum);
mặt: Chỉ định đa giác mà chế độ áp dụng cho. có thể là GL_FRONT cho mặt trước của polygone và GL_BACK cho mặt sau của anh ấy và GL_FRONT_AND_BACK cho cả hai.
chế độ: Ba chế độ được xác định và có thể được chỉ định trong chế độ:
GL_POINT: Các đỉnh đa giác được đánh dấu là điểm bắt đầu của cạnh biên được vẽ dưới dạng các điểm.
GL_LINE: Các cạnh biên của đa giác được vẽ dưới dạng các đoạn thẳng. (Mục tiêu của bạn)
GL_FILL: Phần bên trong của đa giác được lấp đầy.
PS: glPolygonMode kiểm soát việc giải thích các đa giác để rasterization trong đường ống đồ họa.
để biết thêm thông tin, hãy xem các trang tham khảo OpenGL trong nhóm khronos: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml
Nếu đó là OpenGL ES 2.0 mà bạn đang xử lý, bạn có thể chọn một trong các hằng số chế độ vẽ từ
GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,
để vẽ đường
GL_POINTS
(nếu bạn chỉ cần vẽ các đỉnh), hoặc
GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
và GL_TRIANGLES
để vẽ các hình tam giác đầy
như là đối số đầu tiên của bạn
glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
hoặc là
glDrawArrays(GLenum mode, GLint first, GLsizei count)
các cuộc gọi.