คุณแสดงผลแบบดั้งเดิมเป็น wireframes ใน OpenGL ได้อย่างไร


220

คุณแสดงผลแบบดั้งเดิมเป็น wireframes ใน OpenGL ได้อย่างไร

opengl 

2
เฉพาะเจาะจงมากขึ้นในเวอร์ชัน OpenGL ที่คุณใช้
Vertexwahn

ด้วยModernGLคุณสามารถใช้คุณลักษณะwireframeของคลาสContext ได้อย่างง่ายดาย
Szabolcs Dombi

ใช้ GL_LINES เพื่อวาด wireframes
oxine

คำตอบ:


367
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

เพื่อเปิด

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

เพื่อกลับสู่ปกติ

โปรดทราบว่าสิ่งต่าง ๆ เช่นการทำแผนที่พื้นผิวและแสงจะยังคงถูกนำไปใช้กับเส้นโครงลวดหากเปิดใช้งานซึ่งอาจดูแปลก ๆ


2
ฉันชอบคุณ. อีก 4 ไป
โจดังนั้น

37

จาก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);

75
การโทรสองสายนั้นซ้ำซ้อน ใช้ GL_FRONT_AND_BACK
shoosh

6
ในฐานะที่เป็นภาคผนวกของความคิดเห็นของ @ shoosh Red Book ระบุว่า GL_FRONT และ GL_BACK ได้ถูกคัดค้านและนำออกจาก OpenGL 3.1 ขึ้นไป ตอนนี้คุณยังคงสามารถใช้มันผ่านส่วนขยายความเข้ากันได้ แต่ถ้าคุณมีตัวเลือกระหว่างการทำงานร่วมกันไปข้างหน้าและย้อนหลังได้
fouric

1
ลิงก์ในคำตอบนี้ส่งคืน 404
Ondrej Slinták

1
@ OndrejSlintákตอนนี้ได้รับการแก้ไขแล้ว
MaxiMouse

24

สมมติว่าบริบทที่เข้ากันได้ใน 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.2 (ไม่ใช่ ES) แม้ว่ามันจะเป็นไปได้ที่ฉันจะทำอะไรซักอย่าง แต่ฉันก็เล่นกับมันมาซักหน่อยแล้วก็ไม่แน่ใจว่ามันจะใช้ยังไง ข้อมูลเพิ่มเติมใด ๆ เกี่ยวกับสิ่งที่คุณตั้งใจจะแสดงด้วยเฉดสีเหล่านี้จะเป็นประโยชน์ ฉันไม่เห็นว่าสิ่งใดนอกเหนือจากการเติมจะสร้างประโยชน์อะไร แต่นั่นก็ไม่ได้ผลเพราะค่า alpha ของ gl_FragColor ดูเหมือนจะถูกละเว้นโดยสิ้นเชิงใน OpenGL 3.2 ...
user1167662

2
แน่นอนมันไม่ คุณสามารถอ้างถึงการดำเนินงานของใครบางคนของความคิดเดียวกันในstackoverflow.com/questions/7361582/...
สุกร

1
ปัญหาที่ฉันพบเมื่อพยายามใช้การใช้งานที่แนะนำของคุณคือฉันคิดว่า shader จะไม่ได้รับการวาดนอกวัตถุที่ระบุไว้ ดังนั้นสิ่งนี้จะวาดโครงร่างเหนือวัตถุที่ถูกร่างไว้หรือไม่ กล่าวอีกนัยหนึ่งโครงร่างจะถูกบรรจุไว้ภายในวัตถุดั้งเดิมที่จะวาดอย่างหมดจด?
user1167662

1
@BrunoLevy คุณสามารถรับการประสานงานเพิ่มเติมใน webGL ได้หรือไม่? หากคุณโชคดีคุณอาจได้รับพิกัดเหล่านั้นจาก texcoords หากคุณมีโมเดลที่ง่ายมาก แต่ไม่เช่นนั้นคุณเพียงแค่เพิ่มพิกัดใหม่ จะดีเกินไปถ้ามันไม่ทำงาน :) สิ่งที่คุณต้องทำก็คือส่งสเกลาร์เดียวต่อจุดสุดยอด (จากนั้นขยายเป็น 3 เวกเตอร์ในส่วนยอด)
สุกร

2
อาตอนนี้ฉันเห็น ... f_width () เป็นเพื่อนของฉันในแง่นี้ ขอบคุณ
Neil Gatenby

5

หากคุณใช้ไพพ์ไลน์คงที่ (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หรือสร้างข้อมูลใหม่สำหรับโครงลวด


3

วิธีที่ง่ายที่สุดคือการวาด primitives GL_LINE_STRIPเป็น

glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();

ไม่ใช่ถ้ามันเป็นพวงของ GL_TRIANGLES: คุณจะได้เส้นแบ่งระหว่างกัน ใน OpenGL 1.x หรือรุ่นเก่าคุณใช้ glPolygonMode ใน OpenGL ที่ผ่านมาคุณเล่นกับเรขาคณิต shader
Fabrice NEYRET

นี่เป็นวิธีโบราณในการทำสิ่งต่าง ๆ ที่ต้องถูกทิ้งไว้ข้างหลัง
Benny Mackney

2

ใน 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();
}

ประกาศ:


1

คุณสามารถใช้ไลบรารี glut ดังนี้:

  1. สำหรับทรงกลม:

    glutWireSphere(radius,20,20);
    
  2. สำหรับกระบอกสูบ:

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  3. สำหรับ Cube:

    glutWireCube(1.5);
    

0

วิธีที่ดีและง่ายในการวาดเส้นป้องกันนามแฝงบนเป้าหมายการเรนเดอร์ที่ไม่ใช่นามแฝงคือการวาดรูปสี่เหลี่ยมกว้าง 4 พิกเซลด้วยพื้นผิว 1x4 โดยมีค่าช่องอัลฟาเป็น {0, 1, 1, 0.} และใช้การกรองเชิงเส้นโดยไม่ใช้การทำแผนที่ mip สิ่งนี้จะทำให้เส้นหนา 2 พิกเซล แต่คุณสามารถเปลี่ยนพื้นผิวสำหรับความหนาที่แตกต่างกัน นี่คือเร็วกว่าและง่ายกว่าการคำนวณแบบแบริเมทริก


0

ใช้ฟังก์ชั่นนี้: เป็นโมฆะ 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


-1

หากเป็น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) โทร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.