初識:頂點緩沖對象VBO,幀緩沖對象FBO炊苫,正交投影【矩陣】在Android中的使用

一. 什么是VBO裁厅,它是用來做什么的。

  1. VBO: Vertex Buffer Object 【頂點緩沖類】

  2. 為什么要用VBO?
    不使用VBO時侨艾,我們每次繪制( glDrawArrays )圖形時都是從本地內(nèi)存處獲取頂點數(shù)據(jù)然后傳輸給OpenGL來繪制执虹,這樣就會頻繁的操作CPU->GPU增大開銷,從而降低效率唠梨。
    使用VBO袋励,我們就能把頂點數(shù)據(jù)緩存到GPU開辟的一段內(nèi)存中,然后使用時不必再從本地獲取当叭,而是直接從顯存中獲取茬故,這樣就能提升繪制的效率。

  3. 在Android中創(chuàng)建VBO

(a). 創(chuàng)建VBO: GLES20.glGenBuffers(1, vbos, 0);

(b). 綁定VBO:GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbos[0]);

(c). 分配VBO需要的緩存大幸媳睢:
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertex.length * 4,null, GLES20. GL_STATIC_DRAW);

(d). 為VBO設(shè)置頂點數(shù)據(jù)的值:
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);

(e). 解綁VBO:
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

  1. 在Android中使用VBO

(a). 綁定VBO:
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbos[0]);

(b). 設(shè)置頂點數(shù)據(jù):
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0);

(c).解綁VBO:
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

二. 什么是FBO磺芭,它是用來做什么的。

  1. FBO: Frame Buffer object 【幀緩沖對象】

  2. 為什么要用FBO?
    當(dāng)我們需要對紋理進行多次渲染采樣時醉箕,而這些渲染采樣是不需要展示給用戶看的钾腺,所以我們就可以用一個單獨的緩沖對象(離屏渲染)來存儲我們的這幾次渲染采樣的結(jié)果徙垫,等處理完后才顯示到窗口上。

  3. 優(yōu)勢
    提高渲染效率放棒,避免閃屏姻报,可以很方便的實現(xiàn)紋理共享等。

  4. 渲染方式
    渲染到緩沖區(qū)(Render)- 深度測試和模板測試
    渲染到紋理(Texture)- 圖像渲染

  5. FBO大體工作過程


    FBO工作過程.png
  6. 紋理坐標(biāo)系與FBO坐標(biāo)系比較


    坐標(biāo)系比較.jpg
  7. 在Android中創(chuàng)建FBO

(a).創(chuàng)建FBO
GLES20.glGenBuffers(1, fbos, 0);

(b).綁定FBO
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbos[0]);

(c).設(shè)置FBO分配內(nèi)存大小
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 720, 1280, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

(d).把紋理綁定到FBO
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureid, 0);

(e).檢查FBO綁定是否成功GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE)

(f).解綁FBO GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

  1. 在Android中使用FBO

(1)间螟、綁定FBO
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbos[0]);

(2)吴旋、獲取需要繪制的圖片紋理,然后繪制渲染

(3)厢破、解綁FBO
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

(4)荣瑟、再把綁定到FBO的紋理繪制渲染出來

三. 正交投影,它是用來做什么的

存在問題.png

解決方法.png

上面我們得到的( 溉奕?)是不在歸一化坐標(biāo)范圍內(nèi)的,為了能使OpenGL正確的渲染忍啤,我們就需要把(加勤?)以及其他邊統(tǒng)一轉(zhuǎn)換到歸一化坐標(biāo)內(nèi),這個操作就是正交投影同波。

使用正交投影鳄梅,不管物體多遠多近,物體看起來總是形狀未檩、大小相同的戴尸。

1.Android中使用正交投影矩陣
在OpenGL中就需要用到矩形來改變頂點坐標(biāo)的范圍,最后再歸一化就可以了冤狡。
(A)孙蒙、頂點著色器中添加矩陣

attribute vec4 v_Position;
attribute vec2 f_Position;
varying vec2 ft_Position;
uniform mat4 u_Matrix;
void main() {
    ft_Position = f_Position;
    gl_Position = v_Position * u_Matrix;
}

(B)、然后根據(jù)圖形寬高和屏幕寬高計算(悲雳?)的長度
orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)

Matrix.orthoM(matrix, 0, -width / ((height / 702f * 526f)),  width / ((height / 702f * 526f)), -1f, 1f, -1f, 1f);
Matrix.orthoM(matrix, 0, -1, 1, - height / ((width / 526f * 702f)),  height / ((width / 526f * 702f)), -1f, 1f);

(C)挎峦、使用
GLES20.glUniformMatrix4fv(umatrix, 1, false, matrix, 0);

四.代碼樣例如下:

package app.antony.vfmdemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * OpenGL 數(shù)字: 【使用Opengl的大體步驟】
 * t 數(shù)字:  【使用紋理的大體步驟】
 * v 數(shù)字: 【使用VBO的大體步驟】
 * f 數(shù)字: 【使用FBO的大體步驟】
 * m 數(shù)字: 【使用正交投影矩陣大體步驟】
 */
public class OpenGLRender implements GLSurfaceView.Renderer {

    private Context mContext;
    //頂點坐標(biāo)系(-1, -1) (1, -1)  (-1, 1)  (1, 1)
    private float[] vertexData = {
            -1f, -1f,
            1f, -1f,
            -1f, 1f,
            1f, 1f
    };

    //紋理坐標(biāo)系
    private float[] fragmentData = {
//            0f, 0f,
//            1f, 0f,
//            0f, 1f,
//            1f, 1f
            0f, 1f,
            1f, 1f,
            0f, 0f,
            1f, 0f
    };
    private FloatBuffer vertexBuffer; //頂點buffer
    private FloatBuffer fragmentBuffer; //紋理buffer

    private int program; //渲染源程序
    private int vPosition; //頂點位置
    private int fPosition; //紋理位置
    private int textureId; //紋理的ID 【FBO會跟它進行綁定】
    private int sampler; //紋理采樣

    private int vboId;// 保存VBO
    private int fboId;// 保存FBO

    private int uMatrix; //矩陣
    private float[] matrix = new float[16]; //正交投影使用


    private int imgTextureId; //紋理的ID,這個是我們要渲染的紋理【一張圖片】
    private FboRender fboRender;

    OpenGLRender(Context context) {
        this.mContext = context;
        fboRender = new FboRender(context);
        //為頂點坐標(biāo) 分配本地內(nèi)存地址
        //為什么要分配本地內(nèi)存地址呢合瓢? 因為Opengl取頂點的時候坦胶,每一次都到內(nèi)存中去取值,
        // 所以這個內(nèi)存在運行過程中是不允許被java虛擬機GC回收的晴楔,我們就要把它搞成本地(底層)不受虛擬機控制的這種頂點
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4) //分配內(nèi)存大卸傥(分配了32個字節(jié)長度)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        vertexBuffer.position(0);

        fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(fragmentData);
        fragmentBuffer.position(0);
    }


    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        fboRender.onFboCreate(); //離屏渲染的Render(自定義的)
        //以字符串的形式 加載出 頂點shader 和 紋理shader
        String vertexSource = ShaderUtil.getRawResource(mContext, R.raw.vertex_shader_matrix);
        String fragmentSource = ShaderUtil.getRawResource(mContext, R.raw.fragment_shader);
        //創(chuàng)建源程序
        program = ShaderUtil.createProgram(vertexSource, fragmentSource);

        // OpenGL 7.得到著色器中的屬性  todo:我們就從源程序中獲取他的屬性了
        vPosition = GLES20.glGetAttribLocation(program, "av_Position"); //頂點的向量坐標(biāo) todo:一定要跟vertex_shader.glsl中的變量對應(yīng)上
        fPosition = GLES20.glGetAttribLocation(program, "af_Position"); //紋理的向量坐標(biāo)
        sampler = GLES20.glGetUniformLocation(program, "sTexture"); // uniform sampler2D sTexture
        uMatrix = GLES20.glGetUniformLocation(program, "u_Matrix"); // uniform mat4 u_Matrix

        //v1. 創(chuàng)建VBO 【Vertex Buffer Object 頂點緩存類】
        int[] vbos = new int[1];
        GLES20.glGenBuffers(1, vbos, 0);
        //v2. 綁定VBO
        vboId = vbos[0];
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
        //v3. 分配VBO需要的緩存大小:頂點坐標(biāo)數(shù)據(jù)長度 + 紋理坐標(biāo)數(shù)據(jù)長度【data=null 表示只分配了空間,并沒有放入數(shù)據(jù)】
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + fragmentData.length * 4, null, GLES20.GL_STATIC_DRAW);
        //v4. 為VBO設(shè)置坐標(biāo)點數(shù)據(jù)的值
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);//坐標(biāo)頂點賦值
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4, fragmentBuffer);//紋理坐標(biāo)點賦值
        //v5. 解綁VBO
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        //TODO: >>>>>> 到這里 就把坐標(biāo)系中的本地內(nèi)存數(shù)據(jù) 緩存到了  顯存中【GPU中】 <<<<<<<


        //t1. 創(chuàng)建紋理
        int[] textureIds = new int[1];
        GLES20.glGenBuffers(1, textureIds, 0);
        //t2. 綁定紋理
        textureId = textureIds[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        //t3. 激活紋理 【激活紋理texture0】
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glUniform1i(sampler, 0);
        //t4 .設(shè)置紋理 環(huán)繞和過濾方式
        //todo: 環(huán)繞(超出紋理坐標(biāo)范圍):(s==x  t==y GL_REPEAT重復(fù))
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
        //todo: 過濾(紋理像素映射到坐標(biāo)點):(縮小税弃,放大:GL_LINEAR線性)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        //使用GLUtils.texImage2D 把bitmap這張圖片映射到Opengl上
        //Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.androids);
        //GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        //bitmap.recycle();

        //f1. 創(chuàng)建FBO 【Frame Buffer Object 紋理緩存類】
        int[] fbos = new int[1];
        GLES20.glGenBuffers(1, fbos, 0);
        //f2. 綁定FBO
        fboId = fbos[0];
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
        //f3. 為FBO分配需要的內(nèi)存大小 (1080 1920 是我手機的寬高纪岁,沒有ActionBar)
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 1080, 1920, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        //f4.把紋理綁定到FBO上
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0);
        //f5. 檢查FBO綁定是否成功
        if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) {
            Log.e("AnRender", "FBO 綁定 紋理失敗则果! ");
        } else {
            Log.i("AnRender", "FBO 綁定 紋理成功蜂科! ");
        }

        //t5. 解綁紋理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        //f6. 解綁FBO
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

        //這里我們創(chuàng)建一個要繪制的紋理ID
        imgTextureId = createImgTexrute(R.drawable.androids);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        Log.e("AnRender", "width: " + width + "     height:" + height);
        fboRender.onFboChange(width, height);
        if (width > height) { //橫屏
            // m1. 計算橫屏坐標(biāo)占有比例 (702 , 526 是該圖片的高 寬)
            Matrix.orthoM(matrix, 0, -width / ((height / 702f * 526f)), width / ((height / 702f * 526f)), -1f, 1f, -1f, 1f);
        } else { //豎屏
            // m2. 計算豎屏坐標(biāo)占有比例
            Matrix.orthoM(matrix, 0, -1, 1, -height / ((width / 526f * 702f)), height / ((width / 526f * 702f)), -1f, 1f);
        }
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); //清屏
        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);//紅色清屏【這樣背景就是紅色的了】
        //OpenGL 8.使用源程序
        GLES20.glUseProgram(program);
        // m3.使用正交投影
        GLES20.glUniformMatrix4fv(uMatrix, 1, false, matrix, 0);
        //OpenGL 9.綁定紋理顽决, 綁定VBO, 綁定FBO
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//綁定FBO
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imgTextureId); //GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);//綁定VBO


        //OpenGL 10.使頂點屬性數(shù)組有效, 使紋理屬性數(shù)組有效
        GLES20.glEnableVertexAttribArray(vPosition);
        GLES20.glEnableVertexAttribArray(fPosition);

        // OpenGL 11.為頂點坐標(biāo)屬性賦值 todo;就是把 vertexBuffer的數(shù)據(jù)給到  vPosition
        //GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);//vPosition中的數(shù)據(jù)就是本地內(nèi)存中的數(shù)據(jù)了
        //為片元坐標(biāo)屬性賦值  todo:  把textureBuffer的數(shù)據(jù)給到 fPosition
        //GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, fragmentBuffer);//fPosition中的數(shù)據(jù)就是本地內(nèi)存中的數(shù)據(jù)了
        //todo导匣; 到這里 vertex_shader.glsl中的  "av_Position"才菠, "af_Position"就有數(shù)據(jù)了
        // OpenGL[11步]. 在這一步,我們就可以使用生成好的VBO 【顯存中的緩存值了】
        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0); //vPosition中的數(shù)據(jù)就是顯存中的數(shù)據(jù)了
        GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, vertexData.length * 4);//fPosition中的數(shù)據(jù)就是顯存中的數(shù)據(jù)了

        // OpenGL 12.繪制圖形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        // OpenGL 13.解綁
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);//這里 textre=0 解綁紋理
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);//這里 buffer=0 解綁VBO
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);//這里 buffer=0 解綁FBO

        //去離屏渲染
        fboRender.onFboDraw(textureId);
    }


    private int createImgTexrute(int src) {
        int[] imgTextureIds = new int[1];
        GLES20.glGenTextures(1, imgTextureIds, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imgTextureIds[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

        //使用GLUtils.texImage2D 把bitmap這張圖片映射到Opengl上
        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), src);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        return imgTextureIds[0];
    }
}

代碼地址: opengl包下
https://github.com/YuLingRui/AntonyCFAV

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贡定,一起剝皮案震驚了整個濱河市赋访,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缓待,老刑警劉巖蚓耽,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異旋炒,居然都是意外死亡步悠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門瘫镇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鼎兽,“玉大人,你說我怎么就攤上這事铣除⊙枰В” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵尚粘,是天一觀的道長择卦。 經(jīng)常有香客問我,道長郎嫁,這世上最難降的妖魔是什么秉继? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮泽铛,結(jié)果婚禮上秕噪,老公的妹妹穿的比我還像新娘。我一直安慰自己厚宰,他們只是感情好腌巾,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铲觉,像睡著了一般澈蝙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上撵幽,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天灯荧,我揣著相機與錄音,去河邊找鬼盐杂。 笑死逗载,一個胖子當(dāng)著我的面吹牛哆窿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厉斟,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼挚躯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了擦秽?” 一聲冷哼從身側(cè)響起码荔,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎感挥,沒想到半個月后缩搅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡触幼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年硼瓣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片置谦。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡堂鲤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出霉祸,到底是詐尸還是另有隱情筑累,我是刑警寧澤袱蜡,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布丝蹭,位于F島的核電站,受9級特大地震影響坪蚁,放射性物質(zhì)發(fā)生泄漏奔穿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一敏晤、第九天 我趴在偏房一處隱蔽的房頂上張望贱田。 院中可真熱鬧,春花似錦嘴脾、人聲如沸男摧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耗拓。三九已至,卻和暖如春奏司,著一層夾襖步出監(jiān)牢的瞬間乔询,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工韵洋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留竿刁,地道東北人黄锤。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像食拜,于是被迫代替她去往敵國和親鸵熟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355