簡體   English   中英

在OpenGL上懶惰渲染Qt

[英]Lazy rendering of Qt on OpenGL

我遇到了這個問題,並且知道可以做得更好。

問題:

當用Qt小部件覆蓋QGLWidget(Qt OpenGL上下文視圖)時,Qt會在每個Qt幀之后重繪這些小部件。

Qt不是為了不斷重新繪制整個窗口> 60fps,所以速度非常慢。

我的點子:

讓Qt使用其他東西來繪制:透明紋理。 使OpenGL在重繪時使用此紋理,並將其繪制在其他所有內容之上。 使Qt將與OpenGL上下文視圖的所有交互重定向到繪制到紋理上的小部件。

優點是Qt只需要重新繪制(例如,懸停或點擊小部件,或文本字段中的文本光標閃爍),並且可以進行更快的部分重繪。

我的問題:

怎么解決這個問題? 我怎么能告訴Qt繪制紋理? 我如何將與窗口小部件的交互重定向到另一個窗口小部件(例如,如果我將鼠標移動到上下文視圖中區域上方,其中復選框位於繪制到紋理窗口小部件中,Qt應將此事件注冊到復選框並重新繪制以反映它的國家)

出於同樣的原因,我將2D和3D渲染分離為類似CAD的應用程序,盡管在我的情況下我的2D東西不是小部件 - 但它不應該有所作為。 這是如何處理問題:

  1. 當您的窗口小部件更改呈現為QGLFramebufferObject ,請通過在QGLWidget::paintEvent(..)使用FBO作為QPaintDevice來調用QPainter並調用myWidget->render( myQPainter, ...) 對於你有多少小部件重復此操作,但只對同一個FBO重復 - 不要為每個小部件創建一個FBO ...請記住先清除它,就像一個'普通'幀緩沖區。
  2. 當您的當前OpenGL背景更改時,使用標准OpenGL調用將其渲染到另一個QGLFramebufferObject ,方式相同。
  3. 創建一個通過頂點着色器的傳遞('相機'將只是一個單位立方體),以及一個非常簡單的片段着色器,可以將兩個紋理層疊在一起。
  4. QGLWidget::paintEvent(..)的末尾,激活着色器程序,將幀緩沖區綁定為紋理( myFBO->texture()獲取句柄),並渲染單位四元組。 因為您的相機是單位正方形,並且視口大小定義了FBO大小,所以它將完美填充視口像素。

然而,這是最簡單的部分......困難的部分是小部件交互。 因為您實際上是在渲染“代理”,所以您必須在“真實”和“代理”小部件之間傳遞交互,同時保持“真實”小部件不可見。 我將如何開始:

  • 有些操作系統是有點不可思議有關呈現小部件而沒有顯示,所以你可能要顯示,然后隱藏實例化后的小部件-因為Qt的聰明繪畫隊列中,它不可能真正使它的屏幕。
  • 捕獲視口中的所有鼠標事件,找出光標所在的“代理”窗口小部件(如果有),然后將其偏移以獲取“真實”隱藏窗口小部件的相對位置 - 此值將取決於父對象的內容'真實'小部件有,如果有的話。 然后將事件傳遞到“真實”窗口小部件,然后重新繪制窗口小部件幀緩沖區。

我應該聲明我還必須創建一個“標記”系統來很好地處理重繪。 您不希望每個窗口小部件事件觸發窗口小部件FBO重繪,因為可能有許多同時發生的事件(不要只考慮鼠標) - 但您只需要重繪一次。 所以我創建了一個系統,如果應用程序中的任何內容可以在視口中更改視口中的任何內容,那么它會將視口標記為“臟”。 然后為你想要的許多fps設置一個QTimer (在我的情況下,場景會變得非常沉重,所以我也計算了一個幀花了多長時間然后使用該值+ 10%作為下一次檢查的定時器延遲,這個當渲染變得遲鈍時系統不被轟炸的方式)。 然后檢查臟狀態:如果臟了,重繪; 否則不要。 我發現生活變得更容易有兩個臟標志,一個用於3D東西,一個用於2D - 但是如果你需要保持OpenGL繪圖的恆定繪制率,則可能不需要兩個。

我想我所做的並不是最簡單的方法,但它為調整和分析提供了充足的空間 - 從長遠來看,這使得生活更加輕松。 所有的答案絕對不是在這篇文章中,但希望它會讓你走上戰略的道路。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM