一篇文章理清WebGL繪制流程

本文梳理了WebGL中從零到渲染出一個(gè)簡(jiǎn)單幾何圖形的主要流程招盲。幫助一些剛接觸WebGL的玩家簡(jiǎn)單整理下在WebGL中渲染幾何圖形的過程均牢。

目錄

  1. 初始化WebGL環(huán)境
  2. 頂點(diǎn)著色器(Vertex Shader)與片元著色器(Fragment Shader)
  3. 頂點(diǎn)數(shù)組對(duì)象(VBO)、索引數(shù)值對(duì)象(IBO)
  4. 繪制流程
  5. 總結(jié)

初始化WebGL環(huán)境

關(guān)于HTML5削葱、<canvas>標(biāo)簽奖亚、WebGL的一些相關(guān)知識(shí)可以去MDN中查看,里面還有一些相關(guān)的學(xué)習(xí)干貨析砸,初始化WebGL環(huán)境可以參考初識(shí)WebGL昔字,我們這里按下不表。

頂點(diǎn)著色器與片元著色器

WebGL圖形渲染管線

介紹著色器之前首繁,我們先過一下WebGL的圖形管線:

WebGL Rendering Pipeline Overview

我們可以把WebGL的渲染管線當(dāng)做一條車間里的流水線作郭,這個(gè)車間的原材料是一些圖形相關(guān)的數(shù)據(jù)(包括頂點(diǎn)坐標(biāo),頂點(diǎn)顏色等)弦疮,這個(gè)車間生產(chǎn)的產(chǎn)品是我們屏幕上看到的各種圖形夹攒。

圖中綠色的兩個(gè)方塊就是我們要說的頂點(diǎn)著色器(Vertex Shader)片元著色器(Fragment Shader)

我們來(lái)一步一步簡(jiǎn)單介紹下這個(gè)條流水線:
圖中最上面的藍(lán)色方塊Attribute可以看做是一條水管胁塞,一端連接頂點(diǎn)數(shù)據(jù)(Vertex Buffer Objects)咏尝,另一端連接頂點(diǎn)著色器,這條水管的作用是把頂點(diǎn)數(shù)據(jù)輸送給頂點(diǎn)著色器處理啸罢。緊接著编检,頂點(diǎn)著色器把處理過的頂點(diǎn)數(shù)據(jù)交給片元著色器處理,最后經(jīng)過片元著色器處理過的數(shù)據(jù)將被輸送到Framebuffer中去扰才,為了便于理解允懂,我們暫且、姑且可以把這個(gè)Framebuffer當(dāng)做屏幕衩匣,而這最后的步驟蕾总,也就是把這些處理過的數(shù)據(jù)以圖形的方式顯示到屏幕上,至此琅捏,渲染管線也就完成了他的使命生百。

在這條流水線上,寫代碼的我們午绳,扮演著的是流水線上的工人置侍,所以我們做的事情是拿來(lái)數(shù)據(jù),然后確保數(shù)據(jù)在這條流水線上,按照既定的流程蜡坊,最終可以變成我們想要的圖形杠输。

頂點(diǎn)著色器與片元著色器

由上所述,WebGL編程中秕衙,我們需要為渲染流水線構(gòu)建好頂點(diǎn)著色器和片元著色器蠢甲。

頂點(diǎn)著色器的功能是對(duì)傳進(jìn)來(lái)的頂點(diǎn)數(shù)據(jù)通過矩陣進(jìn)行換換位置、計(jì)算照明方程式以生成逐頂點(diǎn)的顏色以及生成或者變換紋理坐標(biāo)据忘。
片元著色器則是對(duì)即將送到屏幕上的像素內(nèi)容進(jìn)行更進(jìn)一步的處理鹦牛,包括一些特殊效果的定制等。

這兩者的內(nèi)容會(huì)在之后的學(xué)習(xí)過程中加以說明勇吊,本文只需對(duì)它們的作用有個(gè)大致的了解即可曼追,更多的內(nèi)容可以參考《OpenGL編程指南》或者是《OpenGL ES 3.0編程指南》,我們這里重點(diǎn)只在于簡(jiǎn)單整理下WebGL的渲染流程汉规。

創(chuàng)建及使用著色器(Shader)

簡(jiǎn)要梳理下shader的創(chuàng)建過程礼殊。shader的作用前文已經(jīng)介紹過了,我們可以把shader當(dāng)做一個(gè)程序针史,頂點(diǎn)數(shù)據(jù)輸入shader晶伦,輸出經(jīng)過shader處理過的數(shù)據(jù),用于之后的渲染流程啄枕。

創(chuàng)建和使用shader的過程分為以下步驟:

  1. 首先創(chuàng)建并編譯好著色器對(duì)象
  2. 將這些著色器對(duì)象鏈接為一個(gè)著色器程序婚陪。

對(duì)于著色器對(duì)象

  1. 創(chuàng)建一個(gè)著色器對(duì)象
  2. 將著色器源代碼編譯為對(duì)象
  3. 驗(yàn)證著色器的編譯是否成功

創(chuàng)建著色器代碼如下:

// 創(chuàng)建一個(gè)著色器對(duì)象
var vertexShader = gl.createShader(gl.VERTEX_SHADER);

// 指定著色器源代碼
gl.shaderSource(vertexShader , vertexshaderSourceCode);

// 將著色器源代碼編譯為對(duì)象
gl.compileShader(vertexShader );

// 驗(yàn)證著色器的編譯是否成功
if (!gl.getShaderParameter(vertexShader , gl.COMPILE_STATUS)) {
    alert(gl.getShaderInfoLog(vertexShader ));
    return;
}

// 以上的代碼創(chuàng)建了一個(gè)頂點(diǎn)著色器,對(duì)于片元著色器
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
// 以下代碼類似
// code gose here ...

創(chuàng)建完著色器對(duì)象后频祝,我們得到了兩個(gè)著色器 vertexShader 和 fragmentShader

對(duì)于著色器程序

  1. 創(chuàng)建一個(gè)著色器程序
  2. 將著色器對(duì)象關(guān)聯(lián)到著色器程序
  3. 連接著色器程序
  4. 判斷著色器的鏈接過程是否成功完成
  5. 使用著色器來(lái)處理頂點(diǎn)和片元

創(chuàng)建著色器程序代碼如下:

// 創(chuàng)建一個(gè)著色器程序
var program = gl.createProgram();

// 將著色器對(duì)象關(guān)聯(lián)到著色器程序
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

// 連接著色器程序
gl.linkProgram(program);

// 判斷著色器的鏈接過程是否成功完成
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
    alert("Could not initialise shaders");
}

//  使用著色器來(lái)處理頂點(diǎn)和片元
gl.useProgram(program);

在大致了解過這條渲染流水線后泌参,我們接著將要介紹下頂點(diǎn)數(shù)組對(duì)象和索引數(shù)組對(duì)象。

頂點(diǎn)數(shù)組對(duì)象(VBO)智润、索引數(shù)值對(duì)象(IBO)

頂點(diǎn)數(shù)組對(duì)象(VBO)

頂點(diǎn)數(shù)組對(duì)象(VBO)對(duì)應(yīng)著圖中最上方的紅色的方塊及舍。頂點(diǎn)數(shù)組對(duì)象包含著WebGL要渲染的圖形的數(shù)據(jù)未辆】弑粒可以看成是流水線上的原材料。在WebGL的渲染過程中咐柜,這些圖形的數(shù)據(jù)往往通過頂點(diǎn)進(jìn)行儲(chǔ)存和輸送兼蜈,頂點(diǎn)數(shù)組對(duì)象包含的數(shù)據(jù)一般包括頂點(diǎn)位置信息、頂點(diǎn)位置上的法線向量拙友、紋理坐標(biāo)等为狸。

索引數(shù)組對(duì)象(IBO)

在圖形的繪制過程中,我們把每3個(gè)頂點(diǎn)繪制成一個(gè)三角形遗契,即圖形學(xué)中“面”(surface)的含義辐棒,而后通過成千上萬(wàn)的面組成了我們空間中的三維模型。索引數(shù)組對(duì)象(IBO)的作用是告訴WebGL要通過什么樣的順序來(lái)將我們傳入的頂點(diǎn)數(shù)據(jù)連接成面。為了便于理解漾根,我們舉個(gè)栗子:


繪制一個(gè)梯形

當(dāng)我們按照如圖所示的方式繪制一個(gè)梯形時(shí)泰涂,我們弄來(lái)了5個(gè)頂點(diǎn)(0, 0)、(10, 10)辐怕、(20, 0)逼蒙、(30, 10)、(40, 0)分別對(duì)應(yīng)從0-4的五個(gè)索引寄疏。而當(dāng)我們繪制圖形時(shí)是牢,定義的索引數(shù)組[0, 2, 1, 1, 2, 3, 2, 4, 3]的意思就是告訴WebGL,把索引為0陕截、2驳棱、1的三個(gè)頂點(diǎn)組成一個(gè)三角形,索引為1农曲、2蹈胡、3的三個(gè)頂點(diǎn)組成另一個(gè)三角形,索引為2朋蔫、4罚渐、3的頂點(diǎn)也組成一個(gè)三角形(可參照?qǐng)D示)。
索引數(shù)組對(duì)象的作用就是保存這些索引數(shù)組的數(shù)據(jù)驯妄,用以傳輸給WebGL渲染管線荷并。

創(chuàng)建頂點(diǎn)數(shù)組對(duì)象&索引數(shù)組對(duì)象

WebGL狀態(tài)機(jī)

在介紹如何創(chuàng)建這兩個(gè)對(duì)象前,我們要先知道青扔,WebGL是個(gè)狀態(tài)機(jī)源织。我們可以這么理解,假設(shè)WebGL中的屬性P的值為1微猖,你在某一次操作中谈息,把P的值設(shè)置成了2,那么在你下一次設(shè)置P的值之前凛剥,P的值永遠(yuǎn)是2侠仇。

更直觀一點(diǎn)的表述,你可以想象WebGL像KFC套餐犁珠,有個(gè)套餐A逻炊,里面包含一個(gè)香辣雞腿堡,一杯百事可樂犁享。你每次點(diǎn)A套餐余素,都會(huì)得到一個(gè)香辣雞腿堡,一杯百事可樂炊昆,而你在每次用餐的過程中桨吊,吃的漢堡都是香辣雞腿堡威根,喝的可樂都是百事可樂。直到某一天视乐,KFC把A套餐的內(nèi)容改成了一個(gè)奧爾良烤雞腿堡医窿,一杯可口可樂。在那天之后炊林,同樣是A套餐姥卢,但是你吃的漢堡就變成了奧爾良烤雞腿堡,喝的可樂變成了可口可樂渣聚,除非KFC對(duì)A套餐的內(nèi)容再進(jìn)行調(diào)整独榴,不然點(diǎn)A套餐的你只能喝上一輩子的可口可樂(本人比較喜歡百事可樂)。

所以你可以把WebGL上下文想象成是A套餐奕枝,WebGL中的一些屬性選項(xiàng)的對(duì)應(yīng)的是漢堡棺榔、可樂,而香辣雞腿堡隘道、奧爾良烤雞腿堡症歇、百事可樂、可口可樂對(duì)應(yīng)的是屬性當(dāng)前的值谭梗。類比一下忘晤。

頂點(diǎn)數(shù)組對(duì)象的創(chuàng)建

接下來(lái)插播一段代碼:

var vertices = [
-50.0, 50.0, 0.0,
-50.0,-50.0, 0.0,
50.0,-50.0, 0.0,
50.0, 50.0, 0.0
];

// 調(diào)用gl.createBuffer()創(chuàng)建了一個(gè)塊內(nèi)存空間,并讓 vertexBufferObject  變量指向這塊空間
var vertexBufferObject = gl.createBuffer();

// 把WebGL中用于繪制的數(shù)組數(shù)據(jù)的屬性(ARRAY_BUFFER)的值的地址指向上文我們創(chuàng)建的 vertexBuffer 內(nèi)存空間激捏。
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObject );

// bufferData 函數(shù)對(duì) ARRAY_BUFFER 屬性對(duì)應(yīng)的空間填充值
// WebGL 狀態(tài)機(jī)概念出場(chǎng)设塔!
// 由于我們?cè)谏弦粋€(gè)語(yǔ)句中,修改了 ARRAY_BUFFER 的值远舅,由于狀態(tài)機(jī)的性質(zhì)闰蛔,所以我們調(diào)用該函數(shù)進(jìn)行傳值時(shí),
// 傳入的值是會(huì)給此時(shí)gl中的 ARRAY_BUFFER 屬性指向的空間图柏,也就是
 vertexBufferObject 的內(nèi)存空間序六。
// 此處調(diào)用把 vertices 中的頂點(diǎn)數(shù)據(jù)傳入了 vertexBufferObject 對(duì)象
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// 傳值完畢,恢復(fù) ARRAY_BUFFER 的值為空
gl.bindBuffer(gl.ARRAY_BUFFER, null);

所以這段代碼就創(chuàng)建了一個(gè)名為 vertexBufferObject 的頂點(diǎn)數(shù)組對(duì)象蚤吹。代碼中具體的API可以查閱相關(guān)的資料例诀。

索引數(shù)組對(duì)象的創(chuàng)建

索引數(shù)組對(duì)象的創(chuàng)建與頂點(diǎn)數(shù)組對(duì)象的創(chuàng)建大同小異

var indices = [
0, 2, 1, 
1, 2, 3
];
var indicesBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBufferObject );
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices),
gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

這里需要注意的是,索引數(shù)組對(duì)象對(duì)應(yīng)的屬性為ELEMENT_ARRAY_BUFFER距辆。而傳入的數(shù)組類型是Uint16Array余佃。

繪制流程

最后,我們要把前面提到的內(nèi)容按照渲染管線的圖示結(jié)合起來(lái)跨算。再看一眼我們的地圖:


WebGL Rendering Pipeline Overview

好,上代碼:

// 按照?qǐng)D示來(lái)看椭懊,要繪制一個(gè)圖形诸蚕,首先我們需要原材料:
// 1. 一個(gè)頂點(diǎn)數(shù)組對(duì)象(VBO)步势,用于存儲(chǔ)相關(guān)的頂點(diǎn)數(shù)據(jù), 
// 同時(shí)需要一個(gè)表示頂點(diǎn)組合順序的索引數(shù)組對(duì)象(IBO)。

// 2. 需要兩個(gè)著色器(vertex shader 及 fragment shader)和一個(gè)著色器程序背犯,用來(lái)保證管線的順利進(jìn)行坏瘩。
// 好了,開工漠魏!

// 先來(lái)VBO和IBO
var vertices =  [
    -0.5,0.5,0.0, 
    -0.5,-0.5,0.0,
    0.5,-0.5,0.0, 
    0.5,0.5,0.0
];  

var indices = [3,2,1,3,1,0];

// 創(chuàng)建VBO
var vertexBufferObj = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObj );
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);

// 創(chuàng)建IBO
var indexBufferObj = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObj );
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

// 創(chuàng)建頂點(diǎn)著色器
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader , vertexshaderSourceCode);
gl.compileShader(vertexShader );
// 驗(yàn)證著色器的編譯是否成功
if (!gl.getShaderParameter(vertexShader , gl.COMPILE_STATUS)) {
    alert(gl.getShaderInfoLog(vertexShader ));
}

// 同理創(chuàng)建片元著色器
var fragmentShader= gl.createShader(gl.FRAGMENT_SHADER);
/* so many balabalabala... */

// 創(chuàng)建著色器程序
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
// 判斷著色器的鏈接過程是否成功完成
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
    alert("Could not initialise shaders");
}

目前為止倔矾,我們已經(jīng)準(zhǔn)備好了繪制圖形的所有原料了,接下里就是如何通過WebGL繪制出圖形了柱锹。

// 先獲取頂點(diǎn)數(shù)據(jù)進(jìn)入著色器的入口(后文會(huì)講解)
program.vertexPosition = gl.getAttribLocation(program, "aVertexPosition");

// 繪制場(chǎng)景的函數(shù)
function drawScene(){
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.enable(gl.DEPTH_TEST);
    
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.viewport(0, 0, c_width, c_height);

    // 指定繪制時(shí)使用的頂點(diǎn)數(shù)據(jù)
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObj );
    // 一下這兩行代碼對(duì)應(yīng)的作用是將頂點(diǎn)數(shù)據(jù)讀入著色器中哪自,后文會(huì)加以解釋
    gl.vertexAttribPointer(program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(program.vertexPosition);

    // 指定繪制時(shí)使用的索引數(shù)組
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObj);
    // 以給定的形式繪制圖形
    gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
}

這樣我們就實(shí)現(xiàn)了圖形的繪制。
由于本文重點(diǎn)在于梳理繪制流程禁熏,并沒有深入介紹著色器相關(guān)的內(nèi)容壤巷,所以對(duì)于gl.vertexAttribPointer函數(shù)和gl.enableVertexAttribArray會(huì)有疑惑。
為了解釋一下這個(gè)問題瞧毙,我們先看一段頂點(diǎn)著色器的代碼

<script id="shader-vs" type="x-shader/x-vertex">
    attribute vec3 aVertexPosition;

    void main(void) {
        gl_Position = vec4(aVertexPosition,1.0); 
    }
</script>

其中代碼中的aVertexPosition表示的是頂點(diǎn)數(shù)據(jù)從這個(gè)變量進(jìn)入著色器胧华。

就像我們前文比喻的那樣,這個(gè)aVertexPosition就像一端連接頂點(diǎn)數(shù)據(jù)(Vertex Buffer Objects)宙彪,另一端連接頂點(diǎn)著色器的水管的開關(guān)矩动。

我們執(zhí)行program.vertexPosition = gl.getAttribLocation(program, "aVertexPosition");時(shí),相當(dāng)于把這個(gè)開關(guān)的位置記錄在program.vertexPosition上面释漆。

以下代碼:

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObj );
gl.vertexAttribPointer(prg.vertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(program.vertexPosition);

bindBuffer指定當(dāng)前WebGL繪制的數(shù)據(jù)為vertexBufferObj中的頂點(diǎn)數(shù)據(jù)铅忿。

vertexAttribPointer函數(shù)則把頂點(diǎn)數(shù)據(jù)通過水管接到著色器"aVertexPosition"的位置上,也就是我們記錄下來(lái)的program.vertexPosition的位置灵汪。

gl.enableVertexAttribArray(program.vertexPosition)則是最后一步把水管的閥門打開檀训,讓頂點(diǎn)數(shù)據(jù)流入著色器。

總結(jié)

本文主要目的是簡(jiǎn)單梳理了下WebGL繪制圖形的大致編程流程享言,并沒有做很深入的講解峻凫。WebGL基于OpenGL ES 2.0,而早先的OpenGL用的都是固定的渲染管線览露,之前學(xué)OpenGL一開始都是glBegin荧琼,glEnd,glVertex2d啥的一堆東西差牛,精簡(jiǎn)版的OpenGL ES一上來(lái)就拋棄了之前固定渲染管線的東西命锄,使用了可編程的渲染管線,一上來(lái)就要求要編寫Shader偏化,所以繪制一個(gè)圖形就變得比較繁瑣一點(diǎn)脐恩。于是有了這篇筆記,以供剛開始學(xué)習(xí)WebGL的玩家們參考侦讨。
對(duì)于文中的一些API并沒有進(jìn)入詳細(xì)的講解驶冒,需要的同學(xué)可以查閱相關(guān)的資料書籍苟翻。

相關(guān)資料

《OpenGL編程指南》
《OpenGL ES 3.0編程指南》
《WebGL Beginner's Guide》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市骗污,隨后出現(xiàn)的幾起案子崇猫,更是在濱河造成了極大的恐慌,老刑警劉巖需忿,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诅炉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡屋厘,警方通過查閱死者的電腦和手機(jī)涕烧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)擅这,“玉大人澈魄,你說我怎么就攤上這事≈亵幔” “怎么了痹扇?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)溯香。 經(jīng)常有香客問我鲫构,道長(zhǎng),這世上最難降的妖魔是什么玫坛? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任结笨,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己膀息,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布赫模。 她就那樣靜靜地躺著,像睡著了一般蒸矛。 火紅的嫁衣襯著肌膚如雪瀑罗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天雏掠,我揣著相機(jī)與錄音斩祭,去河邊找鬼。 笑死乡话,一個(gè)胖子當(dāng)著我的面吹牛摧玫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚊伞,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼席赂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吮铭!你這毒婦竟也來(lái)了时迫?” 一聲冷哼從身側(cè)響起颅停,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掠拳,沒想到半個(gè)月后癞揉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溺欧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年喊熟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姐刁。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芥牌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出聂使,到底是詐尸還是另有隱情壁拉,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布柏靶,位于F島的核電站弃理,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏屎蜓。R本人自食惡果不足惜痘昌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望炬转。 院中可真熱鬧辆苔,春花似錦、人聲如沸扼劈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)测僵。三九已至街佑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捍靠,已是汗流浹背沐旨。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榨婆,地道東北人磁携。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像良风,于是被迫代替她去往敵國(guó)和親谊迄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闷供,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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