2010-01-15 32 views
37

Tôi đang triển khai GUI được xây dựng trên đầu OpenGL. Tôi đã gặp phải vấn đề mà mỗi GUI sẽ có - hiển thị văn bản. Tôi biết một số phương pháp rendering văn bản trong OpenGL, tuy nhiên, tôi là wonderin mà trong số họ sẽ là phù hợp nhất cho một GUI.Làm cách nào để hiển thị văn bản trực tiếp OpenGL cho GUI?

Nói chung trong GUI, chúng tôi có hai loại văn bản - tĩnh và trực tiếp. Tĩnh đủ dễ dàng - chúng ta có thể kết xuất TTF thành một texture và quên nó đi. Đó là văn bản "sống" khiến tôi bận tâm hơn - hãy tưởng tượng bảng điều khiển hoặc trò chuyện trực tiếp trong trò chơi nhiều người chơi.

Tôi nghĩ đến một vài lựa chọn:

  • không có trường hợp đặc biệt - hiển thị và tải một kết cấu mỗi lần thay đổi văn bản, giữ trong tâm trí chỉ để rerender nó khi văn bản thực sự mới xuất hiện, và cố gắng để phân chia các văn bản lớn hơn thành các phần nhỏ (như mỗi dòng trò chuyện). Tuy nhiên, điều này sẽ vẫn khiến chúng tôi bị treo trong các trường hợp như dòng số thay đổi mọi lúc hoặc văn bản giới thiệu hiển thị "trên mỗi ký tự" (kiểu máy đánh chữ được thấy trong một số trò chơi khoa học viễn tưởng)
  • quad-per character - this cũng có vẻ là một giải pháp phổ biến, bạn chuẩn bị một kết cấu với bảng ASCII và hiển thị một ký tự quad. Tuy nhiên, tôi có những nghi ngờ nghiêm trọng về hiệu quả của giải pháp như vậy. Lời khuyên làm thế nào để làm cho nhanh hơn cũng sẽ được chào đón.
  • giải pháp lai - tuy nhiên tôi không có ý tưởng làm thế nào để thực hiện điều đó sạch

Câu hỏi đặt ra do đó là - làm thế nào để làm cho văn bản trong OpenGL một cách hiệu quả?

Nếu điều này giúp, tôi đang viết mã trong STL/Boost-heavy C++ và nhắm vào GForce 6 và các card đồ họa sau này.

+1

ĐỪNG xây dựng kết cấu lớn với tất cả các glyphs thể trên chúng. Trong khi nó dễ dàng và 'hợp lý' cho phông chữ phương Tây, nếu bạn cố gắng quốc tế hóa ứng dụng của bạn, bạn nhanh chóng nhận ra rằng phương pháp này là không bền vững với phông chữ phía đông. Giải pháp có thể mở rộng duy nhất là tạo văn bản động, khi cần thiết. –

+1

Nếu bạn cố gắng tự mình render từng glyph, bạn sẽ bỏ qua mọi thứ mà hệ điều hành biết về các điểm nhấn, dấu trọng âm và các ký tự kết hợp, các kịch bản từ phải sang trái, và một số kiểu bố cục khác mà tôi đang quên. . Có thể không có bảng văn bản với 0-9a-zA-Z với dấu chấm câu để bao gồm một số trường hợp thực sự phổ biến, nhưng hầu hết thời gian bạn có được kiểu đẹp hơn khi bạn hỏi trình kết xuất phông chữ cho toàn bộ dòng hoặc đoạn. – codewarrior

Trả lời

29

EDIT2: Sean Barrett vừa phát hành Bitmap fonts for C/C++ 3D programmers.

EDIT: một mã đá quý khác đáng xem là Font Stash thúc đẩy Sean Barrett's stb_truetype.h.


Bạn có thể tạo họa tiết trong đó bạn hiển thị tất cả các ký tự của phông chữ. Sau đó, bạn chỉ cần vẽ quads kết cấu với chiếu chính xác và tọa độ kết cấu thích hợp: phương pháp này hoạt động khi văn bản của bạn là trong một ngôn ngữ không chứa nhiều biểu tượng: như tiếng Anh. Các kết cấu phông chữ được tạo ra một lần ở đầu của ứng dụng và sau đó rendering quads thực sự là nhanh.

Đó là những gì tôi đang sử dụng và tôi tin rằng đó là cách nhanh nhất để hiển thị văn bản trong OpenGL. Lúc đầu, tôi sử dụng công cụ Angelcode's Bitmap Font Generator và sau đó tôi tích hợp trực tiếp FreeType và xây dựng một kết cấu lớn chứa tất cả các hình tượng trưng khi khởi chạy ứng dụng. Đối với lời khuyên để cải thiện tốc độ render quads, tôi chỉ sử dụng VBO như phần còn lại của hình học trong ứng dụng của tôi.

Tôi ngạc nhiên khi bạn nghi ngờ về hiển thị quad trong khi bạn không có vẻ lo lắng về hiệu suất tạo kết cấu trên cpu, sau đó tải lên, sau đó liên kết nó để cuối cùng hiển thị hình chữ nhật mỗi khung hình. Thay đổi trạng thái OpenGL là nút cổ chai, không phải là 500 - 1000 quads bạn sẽ sử dụng cho văn bản.

Ngoài ra, hãy xem các thư viện như thư viện FTGL chuyển đổi toàn bộ phông chữ thành đa giác (phông chữ hình học).

+0

um, đó là những gì tôi đã viết trong câu hỏi O.o. Tôi đang hỏi về các vấn đề hiệu suất tương đối. –

+0

xin lỗi nhấp gửi trước khi hoàn thành việc viết –

+0

+1: Tôi chỉ tự hỏi về hiệu suất của "giải pháp tiêu chuẩn". Thay đổi kết cấu sẽ chỉ "thay đổi" trong khi các quad cho văn bản sẽ được thực hiện trên mỗi khung hình, đó là lý do tại sao tôi tự hỏi. –

8

Hãy thử đọc: http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1.

Cách tiếp cận được mô tả là phương pháp điển hình cho hiển thị văn bản với API đồ họa. Một ký tự cho mỗi quad và tất cả dữ liệu hình ảnh cho văn bản trong một kết cấu duy nhất. Nếu bạn có thể phù hợp với toàn bộ ký tự của bạn được đặt thành một kết cấu (thực sự, tùy thuộc vào kích thước của kết cấu, bạn có thể có thể phù hợp với một số) dựng hình là cực kỳ nhanh.

Điều quan trọng là ràng buộc kết cấu là thao tác bạn cần để giảm thiểu. Nếu bạn có thể hiển thị tất cả văn bản của mình bằng một kết cấu, bạn sẽ không cần đặt bao nhiêu văn bản lên màn hình. Thậm chí nếu bạn phải chuyển đổi kết cấu một vài lần (các phông chữ khác nhau, các thuộc tính phông chữ khác nhau [đậm, gạch chân, v.v.]) thì hiệu suất vẫn tốt. Hiệu suất văn bản có thể quan trọng hơn đối với một HUD, nhưng nó ít quan trọng hơn trong GUI.

+0

+1: Đây thực sự là một liên kết rất thú vị! Chuyển đổi kết cấu có thể được thực hiện nếu tôi có thể phù hợp với tất cả các phông chữ trong một kết cấu duy nhất. Hiện tại, kích thước của các kết cấu được phép khá lớn, vì vậy tôi nghĩ điều đó khá khả thi. –

+5

Tôi đã ném [gương của hướng dẫn DMedia] (http://fsrv.dyndns.org/mirrors/dmedia-tutorials-textrendering1/index.html). – genpfault

0

Mỗi ký tự bốn ký tự được xem là danh sách hiển thị (chỉ cập nhật khi thay đổi văn bản) là đủ cho hầu hết các trường hợp.

Tôi đã sử dụng phông chữ X11 bằng cách sử dụng XLoadQueryFont, glGenLists, glXUseXFont, glCallLists bạn có một danh sách hiển thị mô tả từng ký tự.

chức năng glCallLists chấp nhận đối số char * cho văn bản của bạn và nó có thể được nhúng bên trong danh sách hiển thị.

Vì vậy, bạn kết thúc bằng một cuộc gọi duy nhất để hiển thị khối văn bản.

Kết cấu phông chữ do G. Pakosz đề xuất tương tự, nhưng bạn tính danh sách hiển thị "theo ký tự" của riêng bạn.

Tùy chọn đầu tiên của bạn sẽ chậm hơn vì nó sẽ yêu cầu hiển thị dựa trên bộ xử lý ở mỗi thay đổi văn bản.

+0

Đây là phương pháp "sách giáo khoa", tôi biết. –

1

chỉ có thể sử dụng hai chức năng:

void renderstring2d(char string[], float r, float g, float b, float x, float y) 
{ 
    glColor3f(r, g, b); 

    glRasterPos2f(x, y); 
    for(unsigned int i = 0; i < strlen(string); i++) 
     glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]); 
} 

void renderstring3d(char string[], float r, float g, float b, float x, float y, float z) 
{ 
    glDisable(GL_LIGHTING); 
    glColor3f(r, g, b); 

    glRasterPos3f(x, y, z); 
    for(unsigned int i = 0; i < strlen(string); i++) 
     glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]); 
}

sau đó khi bạn làm cho văn bản 2D, đừng quên để thiết lập lại cả modelview và ma trận chiếu.

glMatrixMode(GL_MODELVIEW); 
glPushMatrix(); 
glLoadIdentity(); 
glMatrixMode(GL_PROJECTION); 
glPushMatrix(); 
glLoadIdentity(); 

// Render text and quads 

glPopMatrix(); 
glMatrixMode(GL_MODELVIEW); 
glPopMatrix();

Bạn không cần phải hiển thị cho quad bằng các hàm này, vì các hàm này hiển thị trực tiếp với bộ đệm khung.

Và nếu điều đó không hiệu quả đối với bạn, hãy kiểm tra điều này. http://www.opengl.org/resources/faq/technical/fonts.htm

Nó nói về hiển thị văn bản bằng cách sử dụng glBitmap, glDrawPixels và trộn alpha.

+1

Không, cảm ơn, tôi không muốn sự chậm lại như vậy;). Chắc chắn nó sẽ hiển thị trực tiếp cho bộ đệm khung, nhưng hãy dành một chút thời gian để suy nghĩ số lượng dữ liệu bạn chuyển mỗi khung giữa thẻ và bộ nhớ cục bộ. Chưa kể rằng giải pháp này không hỗ trợ phông chữ tùy chỉnh. –

+0

Vâng, tôi đã sử dụng các chức năng này cho gui của riêng mình trong một công cụ trò chơi 3D và không có thay đổi đáng chú ý nào trong tốc độ khung hình khi tôi bật hoặc tắt gui. Ngoài ra, bitmap mà nó đi qua chỉ là 135 pixel cho mỗi ký tự, đó là ít hơn nhiều so với việc tạo ra một texture và truyền toàn bộ texture đó cho card đồ họa mỗi khi bạn muốn render một ký tự. –

+0

@Ned Làm thế nào tôi có thể làm điều này, nếu tôi đang sử dụng SDL thay vì GLUT? – Ben

1

Thật khó để làm, đặc biệt nếu bạn muốn sử dụng các kỹ thuật dựng hình phông chữ phụ. Hãy xem số ClanLib SDK. Nó sử dụng trình kết xuất hàng loạt để hiển thị toàn bộ màn hình văn bản trong một cuộc gọi OpenGL duy nhất. Vì nó có giấy phép dựa trên zlib, bạn có thể trích xuất mã của nó nếu bạn không muốn sử dụng chính SDK đó

4

Bạn có thể hiển thị văn bản dưới dạng mặt tam giác và tránh sử dụng kết cấu. Bằng cách này, bạn tránh các cạnh unsharp khi văn bản được phóng to. Tôi đã viết một phông chữ ASCII low poly có mã nguồn mở và có sẵn tại my github.

Một cách khác để có cạnh sắc nét trên văn bản của bạn là SDF font rendering, nhưng điều này bị một số đồ tạo tác.

3

freetype-glhttps://github.com/rougier/freetype-gl là thư viện tích hợp freetype và OpenGL.

tưởng tượng console

Xem giao diện điều khiển: https://github.com/rougier/freetype-gl/blob/a4cfb9abac19a0ab62b625a9b6f856e032fe3732/demos/console.c

enter image description here

Làm thế nào để làm cho nó chạy trên Ubuntu 15.10: https://github.com/rougier/freetype-gl/issues/82#issuecomment-216025527

Xem thêm chi tiết tại địa chỉ: How to draw text using only OpenGL methods?

Urho3D ConsoleInput.cpp

https://github.com/urho3d/Urho3D/blob/6b63f20065558cff1842bc8e1e3c6ee11f4bf577/Source/Samples/26_ConsoleInput/ConsoleInput.cpp

enter image description here

Các vấn đề liên quan