常見渲染管線整理與總結(jié)

圖形渲染管線是圖形渲染引擎物件繪制的流程邏輯叫榕,平時在工作過程中經(jīng)常會碰到各種跟管線相關(guān)的專業(yè)術(shù)語:前向渲染(Forward Rendering)玩裙,延遲渲染(Deferred Rendering),F(xiàn)orward+齿税, Forward Clustering等等彼硫,那么這些管線究竟對應(yīng)的是怎樣的工作流程,他們之間的優(yōu)劣以及應(yīng)用場景又是怎么樣的呢凌箕?為了解答這個問題拧篮,因此新開一篇文章,嘗試通過聚少成多的方式牵舱,一點點的匯總被業(yè)界所接受的各種渲染流程串绩,因為時間關(guān)系,文章可能不是一蹴而就的芜壁,會不定期更新礁凡。

為了統(tǒng)一敘述,下面的渲染管線名稱統(tǒng)一使用英文詞匯慧妄。

Forward Rendering

Forward Rendering就是俗稱的前向渲染管線顷牌,是最為傳統(tǒng)最為簡單的渲染管線,也是目前移動端上應(yīng)用最為廣泛的渲染管線腰涧。

所謂的前向渲染韧掩,就是將物件串成一個隊列,一個接一個的進行渲染窖铡,通常有兩種實現(xiàn)路徑疗锐,這兩種實現(xiàn)路徑都對應(yīng)于兩個嵌套的循環(huán),區(qū)別在于循環(huán)的主題順序有所不同费彼,按照Nvidia的說法滑臊,可以分別用Single-Pass Lighting與Multipass-Lighting對之進行區(qū)分,實現(xiàn)的偽代碼分別給出如下:

//Single-Pass Lighting
for obj in obj_list
  for light in light_list
    lighting(obj, light);

//Multi-Pass Lighting
for light in light_list
  for obj obj_list
    lighting(obj, light);

所謂的Single-Pass Lighting指的是影響物體的所有的光照一次性計算完畢箍铲,而Multi-Pass Lighting則是以Light作為循環(huán)主體雇卷,物件作為循環(huán)副體,分多次完成物體上光照的處理颠猴。

前向渲染管線實現(xiàn)思路比較簡潔关划,但是其缺陷也非常的明顯:

  1. 從上面的偽代碼我們知道,整個場景渲染時光照計算時間復(fù)雜度為MxN(M為物件數(shù)目翘瓮,N為動態(tài)光源數(shù)目)贮折,因此如果動態(tài)光源數(shù)目增加,場景渲染的效率就會直線下降资盅,因此通常會對場景中同時存在的動態(tài)光源數(shù)目進行限制筐带,在當前的硬件條件下剩燥,通常限制為4或者6。當然偽代碼里面給的算法都比較粗淺,有極大的優(yōu)化空間旺拉,比如Multi-Pass Lighting中赌莺,可以在CPU中挑出受某個光照影響的物件列表秃诵,副循環(huán)中只需要傳入這個物件列表而非所有物件列表降低渲染消耗。
  2. 如果不做特殊處理的話枢析,場景渲染的overdraw比較高。針對這個問題,有比較多的解決方案姐扮,比如使用大塊物件制作的HZB讹堤,以及將動態(tài)物件使用depth-only模式提前繪制一遍的Early-Z Cull算法等,都是通過增強剔除力度的方法來降低overdraw,不過這些方案本身也不是沒有消耗的瘾境,因此通常在使用的時候會需要在收支之間做一個平衡歧杏。

另外,從物件渲染順序來看迷守,前向渲染的渲染邏輯通常按照如下邏輯完成:

Opaque -> Translucent -> PostProcess

Deferred Rendering

延遲渲染Deferred Rendering管線的引出是為了解決前向渲染管線中光源數(shù)目過多時渲染效率低下的問題犬绒,簡單來說,延遲渲染通過兩個pass完成:

  1. Geometry Pass兑凿,完成物體的幾何數(shù)據(jù)處理凯力,將光照計算所需要的數(shù)據(jù)提取出來寫入到GBuffer中
  2. Lighting Pass,通過一個后處理對每盞光源所覆蓋的像素進行PS計算礼华,輸出結(jié)果到FrameBuffer中
Geometry Buffer

延遲渲染的優(yōu)點在于通過兩個pass極大的降低了Shading時候的Overdraw咐鹤,其缺點在于

  1. 具有較高的帶寬要求
  2. 透明物體的渲染需要額外的pass處理
  3. 不支持MSAA(帶寬進一步加劇)
  4. 只支持單一的Lighting Model圣絮。因為Shading Pass是通過渲染Light Geometry來完成的祈惶,而Light Geometry只能綁定一個Pixel Shader(不能為不同的Light Geometry綁定不同的Pixel Shader嗎?)扮匠,因而如果希望實現(xiàn)多個lighting model的話捧请,用延遲渲染就不合適了。

關(guān)于延遲渲染棒搜,此前已經(jīng)寫過一篇比較詳細的文章疹蛉,此處不再贅述,有需要的同學請自行移步帮非。

Tiled Deferred Shading

由于延遲渲染的實現(xiàn)需要較高的帶寬氧吐,而移動端在帶寬能力上嚴重不足,因此移動端常用的渲染管線是前向渲染末盔;而我們前面介紹過,前向渲染的缺點在于動態(tài)光源較多的時候座慰,場景負載較高陨舱,且由于較高的overdraw,所以如果不做特殊處理版仔,在移動端上的消耗還是非常高游盲,因此有人嘗試尋找一種性能更優(yōu)的解決方案。

延遲渲染的缺陷在于帶寬要求高蛮粮,那么一種非常直觀的思路就是益缎,能否將屏幕劃分成多個子區(qū)域,分塊進行渲染然想,這樣就能將每次渲染的帶寬需求降低了莺奔。乍一聽這個想法是一個餿主意,因為如果物件跨越多個區(qū)域的話变泄,可能就需要進行多次渲染令哟,但實際證明恼琼,只要框架設(shè)計的好,收益遠比付出高屏富,再加上硬件支持晴竞,這個方案很快就稱為移動端硬件的標配(這個方案最開始是Imagination Tech公司提出,簡稱TBDR狠半,應(yīng)用在蘋果的PowerVR芯片上噩死,后來陸續(xù)被其他Android芯片廠商跟進發(fā)展)。

Deferred Lighting

Deferred Lighting是與Deferred Shading名字非常相似的一種渲染管線神年,曾經(jīng)在CryEngine 3中被使用已维。Deferred Shading是將所有的著色處理都放到PostProcess階段完成,而這個步驟需要較多的輸入數(shù)據(jù)瘤袖,因此對于帶寬具有較高要求衣摩,而Deferred Lighting則是只將光照部分放到后處理階段完成(光照計算只需要提供對應(yīng)的法線數(shù)據(jù)與高光Power數(shù)據(jù)就已經(jīng)足夠),相對而言捂敌,所需要的輸入數(shù)據(jù)有所減少艾扮,因而可以降低帶寬的要求,提升渲染性能占婉。

通過對Deferred Shading進行分析泡嘴,發(fā)現(xiàn)G-buffer數(shù)據(jù)中Diffuse Color跟Specular Color占了很大一部分,而這部分是Lighting所不需要的數(shù)據(jù)逆济,因此考慮將Lighting單獨做延遲處理來降低帶寬消耗酌予,其基本實現(xiàn)步驟給出如下:

  1. 跟Deferred Shading一樣,經(jīng)過一個Geometry Pass奖慌,這個Pass輸出的數(shù)據(jù)只包含三項:
    1.1 Normal
    1.2 Specular Power
    1.3 Depth
    除了Depth之外抛虫,其余兩項可以共用一個RenderTarget(如果對發(fā)現(xiàn)進行壓縮的話,只需要三個通道即可)简僧。
  2. Lighting Pass建椰,對G-Buffer數(shù)據(jù)進行取用,計算各個輸入光源作用后的Lighting Accumulation Buffer
  3. 進行一遍額外的Geometry Pass岛马,使用Lighting Accumulation Buffer作為光照結(jié)果與Diffuse Color進行混合得到最終的輸出Color棉姐,由于已經(jīng)進行過一遍Geometry Pass,此時有此前的Depth Buffer的作用啦逆,這一個Geometry Pass可以節(jié)省大量的PS計算(相當于屏幕空間渲染)伞矩,效率非常高。

跟Deferred Shading一樣夏志,上述步驟只針對不透明物件乃坤,透明物件的渲染流程在不透明物件渲染完成之后,按照前向渲染完成。

這種方案相對于Deferred Shading而言侥袜,其優(yōu)點在于蝌诡,具有更小的帶寬要求。

Forward+

Forward+渲染管線也叫Tiled Fowrad Rendering枫吧,是AMD在EUROGRAPHICS 2012上首次提出的渲染管線浦旱,其實現(xiàn)也是通過3個Pass來完成,參考文獻[3]中給出了此方案的源碼與相應(yīng)的輸出結(jié)果九杂,下面介紹中的部分資源就來源于此:
1. Depth Pass
前面介紹過的Tiled Deferred Rendering第一遍Geometry Pass主要用于獲取Tiled G-Buffer數(shù)據(jù)颁湖,而這里的Depth Pass只是為了獲取屏幕空間的Depth數(shù)據(jù),方便下一步進行逐Tile的Light Culling例隆,也是為了避免后面Geometry Shading Pass的Overdraw甥捺。

Depth Pass

2. Light Culling Pass
眾所周知,前向渲染之所以慢镀层,就是因為每個像素需要考慮每盞燈光的影響镰禾,為了減少浪費,可以對每盞燈光影響的像素范圍進行計算唱逢,使得不受光照影響的像素無需考慮此盞燈光的輸入吴侦。

這里會將屏幕空間劃分成四方的Tile,Tile尺寸過大坞古,這個算法優(yōu)化幅度就非常有限备韧,而如果Tile尺寸過小就會導(dǎo)致Light Cull復(fù)雜度增加,都會導(dǎo)致效率的下降痪枫,一般來說织堂,此Tile可以跟移動端硬件劃分的Tile統(tǒng)一起來,最大程度保證渲染效率奶陈。

根據(jù)Tile Size以及上一步獲取到的Depth Buffer易阳,獲取每個Tile的Depth Extent,并根據(jù)每個Tile的Sub Frustum與Light的作用范圍計算出影響到當前Tile的Light List吃粒,整個過程可以通過Compute Shader完成闽烙,有Scatter跟Gather兩種實現(xiàn)方案,Gather方案中声搁,每個Tile可以通過一個Thread Group(每個Thread對應(yīng)于一個像素)來統(tǒng)計,輸出Tile的Depth Extent(即Min Depth與MAX Depth)捕发,之后進行Light與Sub Frustum的相交檢測時疏旨,也可以通過Thread Group來完成,并行進行多盞燈光的Cull處理扎酷。

AABB/Sphere Test精度問題
如果按照普通的Frustum Face Cull的方法處理Light對于Tile是否可見檐涝,可能會導(dǎo)致一些原本不可見的Light被識別成可見,從而導(dǎo)致Shading消耗增加,如下圖所示:

False Positive

黑色梯形表示的Frustum與點光作用范圍的藍色圓形谁榜,F(xiàn)rustum上下左右邊界都是與圓形相交的幅聘,因此會被錯誤的認為此Light對于Tile可見,這個問題Gareth Thomas在GDC 2015 的Advancements in Tiled-Based Compute Rendering中給出了解決方案:

Tile AABB Extended Size

如上圖所示窃植,由Min Z & MAX Z以及Tile的上下左右邊界構(gòu)成的Frustum帝蒿,其對應(yīng)的AABB由紅色虛線框表示,要判斷此Tile對于點光是否可見巷怜,只需要以AABB邊界為圓心葛超,以點光作用范圍為半徑外擴,得到的圓角方形與點光中心點進行相交檢測延塑,其算法實現(xiàn)如下圖所示:

Arvo Intersection Test

其實施結(jié)果對比如下圖所示:

Frustum/Sphere Test
Arvo AABB/Sphere Test

渲染效率大概有11%~14%的提升绣张。

min/max extent統(tǒng)計算法
此外,在統(tǒng)計Tile深度的Min/Max數(shù)據(jù)時关带,傳統(tǒng)的atomic min & max算法也可以通過Parallel Reduction算法來提升效率:

每個Tile的Frustum由Min/Max Depth來界定侥涵,而 一般來說Tile的Min/Max是通過atomic min & max操作計算得到的,tile中的每個像素對應(yīng)一個thread宋雏,但這種做法效率并不高芜飘,比如每個tile包含16個像素,那么就需要經(jīng)過15個比較來得到最終的結(jié)果好芭,在比較的結(jié)果時候燃箭,如果發(fā)現(xiàn)待寫入結(jié)果被鎖定,還需要進行等待舍败,但實際上這個處理過程可以分成多層完成:先將16個像素分成8對招狸,兩兩比較,之后將8個結(jié)果分成4對兩兩比較邻薯,最終比較次數(shù)為:8+4+2+1=15裙戏。雖然比較次數(shù)沒有減少,但是在比較的過程中不需要原子操作進行鎖定厕诡,因此效率會更高累榜。

min/max calculation
消耗對比

Depth Discontinuities問題
在某個Tile中如果存在較大的Depth Discontinuities,那么在進行光照剔除時可能會導(dǎo)致false positive灵嫌,即light對于此tile沒有貢獻壹罚,但是卻被包裹在了tile frustum中,如下圖所示:

對于這個問題寿羞,目前有較多的解決方案猖凛,如Harada在12年給出的2.5D culling算法通過將min/max范圍分割成更小的范圍,之后針對每個小范圍統(tǒng)計light 覆蓋區(qū)間與depth覆蓋區(qū)間绪穆,如下圖所示:

2.5D Culling

2.5D Culling方案的不足在于劃分較多會導(dǎo)致計算復(fù)雜度的線性增加辨泳,另一個方案則是GPU Pro 6中記載的HalfZ方案虱岂,此方案的目的不在于將false positive light移除,而在于將這種情況下的depth range一分為二菠红,上半部分與下半部分分別進行l(wèi)ight計算第岖,相對于原有實現(xiàn)方案,此方案復(fù)雜度并沒有過多增加试溯,但是在光照密度較高的情況下蔑滓,可以將單個tile中的light計算復(fù)雜度減半:

HalfZ

相對于HalfZ方案,GPU Pro 6還給出了另外一種更優(yōu)越的方案Modified HalfZ耍共,這種方案是在HalfZ的基礎(chǔ)上烫饼,進一步收縮兩個Depth Range的范圍(需要對Tile上的Depth Range進行兩次Depth Extent計算),保證收縮后的兩個Depth Range剛好包裹兩頭的Geometry Depth Range试读,如下圖所示:

Modified HalfZ

這幾種方案的性能對比如下圖所示:

Total Performance
Color Pass Performance
Culling Performance

可以看到杠纵,Modified HalfZ方案表現(xiàn)最佳,此外不同的Tile Size對于最終的實施性能也有比較顯著的影響:

16x16 VS 32x32 Tiles

在一定范圍內(nèi)钩骇,Tile尺寸較斜仍濉(32x32Tiles)時具有較高的性能,具體表現(xiàn)可能需要根據(jù)應(yīng)用進行單獨測試倘屹。

Light Culling

每個Tile Cull之后的Visible Light Indices被寫入到Shader Storage Buffer中银亲。

3. Geometry Shading Pass
這個Pass就是普通的Forward渲染Pass(需要注意,這里的物件不僅僅局限于不透明物件纽匙,透明物件也可以一起提交务蝠,不過如果需要提交透明物件的話,要保證絕對精確烛缔,前面Depth Pass可能需要將透明物件的深度寫入到Color Buffer中馏段;但如果不需要保證絕對精確,也可以直接使用不透明物件的深度進行光照剔除践瓷,之后將光照應(yīng)用到所有物件上院喜,其結(jié)果可能會有部分光源損失),與普通Forward Pass不同的是晕翠,這里每個pixel在執(zhí)行PS的時候不是針對所有l(wèi)ight進行遍歷計算喷舀,而是計算當前像素所歸屬的Tile,之后獲取Tile中的Light列表淋肾,在這個上面進行光照計算硫麻。

Final Output

這里給出了Forward+與Deferred Rendering方案的性能對比,可以看到樊卓,雖然增加了一個Pass庶香,但實際上其渲染性能要優(yōu)于Deferred Rendering(這個優(yōu)化應(yīng)該是來源于Light Culling)

Forward+ VS Deferred

下面列出兩者分階段的耗時對比,中間的‘<’表示優(yōu)化简识,‘<<’表示大幅優(yōu)化:


Time Consumption Comparison

Clustered Forward Rendering

Forward+是在屏幕空間中劃分Tile進行光源過濾來降低消耗的赶掖,這個劃分是在XY 2D平面進行的,而Clustered Forward Rendering則是在這個基礎(chǔ)上更進一步七扰,在Depth方向上也同樣進行一次劃分奢赂,進一步縮小光照的影響范圍,降低光照計算的浪費颈走。因為劃分的結(jié)果是3D的Frustum膳灶,每個Frustum被稱為一個Cluster,這就是Cluster的由來立由。

為什么要在Depth方向上進行劃分轧钓?
在部分場景中,渲染的距離比較廣锐膜,在局部光源比較密集的情況下毕箍,單個Tile中可能存在著較多的光源,這些光源在深度范圍上比較分散道盏,如果使用Forward+ Rendering管線而柑,會存在較大的浪費,因此考慮在深度方向上增加一維劃分荷逞,希望通過這種方式降低光照計算的消耗媒咳。

在Depth方向上的劃分具體是如何實施的?
在Depth方向上的劃分并不是線性的(指數(shù)劃分)种远,各個Cluster在Depth方向上的劃分是對齊的(是否可以考慮非對齊劃分涩澡?可以仿照Forward+,先通過一個Depth Pass獲取各個Tile上的深度范圍坠敷,之后在此范圍上進行劃分)

Cluster Split

為什么Depth上不做線性劃分妙同?
由于透視相機的作用,需要保留更多近處細節(jié)常拓,導(dǎo)致近大遠小渐溶,如果按照線性劃分,性價比可能會有所下降弄抬。

整個實現(xiàn)過程如果做成與Forward+類似茎辐,那么就同樣需要分成三個Pass:

  1. Depth Pass,用于實現(xiàn)Cluster劃分與Overdraw過濾
  2. Cluster Filling掂恕,通過Compute Shader完成(需要三個Pass)拖陆,輸出Lighting List Info
    Subpass1:統(tǒng)計影響各個Cluster的Light數(shù)目

Subpass2:根據(jù)上一個subpass的結(jié)果,計算當前Cluster對應(yīng)的Light在Light Indices數(shù)組中的起始位置

Subpass3:填充Light Indices數(shù)組懊亡,數(shù)組中存儲的是影響各個Cluster的Light在全局Light Info數(shù)組中的索引

  1. Shading Pass依啰,逐Cluster渲染Geometry,進行Shading處理店枣。

除了上述實現(xiàn)方案之外速警,也可以用不同于Forward+的實現(xiàn)方案來完成叹誉,我們說過,Cluster的劃分是規(guī)則的闷旧,也就是不需要任何的Depth信息长豁,就可以完成,那么就不必像Forward+一樣忙灼,使用Depth Pass來一遍強制的Early-Z匠襟,如果沿著這種思路,那么實現(xiàn)方案需要2個Pass(其實私下里認為该园,還是在前面加一個Depth Pass效果更好酸舍,可以避免大量的Overdraw):

  1. Cluster Filling Pass,跟上面的Pass2一樣里初,填充各個Cluster的光照信息
  2. Shading Pass啃勉,不需要逐Cluster進行,而是全場景一遍Geometry Shading青瀑,在PS中根據(jù)Pixel Depth恢復(fù)期世界坐標璧亮,并進而找到對應(yīng)的Cluster,之后使用Cluster對應(yīng)的Lighting數(shù)據(jù)進行光照處理斥难。

具體性能表現(xiàn)又是如何的枝嘶?
‘Detroit: Become Human’ 方案只給出了在主機上的時間消耗,沒有給出與其他方案的對比數(shù)據(jù):

Performance

Avalanche Studios的Emil Persson在Siggraph 13上分享的Clustered Forward Rendering方案與Deferred Rendering方案的性能對比(如果有與Forward+的性能對比就好了):

參考文獻

1. 游戲引擎中的光照算法 - 知乎fengliancanxue
2. Deferred Shading VS Deferred Lighting
3. Forward+ Renderer
4. Forward+ (EUROGRAPHICS 2012) Slides
5. Clustered Forward Rendering and Anti-Aliasing in ‘Detroit: Become Human’ - GDC 2018
6. Practical Clustered Shading - Emi Persson - Siggraph 13
7. Advancements in Tiled-Based Compute Rendering

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哑诊,一起剝皮案震驚了整個濱河市群扶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌镀裤,老刑警劉巖竞阐,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異暑劝,居然都是意外死亡骆莹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門担猛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幕垦,“玉大人,你說我怎么就攤上這事傅联∠雀模” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵蒸走,是天一觀的道長仇奶。 經(jīng)常有香客問我,道長比驻,這世上最難降的妖魔是什么该溯? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任岛抄,我火速辦了婚禮,結(jié)果婚禮上朗伶,老公的妹妹穿的比我還像新娘弦撩。我一直安慰自己,他們只是感情好论皆,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著猾漫,像睡著了一般点晴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悯周,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天粒督,我揣著相機與錄音,去河邊找鬼禽翼。 笑死屠橄,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的闰挡。 我是一名探鬼主播锐墙,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼长酗!你這毒婦竟也來了溪北?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤夺脾,失蹤者是張志新(化名)和其女友劉穎之拨,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咧叭,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蚀乔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了菲茬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吉挣。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖生均,靈堂內(nèi)的尸體忽然破棺而出听想,到底是詐尸還是另有隱情,我是刑警寧澤马胧,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布汉买,位于F島的核電站,受9級特大地震影響佩脊,放射性物質(zhì)發(fā)生泄漏蛙粘。R本人自食惡果不足惜垫卤,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一右莱、第九天 我趴在偏房一處隱蔽的房頂上張望胯甩。 院中可真熱鬧合蔽,春花似錦悟衩、人聲如沸但两。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坟漱。三九已至伯复,卻和暖如春慨代,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啸如。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工侍匙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叮雳。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓想暗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帘不。 傳聞我的和親對象是個殘疾皇子说莫,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345