OpenGL ES 2.0 顯示圖形(上)

1、概述

Android框架提供了大量標(biāo)準(zhǔn)工具戈钢,用于創(chuàng)建有吸引力的功能性圖形用戶界面痹仙。如果想要更多地控制應(yīng)用程序在屏幕上繪制的內(nèi)容,或者想要繪制三維圖形殉了,則需要使用不同的工具开仰。Android框架提供的OpenGL ES提供了一組工具,用于顯示高端動(dòng)畫(huà)圖形,并且還可以受益于許多Android設(shè)備上提供的圖形處理單元(GPU)的加速众弓。這邊主要初步使用OpenGL ES來(lái)顯示圖形并與之交互恩溅。這邊采用的OpenGL ES 2.0,使用這個(gè)版本的原因是OpenGL ES 1.x的版本和2.0基本是兩套框架谓娃,許多東西不兼容而且過(guò)時(shí)脚乡,而現(xiàn)在比較新的OpenGL ES 3.x的版本是兼容和復(fù)用2.0的接口的,所以這邊以2.0版本作為切入點(diǎn)來(lái)討論滨达。我之前有一篇ARCore的文章——ARCore 相關(guān)奶稠,里面就有提到OpenGL ES 3.x來(lái)實(shí)現(xiàn)相關(guān)AR功能。這篇文章主要討論最最基礎(chǔ)的一些OpenGL ES 2.0操作捡遍,來(lái)實(shí)現(xiàn)用OpenGL ES在Android系統(tǒng)上顯示圖形窒典,并與之交互。

2稽莉、構(gòu)建環(huán)境

要在Android應(yīng)用程序中使用OpenGL ES繪制圖形瀑志,必須為它們創(chuàng)建一個(gè)視圖容器。其中一種比較直接的方法是實(shí)現(xiàn)一個(gè) GLSurfaceView和一個(gè)GLSurfaceView.Renderer污秆。

① GLSurfaceView:一個(gè)用OpenGL ES來(lái)繪制圖片的視圖容器劈猪。這個(gè)類(lèi)是一個(gè)View可以使用OpenGL API調(diào)用繪制和操作對(duì)象的類(lèi),在功能上類(lèi)似于SurfaceView良拼。

② GLSurfaceView.Renderer:用于控制將什么內(nèi)容顯示在GLSurfaceView上战得。這是一個(gè)接口類(lèi),此接口定義了在一個(gè)GLSurfaceView中繪制圖形所需的方法庸推。必須將此接口的實(shí)現(xiàn)作為單獨(dú)的類(lèi)提供常侦,并使用GLSurfaceView.setRenderer()將其附加到GLSurfaceView實(shí)例中 。GLSurfaceView.Renderer接口要求實(shí)現(xiàn)以下方法:

    onSurfaceCreated():創(chuàng)建GLSurfaceView的時(shí)候會(huì)調(diào)用一次該方法贬媒。使用此方法執(zhí)行僅需要發(fā)生一次的操作聋亡,例如設(shè)置OpenGL環(huán)境參數(shù)或初始化OpenGL圖形對(duì)象。

    onDrawFrame():GLSurfaceView在每次重繪時(shí)調(diào)用此方法际乘。使用此方法作為繪制(和重新繪制)圖形對(duì)象的主要執(zhí)行點(diǎn)坡倔。

    onSurfaceChanged():GLSurfaceView在幾何圖形更改時(shí)調(diào)用此方法,包括更改GLSurfaceView設(shè)備屏幕的大小或方向脖含。例如罪塔,當(dāng)設(shè)備從縱向更改為橫向時(shí),系統(tǒng)會(huì)調(diào)用此方法养葵。使用此方法響應(yīng)GLSurfaceView容器更改時(shí)需要進(jìn)行的操作征堪。

GLSurfaceView只是將OpenGL ES圖形合并到應(yīng)用程序中的一種方法。對(duì)于全屏或近全屏圖形視圖关拒,這是一個(gè)合理的選擇后裸。想要在布局的一小部分中加入OpenGL ES圖形可以使用TextureView。也可以使用構(gòu)建OpenGL ES視圖SurfaceView淮逻,這樣更靈活但這需要編寫(xiě)相當(dāng)多的額外代碼。

2.1 添加聲明

為了使應(yīng)用程序能夠使用OpenGL ES 2.0 API涌韩,必須在manifest中添加以下聲明:


<uses-feature android:glEsVersion="0x00020000" android:required="true" />

如果應(yīng)用程序使用紋理壓縮,則還必須聲明應(yīng)用程序支持哪種壓縮格式氯夷,以便它僅安裝在兼容設(shè)備上臣樱。


<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />

<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />

這邊說(shuō)到紋理壓縮指可以通過(guò)減少內(nèi)存需求和更有效地利用內(nèi)存帶寬來(lái)顯著提高OpenGL應(yīng)用程序的性能。Android框架提供對(duì)ETC1壓縮格式的支持腮考,作為標(biāo)準(zhǔn)功能雇毫。但是ETC1紋理壓縮格式不支持具有透明度(alpha通道)的紋理。如果應(yīng)用程序需要具有透明度的紋理踩蔚,則應(yīng)調(diào)查目標(biāo)設(shè)備上可用的其他紋理壓縮格式棚放。支持使用OpenGL ES 3.0 API時(shí),要保證可以使用ETC2 / EAC紋理壓縮格式馅闽。這種紋理格式提供出色的壓縮比和高視覺(jué)質(zhì)量飘蚯,格式還支持透明度(alpha通道)。而paletted是指通用的調(diào)色板紋理壓縮福也。還有ATITC(ATC)局骤、PVRTC、S3TC(DXT n / DXTC)暴凑、3DC等壓縮策略峦甩。

對(duì)于Google Play上的應(yīng)用,如果你添加了這些聲明现喳,會(huì)自動(dòng)檢測(cè)手機(jī)是否支持相關(guān)功能凯傲,如果不支持就不能下載該應(yīng)用。對(duì)于國(guó)內(nèi)的應(yīng)用商店嗦篱,不是很清楚是否會(huì)有改過(guò)濾冰单。

2.2 創(chuàng)建用于OpenGL ES圖形的Activity

使用OpenGL ES的Android應(yīng)用程序就像任何其他具有用戶界面的應(yīng)用程序一樣具有Activity。與其他應(yīng)用程序的主要區(qū)別在于在Activity的布局中添加的內(nèi)容默色。在使用OpenGL ES的應(yīng)用程序球凰,可以添加一個(gè)GLSurfaceView。

以下代碼示例顯示了使用一個(gè)GLSurfaceView作為其主視圖的Activity腿宰,當(dāng)然GLSurfaceView也可以像一般View一樣用在XML中:


public class OpenGLES20Activity extends Activity {

    public static final String TAG = "OpenGLES20";

    private GLSurfaceView mGLView;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        // 創(chuàng)建一個(gè)GLSurfaceView實(shí)例并將其設(shè)置為此Activity的ContentView。

        mGLView = new MyGLSurfaceView(this);

        setContentView(mGLView);

    }

}

2.3 構(gòu)建GLSurfaceView

一個(gè)GLSurfaceView是一個(gè)專(zhuān)門(mén)的視圖缘厢,可以在其中繪制OpenGL ES圖形吃度。它本身并沒(méi)有太大作用。對(duì)象的實(shí)際繪制在GLSurfaceView.Renderer中贴硫。這邊暫時(shí)可以直接使用GLSurfaceView椿每,但下面會(huì)講到的用于捕獲觸摸事件來(lái)進(jìn)行交互時(shí)候就需要擴(kuò)展這個(gè)類(lèi)了伊者。


class MyGLSurfaceView extends GLSurfaceView {

    private final MyGLRenderer mRenderer;

    public MyGLSurfaceView(Context context){

        super(context);

        // 創(chuàng)建一個(gè)OpenGL ES 2.0 的context

        setEGLContextClientVersion(2);

        mRenderer = new MyGLRenderer();

        // 設(shè)置渲染器(Renderer)以在GLSurfaceView上繪制

        setRenderer(mRenderer);

        // 僅在繪圖數(shù)據(jù)發(fā)生更改時(shí)才渲染視圖

        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

    }

}

上面這邊先是設(shè)置了使用OpenGL ES 的版本,然后創(chuàng)建了一個(gè)GLSurfaceView.Renderer并將其設(shè)置為該GLSurfaceView的渲染者间护,最后設(shè)置了一下渲染模式亦渗,將其設(shè)置為RENDERMODE_WHEN_DIRTY,在該模式下當(dāng)渲染內(nèi)容變化時(shí)不會(huì)主動(dòng)刷新效果汁尺,需要手動(dòng)調(diào)用requestRender() 才行法精。

2.4 構(gòu)建渲染器(GLSurfaceView.Renderer)

Renderer這個(gè)類(lèi)前面已經(jīng)提到,需要重寫(xiě)onSurfaceCreated() 痴突、onDrawFrame() 搂蜓、onSurfaceChanged() 這三個(gè)方法,下面實(shí)現(xiàn)一個(gè)最基本的渲染器辽装,之后會(huì)再增加內(nèi)容帮碰。


public class MyGLRenderer implements GLSurfaceView.Renderer {

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

       // 設(shè)置重繪背景框架顏色

        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    }

    public void onDrawFrame(GL10 unused) {

       // 重繪背景顏色

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {

        // 設(shè)置渲染的位置和大小

        GLES20.glViewport(0, 0, width, height);

    }

}

上面的代碼示例創(chuàng)建了一個(gè)簡(jiǎn)單的OpenGL ES應(yīng)用程序,它使用OpenGL顯示黑屏拾积。

3殉挽、定義形狀

OpenGL ES 中主要能定義點(diǎn)線和三角形,而其他多邊形都是由三角形組合而成的拓巧,這邊舉一個(gè)三角形和正方形的例子斯碌。

3.1 三角形

OpenGL ES允許使用三維空間中的坐標(biāo)定義繪制對(duì)象。因此玲销,在繪制三角形之前输拇,必須定義其坐標(biāo)。在OpenGL中贤斜,執(zhí)行此操作的典型方法是為坐標(biāo)定義浮點(diǎn)數(shù)的頂點(diǎn)數(shù)組策吠。為了獲得最大效率,可以將這些坐標(biāo)寫(xiě)入一個(gè)ByteBuffer中瘩绒,然后傳入OpenGL ES圖形管道進(jìn)行處理猴抹。


public class Triangle {

    private FloatBuffer vertexBuffer;

    // 此數(shù)組中每個(gè)頂點(diǎn)的維度

    static final int COORDS_PER_VERTEX = 3;

    static float triangleCoords[] = {  // 按逆時(shí)針順序

            0.0f,  0.622008459f, 0.0f, // 上

            -0.5f, -0.311004243f, 0.0f, // 左下

            0.5f, -0.311004243f, 0.0f  // 右下

    };

    // 設(shè)置顏色的R(紅),G(綠),B(藍(lán)),A(透明度) 值

    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

    public Triangle() {

         // 為形狀坐標(biāo)數(shù)組初始化頂點(diǎn)的字節(jié)緩沖區(qū)

        ByteBuffer bb = ByteBuffer.allocateDirect(

               // (# squareCoords 數(shù)組長(zhǎng)度 * 每個(gè)float占4字節(jié))

                triangleCoords.length * 4);

       // 緩沖區(qū)讀取順序使用設(shè)備硬件的本地字節(jié)讀取順序

        bb.order(ByteOrder.nativeOrder());

       // 從ByteBuffer創(chuàng)建一個(gè)浮點(diǎn)緩沖區(qū)

        vertexBuffer = bb.asFloatBuffer();

        // 將坐標(biāo)點(diǎn)加到FloatBuffer中

        vertexBuffer.put(triangleCoords);

        // 設(shè)置緩沖區(qū)開(kāi)始讀取位置,這邊設(shè)置為從頭開(kāi)始讀取

        vertexBuffer.position(0);

    }

}

默認(rèn)情況下锁荔,OpenGL ES會(huì)有一個(gè)坐標(biāo)系蟀给,其中[0,0,0](X,Y阳堕,Z)指GLSurfaceView框架的中心跋理,[1,1,0]是框架的右上角,并且[-1 恬总,-1,0]是框架的左下角前普。此形狀的坐標(biāo)以逆時(shí)針順序定義。繪圖順序很重要壹堰,因?yàn)樗x了哪一面是想要繪制的形狀的正面拭卿,以及背面骡湖,在繪制時(shí)候可以根據(jù)需求控制只繪制正面或者背面或者都繪制。

3.2 正方形

在OpenGL中定義三角形如上所示峻厚,但是如果想定義一個(gè)多邊形响蕴,例如正方形。在OpenGL ES中繪制這樣一個(gè)形狀的典型途徑是使用兩個(gè)繪制在一起的三角形:

繪制正方形

同樣惠桃,應(yīng)該以逆時(shí)針順序?yàn)楸硎敬诵螤畹膬蓚€(gè)三角形定義頂點(diǎn)浦夷,并將值放在一個(gè)ByteBuffer中。為了避免定義每個(gè)三角形共享的兩個(gè)坐標(biāo)點(diǎn)刽射,使用繪圖列表告訴OpenGL ES圖形管道如何繪制這些頂點(diǎn)军拟。


public class Square {

    private FloatBuffer vertexBuffer;

    private ShortBuffer drawListBuffer;

    // 此數(shù)組中每個(gè)頂點(diǎn)的坐標(biāo)數(shù)

    static final int COORDS_PER_VERTEX = 3;

    static float squareCoords[] = {

            -0.5f,  0.5f, 0.0f,  // 左上

            -0.5f, -0.5f, 0.0f,  // 左下

            0.5f, -0.5f, 0.0f,  // 右下

            0.5f,  0.5f, 0.0f }; // 右上

    private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // 頂點(diǎn)繪制順序

    public Square() {

        // 為形狀坐標(biāo)數(shù)組初始化頂點(diǎn)的字節(jié)緩沖區(qū)

        ByteBuffer bb = ByteBuffer.allocateDirect(

                // (# squareCoords 數(shù)組長(zhǎng)度 * 每個(gè)float占4字節(jié))

                squareCoords.length * 4);

        bb.order(ByteOrder.nativeOrder());

        vertexBuffer = bb.asFloatBuffer();

        vertexBuffer.put(squareCoords);

        vertexBuffer.position(0);

        // 為繪制順序數(shù)組 初始化字節(jié)緩沖區(qū)

        ByteBuffer dlb = ByteBuffer.allocateDirect(

                // (# drawOrder 數(shù)組長(zhǎng)度 * 每個(gè) short 占2字節(jié))

                drawOrder.length * 2);

        dlb.order(ByteOrder.nativeOrder());

        drawListBuffer = dlb.asShortBuffer();

        drawListBuffer.put(drawOrder);

        drawListBuffer.position(0);

    }

}

4 繪制形狀

在前面一節(jié)定義要使用OpenGL繪制的形狀后,這一節(jié)介紹如何繪制誓禁。使用OpenGL ES 2.0繪制形狀需要的代碼比較多懈息,因?yàn)锳PI提供了對(duì)圖形渲染管道的大量控制。這也是為什么說(shuō)OpenGL ES對(duì)開(kāi)發(fā)者不友好的的原因了摹恰。

4.1 初始化形狀

在進(jìn)行任何繪圖之前辫继,必須初始化并加載計(jì)劃繪制的形狀。除非在程序中使用的形狀的結(jié)構(gòu)(原始坐標(biāo))在執(zhí)行過(guò)程中發(fā)生更改俗慈,否則應(yīng)該在onSurfaceCreated()渲染器的方法中初始化它們以避免反復(fù)初始化姑宽。


public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    private Triangle mTriangle;

    private Square  mSquare;

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

        ...

        // 初始化三角形

        mTriangle = new Triangle();

        // 初始化正方形

        mSquare = new Square();

    }

    ...

}

4.2 繪制形狀

使用OpenGL ES 2.0繪制定義的形狀需要大量代碼,因?yàn)楸仨毾驁D形渲染管道提供大量細(xì)節(jié)闺阱。具體而言炮车,必須定義以下內(nèi)容:

① 頂點(diǎn)著色器(Vertex Shader):用于渲染形狀頂點(diǎn)的OpenGL ES圖形代碼。

② 片段著色器(Fragment Shader):OpenGL ES代碼酣溃,用于渲染具有顏色或紋理的形狀的面瘦穆。

③ 程序(Program):一個(gè)OpenGL ES對(duì)象,包含要用于繪制一個(gè)或多個(gè)形狀的著色器赊豌。

需要至少一個(gè)頂點(diǎn)著色器來(lái)繪制形狀扛或,并使用一個(gè)片段著色器為該形狀著色。必須編譯這些著色器碘饼,然后將其添加到OpenGL ES程序中熙兔,然后使用該程序繪制形狀。以下是如何定義可用于在Triangle類(lèi)中繪制形狀的基本著色器的示例:


public class Triangle {

    private final String vertexShaderCode =

        "attribute vec4 vPosition;" +

        "void main() {" +

        "  gl_Position = vPosition;" +

        "}";

    private final String fragmentShaderCode =

        "precision mediump float;" +

        "uniform vec4 vColor;" +

        "void main() {" +

        "  gl_FragColor = vColor;" +

        "}";

    ...

}

著色器包含OpenGL著色語(yǔ)言(GLSL)代碼艾恼,必須在OpenGL ES環(huán)境中使用它之前進(jìn)行編譯住涉。要編譯此代碼,需在渲染器類(lèi)中創(chuàng)建實(shí)用程序方法:


public static int loadShader(int type, String shaderCode){

        //創(chuàng)建頂點(diǎn)著色器類(lèi)型(GLES20.GL_VERTEX_SHADER)

        //或片段著色器類(lèi)型(GLES20.GL_FRAGMENT_SHADER)

        int shader = GLES20.glCreateShader(type);

        // 將源代碼添加到著色器并進(jìn)行編譯

        GLES20.glShaderSource(shader, shaderCode);

        GLES20.glCompileShader(shader);

        return shader;

    }

為了繪制形狀钠绍,必須編譯著色器代碼秆吵,將它們添加到OpenGL ES程序?qū)ο螅缓箧溄釉摮绦蛭宕取T诶L制對(duì)象的構(gòu)造函數(shù)中執(zhí)行此操作纳寂,也就是說(shuō)只執(zhí)行一次就好了。因?yàn)榫幾gOpenGL ES著色器和鏈接程序在CPU周期和處理時(shí)間方面的消耗比較大泻拦,因此應(yīng)該避免多次執(zhí)行此操作毙芜。如果在運(yùn)行時(shí)不需要修改著色器代碼的內(nèi)容,則應(yīng)在構(gòu)造器中構(gòu)建代碼争拐,使其僅創(chuàng)建一次腋粥,然后緩存以供以后使用。


public class Triangle() {

    ...

    private final int mProgram;

    public Triangle() {

        ...

        int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,

                                        vertexShaderCode);

        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,

                                        fragmentShaderCode);

        // 創(chuàng)建一個(gè)空的OpenGL ES 程序

        mProgram = GLES20.glCreateProgram();

        // 將頂點(diǎn)著色器添加到程序中

        GLES20.glAttachShader(mProgram, vertexShader);

        // 將片段著色器添加到程序中

        GLES20.glAttachShader(mProgram, fragmentShader);

       // 編譯鏈接OpenGL ES程序

        GLES20.glLinkProgram(mProgram);

    }

}

此時(shí)架曹,已準(zhǔn)備好添加繪制形狀的實(shí)際調(diào)用隘冲。使用OpenGL ES繪制形狀需要指定幾個(gè)參數(shù)來(lái)告訴渲染管道想要繪制什么以及如何繪制它。由于繪圖選項(xiàng)可能因形狀而異绑雄,因此最好讓形狀類(lèi)包含自己的繪圖邏輯展辞。創(chuàng)建draw()繪制形狀的方法。此代碼將位置和顏色值設(shè)置為形狀的頂點(diǎn)著色器和片段著色器万牺,然后執(zhí)行繪圖功能罗珍。


// Triangle.class

private int mPositionHandle;

private int mColorHandle;

private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;

private final int vertexStride = COORDS_PER_VERTEX * 4; //一個(gè)頂點(diǎn)占用空間,其中每個(gè)頂點(diǎn)單維值占4字節(jié)

public void draw(float[] mvpMatrix) {

        // 將程序添加到OpenGL ES環(huán)境

        GLES20.glUseProgram(mProgram);

        // 獲取頂點(diǎn)著色器vPosition屬性(位置)的句柄

        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        // 啟用三角形頂點(diǎn)的句柄

        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // 準(zhǔn)備三角坐標(biāo)數(shù)據(jù)

        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,

                GLES20.GL_FLOAT, false,

                vertexStride, vertexBuffer);

        // 獲取片段著色器vColor成員(顏色)的句柄

        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        //設(shè)置繪制三角形的顏色

        GLES20.glUniform4fv(mColorHandle, 1, color, 0);

        // 獲取形狀變換矩陣的具柄

        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

        // Pass the projection and view transformation to the shader

        // 將模型視圖投影矩陣傳遞給著色器

        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

        // 繪制三角形

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

        // 禁用頂點(diǎn)數(shù)組

        GLES20.glDisableVertexAttribArray(mPositionHandle);

    }

一旦準(zhǔn)備好所有這些代碼脚粟,繪制此對(duì)象只需要在渲染器的onDrawFrame()方法中調(diào)用draw()方法覆旱。


// MyGLRenderer.class

public void onDrawFrame(GL10 unused) {

    ...

    mTriangle.draw();

}

之后運(yùn)行程序會(huì)得到如下效果:

豎屏下渲染效果
橫屏下渲染效果

上面已經(jīng)初步將三角形顯示在屏幕上了。但明顯可以看到存在問(wèn)題核无,首先如果按照前面三角形的坐標(biāo)扣唱,按理說(shuō)應(yīng)該是一個(gè)等邊三角形。其次团南,這個(gè)三角形豎屏和橫屏拉伸方向也明顯不同噪沙。關(guān)于這個(gè)問(wèn)題的原因和解決辦法,會(huì)在下一篇文章OpenGL ES 顯示圖形(下)中進(jìn)行討論已慢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末曲聂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子佑惠,更是在濱河造成了極大的恐慌朋腋,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膜楷,死亡現(xiàn)場(chǎng)離奇詭異旭咽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赌厅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)穷绵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人特愿,你說(shuō)我怎么就攤上這事仲墨」寸裕” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵目养,是天一觀的道長(zhǎng)俩由。 經(jīng)常有香客問(wèn)我,道長(zhǎng)癌蚁,這世上最難降的妖魔是什么幻梯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮努释,結(jié)果婚禮上碘梢,老公的妹妹穿的比我還像新娘。我一直安慰自己伐蒂,他們只是感情好煞躬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著饿自,像睡著了一般汰翠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昭雌,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天复唤,我揣著相機(jī)與錄音,去河邊找鬼烛卧。 笑死佛纫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的总放。 我是一名探鬼主播呈宇,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼局雄!你這毒婦竟也來(lái)了甥啄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤炬搭,失蹤者是張志新(化名)和其女友劉穎蜈漓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宫盔,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡融虽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灼芭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片有额。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巍佑,到底是詐尸還是另有隱情茴迁,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布句狼,位于F島的核電站笋熬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腻菇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一昔馋、第九天 我趴在偏房一處隱蔽的房頂上張望筹吐。 院中可真熱鬧,春花似錦秘遏、人聲如沸丘薛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)洋侨。三九已至,卻和暖如春倦蚪,著一層夾襖步出監(jiān)牢的瞬間希坚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工陵且, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裁僧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓慕购,卻偏偏與公主長(zhǎng)得像聊疲,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沪悲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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