WebGL基礎(chǔ)介紹

談起WebGL可能有一些人比較陌生,實(shí)際上WebGL是一種3D繪圖標(biāo)準(zhǔn)剧董,這種繪圖技術(shù)標(biāo)準(zhǔn)允許把JavaScript和OpenGL ES 2.0結(jié)合在一起曾雕,通過增加OpenGL ES 2.0的一個(gè)JavaScript綁定跃惫,WebGL可以為HTML5 Canvas提供硬件3D加速渲染,這樣Web開發(fā)人員就可以借助系統(tǒng)顯卡來在瀏覽器里更流暢地展示3D場景和模型了宙项,還能創(chuàng)建復(fù)雜的導(dǎo)航和數(shù)據(jù)視覺化。顯然株扛,WebGL技術(shù)標(biāo)準(zhǔn)免去了開發(fā)網(wǎng)頁專用渲染插件的麻煩尤筐,可被用于創(chuàng)建具有復(fù)雜3D結(jié)構(gòu)的網(wǎng)站頁面,甚至可以用來設(shè)計(jì)3D網(wǎng)頁游戲等等洞就。

此鏈接可以查看你的游覽器是否支持WebGL以及支持的版本盆繁。
檢測瀏覽器是否支持WebGL

看WebGL的背景實(shí)際上是JavaScript操作一些OpenGL接口,也就意味著旬蟋,可能會編寫一部分GLSL ES 2.0的代碼油昂,沒錯(cuò),你猜對了,WebGL只是綁定了一層冕碟,內(nèi)部的一些核心內(nèi)容拦惋,如著色器,材質(zhì)安寺,燈光等都是需要借助GLSL ES語法來操作的.

基于WebGL周邊也衍生了眾多的第三方庫厕妖,如開發(fā)應(yīng)用類的Three.js,開發(fā)游戲類的Egert.js等挑庶,都大大的降低了學(xué)習(xí)WebGL的成本叹放,但是本著有問題解決問題,沒問題制造問題在解決問題的程序猿態(tài)度挠羔,還是覺得應(yīng)該稍微了解一下WebGL一些基本的概念井仰,以便能更好的去理解不同框架帶來的便捷以及優(yōu)勢。一些簡單的效果其實(shí)無需多引入一個(gè)體積可觀的三方庫來實(shí)現(xiàn)破加。如下圖的效果:

波浪預(yù)覽

接下來先簡單介紹一下使用到的知識要點(diǎn)俱恶。

創(chuàng)建webGL對象

不同瀏覽器生命WebGL對象方式有所區(qū)別,雖然大部分瀏覽器都支持experimental-webgl范舀,而且以后會變成webgl合是,所以創(chuàng)建時(shí)做一下兼容處理

var canvas = document.getElementById("glcanvas");
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");

著色器

WebGL依賴一種新的稱為著色器(shader)的繪圖機(jī)制。著色器提供了靈活且強(qiáng)大的繪制二維或三維圖形的方法锭环,所有WebGL必須使用它聪全。著色器不僅強(qiáng)大,而且更復(fù)雜辅辩,僅僅通過一條簡單的繪圖指令是不能操作它的难礼。

WebGL需要兩種著色器

  • 頂點(diǎn)著色器(Vertex shader):頂點(diǎn)著色器是用來描述頂點(diǎn)特性(如位置、顏色等)的程序玫锋。頂點(diǎn)(Vertex)是指二維或三維空間的一個(gè)點(diǎn)蛾茉,比如二維或三維空間線與線之間的交叉點(diǎn)或者端點(diǎn)。
  • 片元著色器(Fragment shader):進(jìn)行逐片元處理過程(如光照等)的程序撩鹿。片元(fragment)是一個(gè)WebGL的術(shù)語谦炬,你可以將其理解成像素。

著色器語言使用的是GLSL ES語言节沦,所以在javascript需要將之存放在字符串中键思,等待調(diào)用編譯

創(chuàng)建頂點(diǎn)著色器:
var VSHADER_SOURCE =
'void main() {\n' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' +
' gl_PointSize = 10.0;\n' +
'}\n';

創(chuàng)建片元著色器:
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';

瀏覽器的整個(gè)過程如下:

WebGL渲染過程

著色器中包含幾個(gè)內(nèi)置變量:gl_Position, gl_PointSize, gl_FragColor

著色器語言中涉及到vec4的數(shù)據(jù)類型甫贯,此數(shù)據(jù)類型是一個(gè)思維浮點(diǎn)數(shù)組吼鳞,所以其值不可以是整形如(1,1,1,1),正確應(yīng)為:(1.0,1.0,1.0,1.0)

  • gl_Position: 為一種vec4類型的變量获搏,且必須被賦值赖条。四維坐標(biāo)矢量失乾,我們稱之為齊次坐標(biāo),即(x,y,z,w)等價(jià)于三維左邊(x/w,y/w,z/w)纬乍,w相當(dāng)于深度碱茁,沒有特殊要求設(shè)置為1.0即可。

  • gl_PointSize:表示頂點(diǎn)的尺寸仿贬,也是浮點(diǎn)數(shù)纽竣,為非必填項(xiàng),如果不填則默認(rèn)顯示為1.0茧泪。

  • gl_FragColor:該變量為片元著色器唯一的內(nèi)置變量蜓氨,表示其顏色,也是一個(gè)vec4類型變量队伟,分別代表(R,G,B,A)穴吹,不過顏色范圍是從0.0-1.0對應(yīng)Javascript中的#00-#FF

有了著色器我們就可以著手去繪制圖像了嗜侮,既然繪制3D圖形港令,必然會有對應(yīng)的三維坐標(biāo)系,WebGL采用右手坐標(biāo)系锈颗,如圖所示:

坐標(biāo)系

使用著色器

讓我們來看看如何把著色器代碼編譯并且使用起來

著色器代碼需要載入到一個(gè)程序中顷霹,webgl使用此程序才能調(diào)用著色器。
var program = gl.createProgram();
// 創(chuàng)建頂點(diǎn)著色器
var vShader = gl.createShader(gl.VERTEX_SHADER);
//創(chuàng)建片元著色器
var fShader = gl.createShader(gl.FRAGMENT_SHADER);
//shader容器與著色器綁定
gl.shaderSource(vShader, VSHADER_SOURCE);
gl.shaderSource(fShader, FSHADER_SOURCE);
//將GLSE語言編譯成瀏覽器可用代碼
gl.compileShader(vShader);
gl.compileShader(fShader);
//將著色器添加到程序上
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
//鏈接程序击吱,在鏈接操作執(zhí)行以后淋淀,可以任意修改shader的源代碼,
對shader重新編譯不會影響整個(gè)程序覆醇,除非重新鏈接程序
gl.linkProgram(program);
//加載并使用鏈接好的程序
gl.useProgram(program);

讓我們嘗試?yán)L制一個(gè)點(diǎn)

gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0 ,1);

我們來看一看最終結(jié)果,果然出來了一個(gè)點(diǎn)

繪制單點(diǎn)的結(jié)果

程序創(chuàng)建完之后朵纷,我們需要需要對著色器進(jìn)行動態(tài)控制才能達(dá)到我們所需要的功能。

首先讓我來介紹2個(gè)變量叫乌,我們需要借助這2個(gè)變量搭建的橋梁才能使JavaScript與GLSL ES之間進(jìn)行溝通柴罐。

  • attribute: 用于頂點(diǎn)點(diǎn)著色器(Vertex Shader)傳值時(shí)使用徽缚。
  • uniform:可用于頂點(diǎn)著色器(Vertex Shader)與片元著色器(Fragment Shader)使用憨奸。

將頂點(diǎn)動態(tài)化

先在頂點(diǎn)著色器代碼中,將對應(yīng)的vec4的固定值變成變量
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = 10.0;\n' +
'}\n';

位置參數(shù)使用了attribute變量來承載凿试。這樣WebGL對象就可以獲取到對應(yīng)的存儲位置排宰,就可以去動態(tài)改變GLSL變量了。

使用WebGL來獲取對應(yīng)參數(shù)的存儲地址地址
//返回對應(yīng)的地址信息
var aPosition = gl.getAttribLocation(gl.program, 'a_Position');
//判斷地址是否獲取成功
if(aPosition < 0) {
console.log('沒有獲取到對應(yīng)position');
}
然后給變量賦值
gl.vertexAttrib3f(aPosition, 1.0, 1.0, 0.0);
//或者使用Float32Array來傳參
var p = new Float32Array([1.0, 1.0, 1.0]);
gl.vertexAttrib3fv(aPosition, p);

注意:vertexAttrib3fv這個(gè)函數(shù)是典型的GLSL語法命名規(guī)范那婉,
vertexAttrib函數(shù)功能板甘,
3:對應(yīng)需要傳3個(gè)參數(shù),或者是幾維向量详炬,
f:表示參數(shù)是float類型盐类,
v:表示傳如的為一個(gè)vector變量。

也就是說對應(yīng)設(shè)置頂點(diǎn)著色器的函數(shù)有一下幾種功能,參考文檔

void gl.vertexAttrib1f(index, v0);
void gl.vertexAttrib2f(index, v0, v1);
void gl.vertexAttrib3f(index, v0, v1, v2);
void gl.vertexAttrib4f(index, v0, v1, v2, v3);
void gl.vertexAttrib1fv(index, value);
void gl.vertexAttrib2fv(index, value);
void gl.vertexAttrib3fv(index, value);
void gl.vertexAttrib4fv(index, value);

同樣操作可以如下修改PointSize:
//著色器中添加變量
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute float a_PointSize;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = a_PointSize;\n' +
'}\n';
var aPointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttrib1f(aPointSize, 10.0);

片元著色器編程

對片元著色器變成需要使用uniform變量來承載在跳。
var FSHADER_SOURCE =
'precision mediump float;\n'+
'uniform vec4 vColor;\n'+
'void main() {\n' +
' gl_FragColor = vColor;\n' + // Set the point color
'}\n';
獲取片元著色器變量地址
var vColor = gl.getUniformLocation(gl.program, 'vColor');
給變量賦值
gl.uniform4f(vColor, 1.0, 0.0, 0.0, 1.0);
//或使用Float32Array來傳參
var color = new Float32Array([1.0, 0.0, 0.0, 1.0]);
gl.uniform4fv(vColor,color)
注意:uniform3fv這個(gè)函數(shù)是典型的GLSL語法命名規(guī)范枪萄,
uniform3fv函數(shù)功能,
3:對應(yīng)需要傳3個(gè)參數(shù)猫妙,或者是幾維向量瓷翻,
f:表示參數(shù)是float類型,
u:表示參數(shù)是Uint32Array類型割坠,
i:表示參數(shù)是integer類型齐帚,
ui:表示參數(shù)是unsigned integer類型,
v:表示傳如的為一個(gè)vector變量彼哼。

頂點(diǎn)著色器對應(yīng)函數(shù)对妄,參考文檔

void gl.uniform1ui(location, v0);
void gl.uniform2ui(location, v0, v1);
void gl.uniform3ui(location, v0, v1, v2);
void gl.uniform4ui(location, v0, v1, v2, v3);
void gl.uniform1fv(location, data, optional srcOffset, optional srcLength);
void gl.uniform2fv(location, data, optional srcOffset, optional srcLength);
void gl.uniform3fv(location, data, optional srcOffset, optional srcLength);
void gl.uniform4fv(location, data, optional srcOffset, optional srcLength);
void gl.uniform1iv(location, data, optional srcOffset, optional srcLength);
void gl.uniform2iv(location, data, optional srcOffset, optional srcLength);
void gl.uniform3iv(location, data, optional srcOffset, optional srcLength);
void gl.uniform4iv(location, data, optional srcOffset, optional srcLength);
void gl.uniform1uiv(location, data, optional srcOffset, optional srcLength);
void gl.uniform2uiv(location, data, optional srcOffset, optional srcLength);
void gl.uniform3uiv(location, data, optional srcOffset, optional srcLength);
void gl.uniform4uiv(location, data, optional srcOffset, optional srcLength);

著色器中的代碼precision mediump float;表示的意思是著色器中配置的float對象會占用中等尺寸內(nèi)存。
具體包含的尺寸:

  • highp for vertex positions,
  • mediump for texture coordinates,
  • lowp for colors.

如果不設(shè)置此參數(shù)會報(bào)錯(cuò):


yanglei8.jpg

我們可以繪制自定義的點(diǎn)了敢朱,接下來我們就可以嘗試?yán)L制大批量點(diǎn)來達(dá)到波浪的基礎(chǔ)效果饥伊,但是之前的操作都是針對一個(gè)點(diǎn)的,如何可以同時(shí)繪制多個(gè)訂點(diǎn)呢蔫饰,如果你的回答是循環(huán)數(shù)據(jù)琅豆,BINGGO,沒錯(cuò)這樣你的確是可以達(dá)到這個(gè)目的篓吁,但是不是我們接下來要講的茫因,因?yàn)樵?D繪制的時(shí)候是會經(jīng)常出現(xiàn)大批量點(diǎn)、線杖剪、面的繪制的冻押,所以WebGL提供了一種承載機(jī)制來達(dá)到傳遞多點(diǎn)的能力,說了這么多盛嘿,也讓我們來看看它到底是什么吧

緩存區(qū)對象

之前的方式可以通過循環(huán)來繪制多個(gè)點(diǎn)洛巢,一次需要繪制多個(gè)點(diǎn),需要同時(shí)傳遞進(jìn)去多個(gè)點(diǎn)的數(shù)據(jù)次兆。剛好稿茉,在WebGL中提供了一種機(jī)制:緩存區(qū)對象(buffer data),緩存區(qū)對象可以同時(shí)向著色器傳遞多個(gè)頂點(diǎn)坐標(biāo)。緩存區(qū)是WebGL中的一塊內(nèi)存區(qū)域芥炭,我們可以向里面存放大量頂點(diǎn)坐標(biāo)數(shù)據(jù)漓库,可隨時(shí)供著色器使用。

使用緩存區(qū)步驟

  • 創(chuàng)建緩存區(qū)對象(gl.createBuffer())
  • 綁定緩存區(qū)對象(gl.bindBuffer())
  • 將數(shù)據(jù)寫入緩存區(qū)對象(gl.bufferData())
  • 將緩存區(qū)對象分配給一個(gè)attribute變量(gl.vertexAttribPointer())
  • 開啟attribute變量(gl.enableVertexAttribArray())

首先园蝠,我們?nèi)匀恍枰獎(jiǎng)?chuàng)建WebGL對象渺蒿、片元著色器以及頂點(diǎn)著色器,具體創(chuàng)建的步驟以及原理彪薛,可參考之前的教程茂装。具體代碼實(shí)現(xiàn)如下:
當(dāng)創(chuàng)建好WebGL之后怠蹂,可以通過著色器中的attrbute或者uniform對象來傳遞需要?jiǎng)討B(tài)修改或設(shè)置的的變量。
接下來我們需要進(jìn)行緩沖區(qū)的操作:
首先少态,需要?jiǎng)?chuàng)建一個(gè)緩沖區(qū)來承載大量頂點(diǎn)的坐標(biāo)
//創(chuàng)建緩存區(qū)
var vertexBuffer = gl.createBuffer();
if(!vertexBuffer) {
log('創(chuàng)建緩存區(qū)失敗褥蚯。');
return -1;
}
//將創(chuàng)建的緩存區(qū)對象綁定到target表示的目標(biāo)上
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//開辟存儲空間,向綁定在target上的緩存區(qū)對象中寫入數(shù)據(jù)
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
//獲取著色器中的變量值
var a_position = gl.getAttribLocation(gl.program, 'a_p');
//將緩存區(qū)對象綁定到著色器變量中
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0);
// 啟用緩存區(qū)
gl.enableVertexAttribArray(a_position);
// 繪制緩存區(qū)中畫的多個(gè)頂點(diǎn)
gl.drawArrays(gl.POINTS, 0 , array);

看完了繪制過程况增,讓我們來拆解一下具體內(nèi)容:

首先赞庶,我們要在茫茫內(nèi)存中申請一個(gè)區(qū)域來放置緩存區(qū)對象的內(nèi)容,但是我們無法直接放置緩存對象進(jìn)入內(nèi)存中澳骤,否則會無法識別對應(yīng)的數(shù)據(jù)類型歧强,從而無法達(dá)到存取自如的境界,那我們就需要將數(shù)據(jù)的類型告知內(nèi)存为肮,bingBuffer就是為解決此問題誕生的摊册,函數(shù)會在內(nèi)存中申請一部分區(qū)域,并且通過target來制定數(shù)據(jù)類型颊艳,也就是說茅特,緩存區(qū)是需要放置在target表示的類型部分去存儲。

gl.bindBuffer(target, buffer)

target: 指定存儲緩存區(qū)的目標(biāo)類型

  • gl.ARRAY_BUFFER : 指緩存區(qū)中包含了頂點(diǎn)的數(shù)據(jù)
  • gl.ELEMENT_ARRAY_BUFFER : 指緩存區(qū)中包含了頂點(diǎn)數(shù)據(jù)的索引值

buffer: 自己創(chuàng)建的緩存區(qū)對象

接下來棋枕,我們需要做的是填充剛剛申請的緩存區(qū)白修,我們需要使用一個(gè)符合GLSL語法的數(shù)據(jù)格式,Javascript中可用Float32Array類型來創(chuàng)建支持GLSL的數(shù)據(jù)重斑。使用bufferData函數(shù)將數(shù)據(jù)放入緩存區(qū)內(nèi)兵睛。

gl.bufferData(target, size, usage)

target: 同上
size: 為多個(gè)頂點(diǎn)坐標(biāo)的集合數(shù)組
usage: 表示程序?qū)⑷绾问褂镁彺鎱^(qū)中的數(shù)據(jù)

  • gl.STATIC_DRAW : 只會向緩存區(qū)對象中寫入一次數(shù)據(jù),但需要繪制很多次
  • gl.STREAM_DRAW : 只會向緩存區(qū)對象中寫入一次數(shù)據(jù)窥浪,然后繪制若干次
  • gl.DYNAMIC_DRAW : 會想緩存區(qū)對象中多次寫入數(shù)據(jù)祖很,并繪制很多次

緩存區(qū)中已經(jīng)存儲了多個(gè)頂點(diǎn)坐標(biāo),接下來我們需要將此數(shù)據(jù)運(yùn)用到對應(yīng)的著色器上漾脂,才能真正的繪制出來可視化圖像假颇,如何傳遞呢?首先我們需要在著色器中建立一個(gè)attribute類型的變量以方便我們操作骨稿,著色器中的對象笨鸡,著色器中存在對象之后,我們可以使用Javascript中getAttribLocation函數(shù)獲取著色器中的attribute類型變量啊终,并且通過vertexAttribPointer將其賦值改變镜豹,從而達(dá)到改變圖像呈現(xiàn)。

gl.getAttribLocation(program,name)

param: webgl之前創(chuàng)建的進(jìn)程
name: 變量名稱

gl.vertexAttribPointer(name, size, type, normalized, stride, offset)

name: 指定要賦值的attribute變量位置
size: 指定每個(gè)頂點(diǎn)數(shù)據(jù)的分量個(gè)數(shù)(1或4)
type: 指定傳入的數(shù)據(jù)格式

  • gl.BYTE: 字節(jié)型, 取值范圍[-128, 127]
  • gl.SHORT: 短整型,取值范圍[-32768, 32767]
  • gl.UNSIGNED_BYTE: 無符號字節(jié)型,取值范圍[0, 255]
  • gl.UNSIGNED_SHORT: 無符號短整型, 取值范圍[0, 65535]
  • gl.FLOAT: 浮點(diǎn)型

normalized: 表明是否將非浮點(diǎn)數(shù)的數(shù)據(jù)歸入到[0, 1]或[-1, 1]區(qū)間
stride: 指定相鄰2個(gè)頂點(diǎn)間的字節(jié)數(shù)蓝牲,默認(rèn)為0
offset: 指定緩存區(qū)對象中的偏移量,設(shè)置為0即可

如為2泰讽,則
new Float32Array([
    1.0, 1.0,
    1.0,1.0
])
代表2個(gè)頂點(diǎn)
如為4例衍,則
new Float32Array([
    1.0, 1.0, 1.0,1.0
])
代表1個(gè)頂點(diǎn)

現(xiàn)在緩存區(qū)已經(jīng)存在多個(gè)頂點(diǎn)數(shù)據(jù)昔期,接下來我們來啟用攜帶緩存區(qū)數(shù)據(jù)的attribute變量,使用enableVertexAttribArray來啟用對應(yīng)變量佛玄。

gl.enableVertexAttribArray(name)

name: 待啟動的變量指針硼一,也就是名稱
所有的緩存區(qū)操作步驟我們都已經(jīng)完成,那么接下來我們可以繪制出緩存區(qū)中的多個(gè)頂點(diǎn)

gl.drawArrays(mode, first, count)

mode: 需要繪制的圖像形狀

  • gl.POINTS: 繪制一個(gè)點(diǎn)梦抢。
  • gl.LINE_STRIP: 繪制一條直線到下一個(gè)頂點(diǎn)般贼。
  • gl.LINE_LOOP: 繪制一條首尾相連的線。
  • gl.LINES: 繪制一條線奥吩。
  • gl.TRIANGLES: 繪制一個(gè)三角形哼蛆。
    first: 繪制的開始點(diǎn)
    count: 需要繪制的圖形個(gè)數(shù)
    看看屏幕吧,是不是出來了好多點(diǎn)霞赫,接下來我們就可以來繪制對應(yīng)的波浪圖了腮介。
    接下來會講解如何繪制波浪圖。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末端衰,一起剝皮案震驚了整個(gè)濱河市叠洗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旅东,老刑警劉巖灭抑,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抵代,居然都是意外死亡名挥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門主守,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禀倔,“玉大人,你說我怎么就攤上這事参淫【群” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵涎才,是天一觀的道長鞋既。 經(jīng)常有香客問我,道長耍铜,這世上最難降的妖魔是什么邑闺? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮棕兼,結(jié)果婚禮上陡舅,老公的妹妹穿的比我還像新娘。我一直安慰自己伴挚,他們只是感情好靶衍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布灾炭。 她就那樣靜靜地躺著,像睡著了一般颅眶。 火紅的嫁衣襯著肌膚如雪蜈出。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天涛酗,我揣著相機(jī)與錄音铡原,去河邊找鬼。 笑死商叹,一個(gè)胖子當(dāng)著我的面吹牛燕刻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沈自,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酌儒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枯途?” 一聲冷哼從身側(cè)響起忌怎,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酪夷,沒想到半個(gè)月后榴啸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晚岭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年鸥印,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坦报。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡库说,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出片择,到底是詐尸還是另有隱情潜的,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布字管,位于F島的核電站啰挪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嘲叔。R本人自食惡果不足惜亡呵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望硫戈。 院中可真熱鬧锰什,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽果港。三九已至沦泌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辛掠,已是汗流浹背谢谦。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萝衩,地道東北人回挽。 一個(gè)月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像猩谊,于是被迫代替她去往敵國和親千劈。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

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