OpenGL/OpenGL ES入門(mén):紋理初探 - 常用API解析

系列推薦文章:
OpenGL/OpenGL ES入門(mén):圖形API以及專業(yè)名詞解析
OpenGL/OpenGL ES入門(mén):渲染流程以及固定存儲(chǔ)著色器
OpenGL/OpenGL ES入門(mén):圖像渲染實(shí)現(xiàn)以及渲染問(wèn)題
OpenGL/OpenGL ES入門(mén):基礎(chǔ)變換 - 初識(shí)向量/矩陣
OpenGL/OpenGL ES入門(mén):紋理初探 - 常用API解析
OpenGL/OpenGL ES入門(mén): 紋理應(yīng)用 - 紋理坐標(biāo)及案例解析(金字塔)

什么是紋理

在之前的幾片文章中恕曲,已經(jīng)對(duì)點(diǎn)剔难、線和三角形進(jìn)行了渲染晨另,也看到了如何通過(guò)計(jì)算顏色值對(duì)它們進(jìn)行著色,以及在它們之間進(jìn)行值操作來(lái)模擬光照效果翩隧。為了能夠達(dá)到更加真實(shí)的效果,這一篇引入紋理貼圖。

紋理只是一種能夠應(yīng)用到場(chǎng)景中的三角形上的圖像數(shù)據(jù)痰催,它通過(guò)經(jīng)過(guò)過(guò)濾的紋理單元(texel,相當(dāng)于基于紋理的像素)填充到實(shí)心區(qū)域己英。

初識(shí)紋理的小伙伴們可以理解為间螟,紋理就是圖片。當(dāng)然紋理遠(yuǎn)遠(yuǎn)不止是圖像數(shù)據(jù)這么簡(jiǎn)單损肛,它是大多數(shù)現(xiàn)代3D渲染算法的一個(gè)關(guān)鍵因素厢破。這里只做簡(jiǎn)單了解。

像素

像素包裝

圖像數(shù)據(jù)在內(nèi)存中很少以緊密包裝的形式存在治拿。在許多硬件平臺(tái)上摩泪,處于性能考慮,一幅圖像的每一行都應(yīng)該從一種特定的字節(jié)對(duì)齊地址開(kāi)始劫谅。絕大多數(shù)編譯器會(huì)自動(dòng)把變量和緩沖區(qū)放置在一個(gè)針對(duì)該架構(gòu)對(duì)齊優(yōu)化的地址上见坑。

默認(rèn)情況下嚷掠,OpenGL采用4個(gè)字節(jié)的對(duì)齊方式,這種方式適合于很多目前正在使用時(shí)的系統(tǒng)荞驴。

下面這個(gè)句話引用來(lái)自《OpenGL超級(jí)寶典》(第5版)
很多程序員會(huì)簡(jiǎn)單地將圖像寬度值乘以高度值不皆,在乘以每個(gè)像素的字節(jié)數(shù),這樣就錯(cuò)誤地判斷一個(gè)圖像所需的存儲(chǔ)器數(shù)量熊楼。
例如:一幅RGB圖像霹娄,包含3個(gè)分量,每個(gè)分類都存儲(chǔ)在一個(gè)字節(jié)中(每個(gè)顏色通道8位)鲫骗,如果圖像的寬度為199個(gè)像素犬耻,那么圖像的每一行需要多少存儲(chǔ)空間呢?
按照上面的算法來(lái)計(jì)算:199*3 = 597字節(jié)
這樣也許是對(duì)的执泰,但是作為優(yōu)秀的程序員枕磁,可能會(huì)討厭這個(gè)數(shù)字。如果硬件本身的體系結(jié)構(gòu)是4字節(jié)排列(大部分是這樣的)坦胶,那么圖像每一行的末尾都將有額外的3個(gè)空字節(jié)進(jìn)行填充(每一行600字節(jié))透典,而這是為了使每一行的存儲(chǔ)器地址從一個(gè)能夠被4整除的地址開(kāi)始。

許多未經(jīng)壓縮的圖像文件格式也遵循這種慣例顿苇,然而Targa(.TGA)文件格式則是1個(gè)字節(jié)排列的峭咒,這樣不會(huì)浪費(fèi)空間。為什么內(nèi)存分配意圖對(duì)于OpenGL來(lái)說(shuō)這么重要纪岁?

因?yàn)樵谖覀兿?code>OpenGL提交圖像數(shù)據(jù)或從OpenGL獲取圖像數(shù)據(jù)時(shí)凑队,OpenGL需要知道我們想要在內(nèi)存中對(duì)數(shù)據(jù)進(jìn)行怎樣的包裝或解包裝操作。

認(rèn)識(shí)一下下面幾個(gè)函數(shù):

// 改變像素存儲(chǔ)方式
glPixelStorei(GLenum pname, GLint param);

// 恢復(fù)像素存儲(chǔ)值方式
glPixelStoref(GLenum pname, GLint param);

// 如果我們想要改成緊密包裝像素?cái)?shù)據(jù)幔翰,應(yīng)該像下面這樣調(diào)用函數(shù)
/*
參數(shù)1: 指定OpenGL如何從數(shù)據(jù)緩沖區(qū)中解包圖像數(shù)據(jù)
參數(shù)2: 允許設(shè)置1(byte排列)漩氨、2(排列為偶數(shù)byte的行)、4(字word排列)遗增、8(行從雙字節(jié)邊界開(kāi)始)
*/
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

像素圖

像素圖在內(nèi)存布局上與位圖非常相似叫惊,但是每個(gè)像素將需要一個(gè)以上的存儲(chǔ)位來(lái)表示。每個(gè)像素的附加位允許存儲(chǔ)強(qiáng)度(亮度)或者顏色分量值做修。

OpenGL中霍狰,可以使用下面的函數(shù)將顏色緩沖區(qū)的內(nèi)容作為像素圖直接讀取。

// 將顏色緩沖區(qū)的內(nèi)容作為像素圖直接讀取
/*
參數(shù)1&參數(shù)2: x饰及,y矩形左下角的窗口坐標(biāo)
參數(shù)3&參數(shù)4: width蔗坯,height矩形的寬高,以像素為單位
參數(shù)5: 像素格式
參數(shù)6: 解釋參數(shù)pixels指向的數(shù)據(jù)燎含,告訴OpenGL使用緩沖區(qū)中的什么數(shù)據(jù)類型來(lái)存儲(chǔ)顏色分量宾濒,像素?cái)?shù)據(jù)的數(shù)據(jù)類型
參數(shù)7: pixels,指向圖像數(shù)據(jù)的指針
*/
glReadPixel(GLint x, GLint y, GLSizei width, GLSizei height, GLenum format, GLenum type, const void *pixels);

/*
模式參數(shù):GL_FRONT屏箍、GL_BACK绘梦、GL_LEFT橘忱、GL_RIGHT、GL_FRONT_LEFT谚咬、
GL_FRONT_RIGHT鹦付、GL_BACK_LEFT、GL_BACK_RIGHT或者甚至是GL_NONE中的任意一個(gè)
*/
// 指定讀取的緩存
glReadBuffer(mode);
// 指定寫(xiě)入的緩存
glWriteBuffer(mode);
像素格式表
像素?cái)?shù)據(jù)的數(shù)據(jù)類型

讀取像素

Targa圖像格式是一種方便而且容易使用的圖像格式择卦,并且它既支持簡(jiǎn)單顏色圖像敲长,也支持帶有Alpha值的圖像。后面篇幅中一致使用這種格式來(lái)進(jìn)行紋理操作秉继。

/*
參數(shù)1: 將要載入的Targa文件的文件名
參數(shù)2: 文件寬度地址
參數(shù)3: 文件高度地址
參數(shù)4: 文件數(shù)據(jù)格式地址
參數(shù)5: 文件格式地址
返回值: 如果函數(shù)調(diào)用成功祈噪,返回一個(gè)新定位到直接從文件中讀取的圖像數(shù)據(jù)的指針,否則返回NULL
*/
GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat);

載入紋理

在幾何圖形中應(yīng)用貼圖時(shí)尚辑,第一個(gè)必要步驟就是將紋理載入內(nèi)存辑鲤。一旦被載入,這些紋理就會(huì)成為當(dāng)前紋理狀態(tài)的一部分杠茬。

/*
參數(shù)1: GL_TEXTURE_1D月褥、GL_TEXTURE_2D、GL_TEXTURE_3D
參數(shù)2: 指定這個(gè)函數(shù)所加載的mip貼圖層次瓢喉,默認(rèn)設(shè)為0
參數(shù)3: 每個(gè)紋理單元存儲(chǔ)多少顏色成分(從讀取像素圖時(shí)獲得)
參數(shù)4: width宁赤、height、depth指加載紋理的寬度栓票、高度决左、深度
參數(shù)5: 允許為紋理貼圖指定一個(gè)邊界寬度,目前來(lái)說(shuō)走贪,設(shè)置為0
參數(shù)6: OpenGL 數(shù)據(jù)存儲(chǔ)方式佛猛,一般使用GL_UNSIGNED_BYTE
參數(shù)7: 圖片數(shù)據(jù)指針
*/
void glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, void *data);

void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data);

void glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, void *data);

使用顏色緩沖區(qū)

一維和二維紋理也可以從顏色緩沖區(qū)加載數(shù)據(jù)∽菇疲可以從顏色緩沖區(qū)讀取一幅圖像继找,并通過(guò)下面的函數(shù)將它作為一個(gè)新紋理使用

void glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);

void glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);

這兩個(gè)函數(shù)的操作類似glTexImage,但是這里xy在顏色緩沖區(qū)中指定了開(kāi)始讀取紋理數(shù)據(jù)的位置逃沿。源緩沖區(qū)時(shí)通過(guò)glReadBuffer函數(shù)設(shè)置的码荔。請(qǐng)注意,并不存在glCopyTexImage3D感挥,因?yàn)槲覀儫o(wú)法從2D顏色緩沖區(qū)獲取體積數(shù)據(jù)。

更新紋理

在時(shí)間敏感的場(chǎng)合如游戲或模擬應(yīng)用程序中越败,重復(fù)加載新紋理可能會(huì)成為性能瓶頸触幼。
如果我們不再需要某個(gè)已加載的紋理,它可以被全部替換究飞,也可以被替換掉一部分置谦。替換一個(gè)紋理圖像常常要比直接使用glTexImage重新加載一個(gè)新紋理快的多堂鲤。函數(shù)代碼如下

void glTexSubImage1D(GLenum target, GLint level, 
                    GLint xOffset, 
                    GLsizei width, 
                    GLenum format, GLenum type, const GLvoid *data);
                    
void glTexSubImage2D(GLenum target, GLint level, 
                    GLint xOffset, GLint yOffset, 
                    GLsizei width, GLsizei height,
                    GLenum format, GLenum type, const GLvoid *data);
                    
void glTexSubImage3D(GLenum target, GLint level, 
                    GLint xOffset, GLint yOffset, GLint zOffset,
                    GLsizei width, GLsizei height, GLsizei depth,
                    GLenum format, GLenum type, const GLvoid *data);

上面函數(shù)絕大部分參數(shù)都與glTexImage函數(shù)所使用的參數(shù)準(zhǔn)確對(duì)應(yīng)。xOffset媒峡、yOffset瘟栖、zOffset參數(shù)指定了在原來(lái)的紋理貼圖中開(kāi)始替換紋理數(shù)據(jù)的偏移量。width谅阿、height半哟、depth參數(shù)指定了“插入”到原來(lái)那個(gè)紋理中的新紋理的寬度、高度和深度签餐。

而下面一組函數(shù)允許我們從顏色緩沖區(qū)讀取紋理寓涨,并插入或替換原來(lái)紋理的一部分,都是glCopyTexSubImage函數(shù)的變型氯檐。

void glCopyTexSubImage1D(GLenum target, GLint level, 
                    GLint xOffset, 
                    GLint x, GLint y, 
                    GLsizei width);
                    
void glCopyTexSubImage2D(GLenum target, GLint level, 
                    GLint xOffset, GLint yOffset
                    GLint x, GLint y, 
                    GLsizei width, GLsizei height);
                    
void glCopyTexSubImage1D(GLenum target, GLint level, 
                    GLint xOffset, GLint yOffset, GLint zOffset,
                    GLint x, GLint y, 
                    GLsizei width, GLsizei height);

前面說(shuō)到戒良,不存在一種對(duì)應(yīng)方法來(lái)將一幅2D彩色圖像作為一個(gè)3D紋理的來(lái)源。但是冠摄,我們可以使用glCopyTexSubImage3D函數(shù)糯崎,在一個(gè)三維紋理中使用顏色緩沖區(qū)的數(shù)據(jù)來(lái)設(shè)置它的一個(gè)紋理單元平面。

紋理對(duì)象

紋理對(duì)象允許我們一次加載一個(gè)以上紋理狀態(tài)(包含紋理圖像)河泳。以及在它們之間進(jìn)行快速切換沃呢。紋理狀態(tài)是由當(dāng)前綁定的紋理對(duì)象維護(hù)的。而紋理對(duì)象時(shí)一個(gè)無(wú)符號(hào)整數(shù)標(biāo)識(shí)的乔询。

//使用函數(shù)分配紋理對(duì)象
//指定紋理對(duì)象的數(shù)量 和 指針(指針指向一個(gè)無(wú)符號(hào)整形數(shù)組樟插,由紋理對(duì)象標(biāo)識(shí)符填充)。
void glGenTextures(GLsizei n, GLuint *textTures);

//綁定紋理狀態(tài)
//參數(shù)1: GL_TEXTURE_1D竿刁、GL_TEXTURE_2D黄锤、GL_TEXTURE_3D
//參數(shù)2: 需要綁定的紋理對(duì)象
void glBindTexture(GLenum target, GLunit texture);

//刪除綁定紋理對(duì)象
//紋理對(duì)象 以及 紋理對(duì)象指針(指針指向一個(gè)無(wú)符號(hào)整形數(shù)組,由紋理對(duì)象標(biāo)識(shí)符填充)食拜。
void glDeleteTextures(GLsizei n, GLuint *textures);

//測(cè)試紋理對(duì)象是否有效
//如果texture是一個(gè)已經(jīng)分配空間的紋理對(duì)象鸵熟,那么這個(gè)函數(shù)會(huì)返回GL_TRUE,否則會(huì)返回GL_FALSE。
GLboolean glIsTexture(GLuint texture);

紋理參數(shù)設(shè)置

和將一幅圖片貼在三角形的一面相比负甸,紋理貼圖需要更多的工作流强,很多參數(shù)的應(yīng)用都會(huì)影響渲染的規(guī)則和紋理貼圖的行為。這些紋理參數(shù)都是通過(guò)glTexParameter函數(shù)的變量來(lái)進(jìn)行設(shè)置的呻待。

/*
參數(shù)1: target,指定這些參數(shù)將要應(yīng)用在那個(gè)紋理模式上打月,比如GL_TEXTURE_1D、GL_TEXTURE_2D蚕捉、GL_TEXTURE_3D奏篙。
參數(shù)2: pname,指定需要設(shè)置那個(gè)紋理參數(shù)
參數(shù)3: param,設(shè)定特定的紋理參數(shù)的值
*/
glTexParameterf(GLenum target, GLenum pname, GLFloat param);
glTexParameteri(GLenum target, GLenum pname, GLint param);
glTexParameterfv(GLenum target, GLenum pname, GLFloat *param);
glTexParameteriv(GLenum target, GLenum pname, GLint *param);

基本過(guò)濾

根據(jù)一個(gè)拉伸或收縮的紋理貼圖計(jì)算顏色片段的過(guò)程稱為紋理過(guò)濾

使用OpenGL的紋理參數(shù)函數(shù),可以同時(shí)設(shè)置放大和縮小過(guò)濾器秘通。參數(shù)名為:GL_TEXTURE_MAG_FILTERGL_TEXTURE_MIN_FILTER为严。

就目前來(lái)說(shuō),可以認(rèn)為它們從兩種基本的紋理過(guò)濾器:最鄰近過(guò)濾(GL_NEAREST)和線性過(guò)濾(GL_LINEAR)中選擇肺稀。

最鄰近過(guò)濾: 最為顯著的特征就是當(dāng)紋理被拉伸到特別大時(shí)第股,所出現(xiàn)的大片斑駁像素。它是我們能夠選擇的最簡(jiǎn)單话原、最快速的過(guò)濾方法夕吻。

線性過(guò)濾: 最為顯著的特征就是當(dāng)紋理被拉伸時(shí),所出現(xiàn)的“失真”圖形稿静,但是梭冠,和最鄰近過(guò)濾模式下所呈現(xiàn)的斑駁狀像素塊相比較,這種“失真”更接近事實(shí)改备。

image
/*
參數(shù)1: 紋理維度
參數(shù)2: 放大&縮小過(guò)濾器
參數(shù)3: 環(huán)繞模式
*/
// 為放大和縮小過(guò)濾器設(shè)置紋理過(guò)濾器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEARST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEARST);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

通過(guò)下面的圖片可以比較一下兩種過(guò)濾的區(qū)別:

image

紋理環(huán)繞

在正常情況下控漠,是在0.0到1.0的范圍之內(nèi)指定紋理坐標(biāo),使它與紋理貼圖中的紋理單元形成映射關(guān)系悬钳。如果紋理坐標(biāo)落在這個(gè)范圍之外盐捷,OpenGL則根據(jù)當(dāng)前紋理環(huán)繞模式處理這個(gè)問(wèn)題。

調(diào)用glTexParameter函數(shù)(并分別使用GL_TEXTURE_WRAP_S默勾、GL_TEXTURE_WRAP_T或GL_TEXTURE_WRAP_R做參數(shù))碉渡,為每個(gè)坐標(biāo)分別設(shè)置環(huán)繞模式。

/*
參數(shù)1: 紋理維度 GL_TEXTURE_1D母剥、GL_TEXTURE_2D滞诺、GL_TEXTURE_3D
參數(shù)2: GL_TEXTURE_WRAP_S、GL_TEXTURE_T环疼、GL_TEXTURE_R习霹,針對(duì)s,t,r坐標(biāo)
參數(shù)3: 環(huán)繞方式
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
image
image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市炫隶,隨后出現(xiàn)的幾起案子淋叶,更是在濱河造成了極大的恐慌,老刑警劉巖伪阶,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煞檩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡栅贴,警方通過(guò)查閱死者的電腦和手機(jī)斟湃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)檐薯,“玉大人桐早,你說(shuō)我怎么就攤上這事。” “怎么了哄酝?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)祷膳。 經(jīng)常有香客問(wèn)我陶衅,道長(zhǎng),這世上最難降的妖魔是什么直晨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任搀军,我火速辦了婚禮,結(jié)果婚禮上勇皇,老公的妹妹穿的比我還像新娘罩句。我一直安慰自己,他們只是感情好敛摘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布门烂。 她就那樣靜靜地躺著,像睡著了一般兄淫。 火紅的嫁衣襯著肌膚如雪屯远。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天捕虽,我揣著相機(jī)與錄音慨丐,去河邊找鬼。 笑死泄私,一個(gè)胖子當(dāng)著我的面吹牛房揭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晌端,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼捅暴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了斩松?” 一聲冷哼從身側(cè)響起伶唯,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惧盹,沒(méi)想到半個(gè)月后乳幸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钧椰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年粹断,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫡霞。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓶埋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情养筒,我是刑警寧澤曾撤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站晕粪,受9級(jí)特大地震影響挤悉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巫湘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一装悲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尚氛,春花似錦诀诊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至奈懒,卻和暖如春奠涌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磷杏。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工溜畅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人极祸。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓慈格,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親遥金。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浴捆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容