คุณแสดงผลแบบดั้งเดิมเป็น wireframes ใน OpenGL ได้อย่างไร
คุณแสดงผลแบบดั้งเดิมเป็น wireframes ใน OpenGL ได้อย่างไร
คำตอบ:
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
เพื่อเปิด
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
เพื่อกลับสู่ปกติ
โปรดทราบว่าสิ่งต่าง ๆ เช่นการทำแผนที่พื้นผิวและแสงจะยังคงถูกนำไปใช้กับเส้นโครงลวดหากเปิดใช้งานซึ่งอาจดูแปลก ๆ
จาก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);
สมมติว่าบริบทที่เข้ากันได้ใน OpenGL 3 และสูงกว่านั้นคุณสามารถใช้glPolygonMode
ตามที่กล่าวไว้ก่อนหน้านี้ แต่โปรดสังเกตว่าบรรทัดที่มีความหนามากกว่า 1px จะถูกคัดค้าน ดังนั้นในขณะที่คุณสามารถวาดรูปสามเหลี่ยมเป็นโครงลวดได้พวกมันจะต้องผอมมาก ใน OpenGL ES คุณสามารถใช้GL_LINES
ด้วยข้อ จำกัด เดียวกัน
ใน OpenGL มีความเป็นไปได้ที่จะใช้รูปทรงเรขาคณิตที่มีรูปสามเหลี่ยมที่เข้ามาแยกส่วนพวกเขาและส่งพวกเขาสำหรับ rasterization เป็นล่าม (รูปสามเหลี่ยมจริง ๆ ) จำลองเส้นหนา ค่อนข้างเรียบง่ายจริงๆยกเว้นว่าเฉดสีเรขาคณิตนั้นมีชื่อเสียงในด้านการปรับขนาดที่ไม่ดี
คุณสามารถทำอะไรแทนและสิ่งที่จะทำงานใน OpenGL ES คือการจ้างส่วน Shader คิดว่าการใช้พื้นผิวของสามเหลี่ยมโครงลวดกับสามเหลี่ยม ยกเว้นว่าไม่ต้องการพื้นผิวใด ๆ ก็สามารถสร้างขั้นตอนได้ แต่พอคุยกันได้รหัส ชิ้นส่วน shader:
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);
}
และจุดสุดยอด 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
}
นี่พิกัด Barycentric เป็นเพียง(1, 0, 0)
, (0, 1, 0)
และ(0, 0, 1)
สำหรับสามจุดสามเหลี่ยม (คำสั่งที่ไม่ได้เรื่องจริงๆซึ่งจะทำให้การบรรจุลงในแถบสามเหลี่ยมที่อาจเกิดขึ้นได้ง่ายขึ้น)
ข้อเสียที่ชัดเจนของวิธีนี้คือมันจะกินพิกัดพื้นผิวบางส่วนและคุณจำเป็นต้องแก้ไขอาร์เรย์จุดสุดยอดของคุณ สามารถแก้ไขได้ด้วยส่วนทรงเรขาคณิตที่เรียบง่าย แต่ฉันก็ยังสงสัยว่ามันจะช้ากว่าการป้อนข้อมูล GPU ด้วยข้อมูลเพิ่มเติม
หากคุณใช้ไพพ์ไลน์คงที่ (OpenGL <3.3) หรือโปรไฟล์ความเข้ากันได้ที่คุณสามารถใช้ได้
//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);
ในกรณีนี้คุณสามารถเปลี่ยนความกว้างของเส้นได้โดยการเรียกglLineWidth
มิฉะนั้นคุณจำเป็นต้องเปลี่ยนโหมดรูปหลายเหลี่ยมภายในวิธีการวาดของคุณ (glDrawElements, glDrawArrays ฯลฯ ) และคุณอาจได้ผลลัพธ์ที่หยาบเพราะข้อมูลจุดยอดของคุณใช้สำหรับรูปสามเหลี่ยมและคุณกำลังเอาท์พุทเส้น เพื่อผลลัพธ์ที่ดีที่สุดลองใช้Geometry shaderหรือสร้างข้อมูลใหม่สำหรับโครงลวด
วิธีที่ง่ายที่สุดคือการวาด primitives GL_LINE_STRIP
เป็น
glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
ใน Modern OpenGL (OpenGL 3.2 และสูงกว่า) คุณสามารถใช้ Geometry Shader สำหรับสิ่งนี้:
#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();
}
ประกาศ:
layout (line_strip, max_vertices=3) out;
เป็นlayout (points, max_vertices=3) out;
คุณสามารถใช้ไลบรารี glut ดังนี้:
สำหรับทรงกลม:
glutWireSphere(radius,20,20);
สำหรับกระบอกสูบ:
GLUquadric *quadratic = gluNewQuadric();
gluQuadricDrawStyle(quadratic,GLU_LINE);
gluCylinder(quadratic,1,1,1,12,1);
สำหรับ Cube:
glutWireCube(1.5);
วิธีที่ดีและง่ายในการวาดเส้นป้องกันนามแฝงบนเป้าหมายการเรนเดอร์ที่ไม่ใช่นามแฝงคือการวาดรูปสี่เหลี่ยมกว้าง 4 พิกเซลด้วยพื้นผิว 1x4 โดยมีค่าช่องอัลฟาเป็น {0, 1, 1, 0.} และใช้การกรองเชิงเส้นโดยไม่ใช้การทำแผนที่ mip สิ่งนี้จะทำให้เส้นหนา 2 พิกเซล แต่คุณสามารถเปลี่ยนพื้นผิวสำหรับความหนาที่แตกต่างกัน นี่คือเร็วกว่าและง่ายกว่าการคำนวณแบบแบริเมทริก
ใช้ฟังก์ชั่นนี้: เป็นโมฆะ glPolygonMode (ใบหน้า GLenum, โหมด GLenum);
face: ระบุรูปหลายเหลี่ยมที่ใช้กับโหมด สามารถ GL_FRONT สำหรับด้านหน้าของ polygone และ GL_BACK สำหรับด้านหลังของเขาและ GL_FRONT_AND_BACK สำหรับทั้งสอง
โหมด: กำหนดสามโหมดและสามารถระบุได้ในโหมด:
GL_POINT: จุดยอดรูปหลายเหลี่ยมที่ทำเครื่องหมายว่าเป็นจุดเริ่มต้นของขอบขอบเขตจะถูกวาดเป็นจุด
GL_LINE: ขอบของรูปหลายเหลี่ยมถูกวาดเป็นส่วนของเส้น (เป้าหมายของคุณ)
GL_FILL: การตกแต่งภายในของรูปหลายเหลี่ยมเต็มไป
PS: glPolygonMode ควบคุมการแปลความหมายของรูปหลายเหลี่ยมสำหรับ rasterization ในไปป์ไลน์กราฟิก
สำหรับข้อมูลเพิ่มเติมดูที่หน้าอ้างอิงของ OpenGL ในกลุ่ม khronos: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml
หากเป็นOpenGL ES 2.0 ที่คุณกำลังเผชิญอยู่คุณสามารถเลือกหนึ่งในค่าคงที่โหมดการวาดจาก
GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,
เพื่อวาดเส้น
GL_POINTS
(หากคุณต้องการวาดจุดยอดเท่านั้น) หรือ
GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
และGL_TRIANGLES
การวาดรูปสามเหลี่ยมที่เต็มไปด้วย
เป็นอาร์กิวเมนต์แรกของคุณ
glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
หรือ
glDrawArrays(GLenum mode, GLint first, GLsizei count)
โทร