在 iOS 中使用 GLSL 實(shí)現(xiàn)抖音特效

本文通過(guò)模仿抖音中幾種特效的實(shí)現(xiàn)妓盲,來(lái)講解 GLSL 的實(shí)際應(yīng)用杂拨。

前言

本文的靈感來(lái)自于 《當(dāng)一個(gè) Android 開(kāi)發(fā)玩抖音玩瘋了之后(二)》 這篇文章。

這位博主在 Android 平臺(tái)上悯衬,通過(guò)自己的分析弹沽,嘗試還原了抖音上的幾種視頻特效。他是通過(guò)「部分 GLSL 代碼 + 部分 Java 代碼」的方式來(lái)實(shí)現(xiàn)的筋粗。

讀完之后策橘,在膜拜之余,我產(chǎn)生了一個(gè)大膽的想法:我可不可以在 iOS 上娜亿,只通過(guò)純 GLSL 的編寫丽已,來(lái)實(shí)現(xiàn)類似的效果呢?

很好的想法暇唾,不過(guò)促脉,由于抖音的特效是基于視頻的濾鏡,我們?cè)谶@之前只講到了關(guān)于圖片的渲染策州,如果馬上跳躍到視頻的部分瘸味,好像有點(diǎn)超綱了。

于是够挂,我又有了一個(gè)更大膽的想法:我可不可以在 iOS 上旁仿,只通過(guò)純 GLSL 的編寫,在靜態(tài)的圖片上孽糖,實(shí)現(xiàn)類似的效果呢枯冈?

這樣的話,我們就可以把更多的注意力放在 GLSL 本身办悟,而不是視頻的采集和輸出上面尘奏。

于是,就有了這篇文章病蛉。為了無(wú)縫地過(guò)渡炫加,我會(huì)沿用之前 GLSL 渲染的例子 ,只改變 Shader 部分的代碼铺然,來(lái)嘗試還原那篇文章中實(shí)現(xiàn)的六種特效俗孝。

〇、動(dòng)畫

你可能會(huì)問(wèn):抖音上的特效都是動(dòng)態(tài)的魄健,要怎么把動(dòng)態(tài)的效果赋铝,加到一個(gè)靜態(tài)的圖片上呢?

問(wèn)的好沽瘦,所以第一步革骨,我們就要讓靜態(tài)的圖片動(dòng)起來(lái)农尖。

回想一下,我們?cè)?UIKit 中實(shí)現(xiàn)的動(dòng)畫苛蒲,無(wú)非就是把指令發(fā)送給 CoreAnimation卤橄,然后在屏幕刷新的時(shí)候,CoreAnimation 會(huì)去逐幀計(jì)算當(dāng)前應(yīng)該顯示的圖像臂外。

這里的重點(diǎn)是「逐幀計(jì)算」窟扑。在 OpenGL ES 中也是類似,我們實(shí)現(xiàn)動(dòng)畫的方式漏健,就是自己去計(jì)算每一幀應(yīng)該顯示的圖像嚎货,然后在屏幕刷新的時(shí)候,重新渲染蔫浆。

這個(gè)「逐幀計(jì)算」的過(guò)程殖属,我們是放到 Shader 中進(jìn)行的。然后我們可以通過(guò)一個(gè)表示時(shí)間的參數(shù)瓦盛,在重新渲染的時(shí)候洗显,傳入當(dāng)前的時(shí)間,讓 Shader 計(jì)算出當(dāng)前動(dòng)畫的進(jìn)度原环。至于重新渲染的時(shí)機(jī)挠唆,則是依靠 CADisplayLink 來(lái)實(shí)現(xiàn)的。

具體代碼大概像這樣:

self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeAction)];
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
- (void)timeAction {
    glUseProgram(self.program);
    glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);
    
    // 傳入時(shí)間
    CGFloat currentTime = self.displayLink.timestamp - self.startTimeInterval;
    GLuint time = glGetUniformLocation(self.program, "Time");
    glUniform1f(time, currentTime);

    // 清除畫布
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(1, 1, 1, 1);
    
    // 重繪
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    [self.context presentRenderbuffer:GL_RENDERBUFFER];
}

相應(yīng)地嘱吗,在 Shader 中有一個(gè) uniform 修飾的 Time 參數(shù):

uniform float Time;

這樣 Shader 就可以通過(guò) Time 來(lái)計(jì)算出當(dāng)前應(yīng)該顯示的圖像了玄组。

一、縮放

1谒麦、最終效果

我們要實(shí)現(xiàn)的第一種效果是「縮放」俄讹,看起來(lái)很簡(jiǎn)單,可以通過(guò)修改頂點(diǎn)坐標(biāo)和紋理坐標(biāo)的對(duì)應(yīng)關(guān)系來(lái)實(shí)現(xiàn)绕德。

這是一個(gè)很基礎(chǔ)的效果患膛,在下面的其它特效中還會(huì)用到。修改坐標(biāo)的對(duì)應(yīng)關(guān)系可以通過(guò)修改頂點(diǎn)著色器耻蛇,或者修改片段著色器來(lái)實(shí)現(xiàn)剩瓶。 這里先講修改頂點(diǎn)著色器的方式,在后面的特效中會(huì)再提一下修改片段著色器的方式城丧。

2、代碼實(shí)現(xiàn)

頂點(diǎn)著色器代碼:

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

void main (void) {
    float duration = 0.6;
    float maxAmplitude = 0.3;
    
    float time = mod(Time, duration);
    float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));
    
    gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
    TextureCoordsVarying = TextureCoords;
}

這里的 duration 表示一次縮放周期的時(shí)長(zhǎng)豌鹤,mod(Time, duration) 表示將傳入的時(shí)間轉(zhuǎn)換到一個(gè)周期內(nèi)亡哄,即 time 的范圍是 0 ~ 0.6amplitude 表示振幅布疙,引入 PI 的目的是為了使用 sin 函數(shù)蚊惯,將 amplitude 的范圍控制在 1.0 ~ 1.3 之間愿卸,并隨著時(shí)間變化。

這里放大的關(guān)鍵在于 vec4(Position.x * amplitude, Position.y * amplitude, Position.zw) 截型,我們將頂點(diǎn)坐標(biāo)的 xy 分別乘上一個(gè)放大系數(shù)趴荸,在紋理坐標(biāo)不變的情況下,就達(dá)到了拉伸的效果宦焦。

二发钝、靈魂出竅

1、最終效果

「靈魂出竅」看上去是兩個(gè)層的疊加波闹,并且上面的那層隨著時(shí)間的推移酝豪,會(huì)逐漸放大且不透明度逐漸降低。這里也用到了放大的效果精堕,我們這次用片段著色器來(lái)實(shí)現(xiàn)孵淘。

2、代碼實(shí)現(xiàn)

片段著色器代碼:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
    float duration = 0.7;
    float maxAlpha = 0.4;
    float maxScale = 1.8;
    
    float progress = mod(Time, duration) / duration; // 0~1
    float alpha = maxAlpha * (1.0 - progress);
    float scale = 1.0 + (maxScale - 1.0) * progress;
    
    float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
    float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
    vec2 weakTextureCoords = vec2(weakX, weakY);
    
    vec4 weakMask = texture2D(Texture, weakTextureCoords);
    
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    
    gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}

首先是放大的效果歹篓。關(guān)鍵點(diǎn)在于 weakXweakY 的計(jì)算瘫证,比如 0.5 + (TextureCoordsVarying.x - 0.5) / scale 這一句的意思是,將頂點(diǎn)坐標(biāo)對(duì)應(yīng)的紋理坐標(biāo)的 x 值到紋理中點(diǎn)的距離庄撮,縮小一定的比例背捌。這次我們是改變了紋理坐標(biāo),而保持頂點(diǎn)坐標(biāo)不變重窟,同樣達(dá)到了拉伸的效果载萌。

然后是兩層疊加的效果蛙讥。通過(guò)上面的計(jì)算狼忱,我們得到了兩個(gè)紋理顏色值 weakMaskmaskweakMask 是在 mask 的基礎(chǔ)上做了放大處理展蒂。

我們將兩個(gè)顏色值進(jìn)行疊加需要用到一個(gè)公式:最終色 = 基色 * a% + 混合色 * (1 - a%) 厅翔,這個(gè)公式來(lái)自 混合模式中的正常模式 乖坠。

這個(gè)公式表明了一個(gè)不透明的層和一個(gè)半透明的層進(jìn)行疊加,重疊部分的最終顏色值刀闷。因此熊泵,上面疊加的最終結(jié)果是 mask * (1.0 - alpha) + weakMask * alpha

三甸昏、抖動(dòng)

1顽分、最終效果

「抖動(dòng)」是很經(jīng)典的抖音的顏色偏移效果,其實(shí)這個(gè)效果實(shí)現(xiàn)起來(lái)還挺簡(jiǎn)單的施蜜。另外卒蘸,除了顏色偏移,可以看到還有微弱的放大效果。

2缸沃、代碼實(shí)現(xiàn)

片段著色器代碼:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
    float duration = 0.7;
    float maxScale = 1.1;
    float offset = 0.02;
    
    float progress = mod(Time, duration) / duration; // 0~1
    vec2 offsetCoords = vec2(offset, offset) * progress;
    float scale = 1.0 + (maxScale - 1.0) * progress;
    
    vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
    
    vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
    vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
    vec4 mask = texture2D(Texture, ScaleTextureCoords);
    
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

這里的放大和上面類似恰起,我們主要看一下顏色偏移。顏色偏移是對(duì)三個(gè)顏色通道進(jìn)行分離趾牧,并且給紅色通道和藍(lán)色通道添加了不同的位置偏移检盼,代碼很容易看懂。

四翘单、閃白

1吨枉、最終效果

「閃白」其實(shí)看起來(lái)一點(diǎn)兒也不酷炫,而且看久了還容易被閃瞎县恕。這個(gè)效果實(shí)現(xiàn)起來(lái)也十分簡(jiǎn)單东羹,無(wú)非就是疊加一個(gè)白色層,然后白色層的透明度隨著時(shí)間不斷地變化忠烛。

2属提、代碼實(shí)現(xiàn)

片段著色器代碼:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

void main (void) {
    float duration = 0.6;
    
    float time = mod(Time, duration);
    
    vec4 whiteMask = vec4(1.0, 1.0, 1.0, 1.0);
    float amplitude = abs(sin(time * (PI / duration)));
    
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    
    gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
}

在上面「靈魂出竅」的例子中,我們已經(jīng)知道了如何實(shí)現(xiàn)兩個(gè)層的疊加美尸。這里我們只需要?jiǎng)?chuàng)建一個(gè)白色的層 whiteMask冤议,然后根據(jù)當(dāng)前的透明度來(lái)計(jì)算最終的顏色值即可。

五师坎、毛刺

1恕酸、最終效果

終于有了一個(gè)稍微復(fù)雜一點(diǎn)的效果,「毛刺」看上去是「撕裂 + 微弱的顏色偏移」胯陋。顏色偏移我們?cè)谏厦嬉呀?jīng)實(shí)現(xiàn)蕊温,這里主要是講解撕裂的效果。

具體的思路是遏乔,我們讓每一行像素隨機(jī)偏移 -1 ~ 1 的距離(這里的 -1 ~ 1 是對(duì)于紋理坐標(biāo)來(lái)說(shuō)的)义矛,但是如果整個(gè)畫面都偏移比較大的值,那我們可能都看不出原來(lái)圖像的樣子盟萨。所以我們的邏輯是凉翻,設(shè)定一個(gè)閾值,小于這個(gè)閾值才進(jìn)行偏移捻激,超過(guò)這個(gè)閾值則乘上一個(gè)縮小系數(shù)制轰。

則最終呈現(xiàn)的效果是:絕大部分的行都會(huì)進(jìn)行微小的偏移,只有少量的行會(huì)進(jìn)行較大偏移胞谭。

2垃杖、代碼實(shí)現(xiàn)

片段著色器代碼:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

float rand(float n) {
    return fract(sin(n) * 43758.5453123);
}

void main (void) {
    float maxJitter = 0.06;
    float duration = 0.3;
    float colorROffset = 0.01;
    float colorBOffset = -0.025;
    
    float time = mod(Time, duration * 2.0);
    float amplitude = max(sin(time * (PI / duration)), 0.0);
    
    float jitter = rand(TextureCoordsVarying.y) * 2.0 - 1.0; // -1~1
    bool needOffset = abs(jitter) < maxJitter * amplitude;
    
    float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
    vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);
    
    vec4 mask = texture2D(Texture, textureCoords);
    vec4 maskR = texture2D(Texture, textureCoords + vec2(colorROffset * amplitude, 0.0));
    vec4 maskB = texture2D(Texture, textureCoords + vec2(colorBOffset * amplitude, 0.0));
    
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

上面提到的像素隨機(jī)偏移需要用到隨機(jī)數(shù),可惜 GLSL 里并沒(méi)有內(nèi)置的隨機(jī)函數(shù)丈屹,所以我們需要自己實(shí)現(xiàn)一個(gè)缩滨。

這個(gè) float rand(float n) 的實(shí)現(xiàn)看上去很神奇,它其實(shí)是來(lái)自 這里 ,江湖人稱「噪聲函數(shù)」脉漏。

它其實(shí)是一個(gè)偽隨機(jī)函數(shù),本質(zhì)上是一個(gè) Hash 函數(shù)袖牙。但在這里我們可以把它當(dāng)成隨機(jī)函數(shù)來(lái)使用侧巨,它的返回值范圍是 0 ~ 1。如果你對(duì)這個(gè)函數(shù)想了解更多的話可以看 這里 鞭达。

六司忱、幻覺(jué)

1、最終效果

「幻覺(jué)」這個(gè)效果有點(diǎn)一言難盡畴蹭,因?yàn)槠鋵?shí)看上去并不是很像坦仍。原來(lái)的效果是基于視頻上一幀的結(jié)果去合成,靜態(tài)的圖片很難模擬出這種情況叨襟。不管怎么說(shuō)繁扎,既然已經(jīng)盡力,不像就不像吧糊闽,下面講一下我的實(shí)現(xiàn)思路梳玫。

可以看出這個(gè)效果是殘影顏色偏移的疊加。

殘影的效果還好右犹,在移動(dòng)的過(guò)程中提澎,每經(jīng)過(guò)一段時(shí)間間隔,根據(jù)當(dāng)前的位置去創(chuàng)建一個(gè)新層念链,并且新層的不透明度隨著時(shí)間逐漸減弱盼忌。于是在一個(gè)移動(dòng)周期內(nèi),可以看到很多透明度不同的層疊加在一起掂墓,從而形成殘影的效果谦纱。

然后是這個(gè)顏色偏移。我們可以看到梆暮,物體移動(dòng)的過(guò)程是藍(lán)色在前面服协,紅色在后面。所以整個(gè)過(guò)程可以理解成:在移動(dòng)的過(guò)程中啦粹,每間隔一段時(shí)間偿荷,遺失了一部分紅色通道的值在原來(lái)的位置,并且這部分紅色通道的值唠椭,隨著時(shí)間偏移跳纳,會(huì)逐漸恢復(fù)。

2贪嫂、代碼實(shí)現(xiàn)

片段著色器代碼:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;
const float duration = 2.0;

vec4 getMask(float time, vec2 textureCoords, float padding) {
    vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),
                            cos(time * (PI * 2.0 / duration)));
    vec2 translationTextureCoords = textureCoords + padding * translation;
    vec4 mask = texture2D(Texture, translationTextureCoords);
    
    return mask;
}

float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
    float time = mod(duration + currentTime - startTime, duration);
    return min(time, hideTime);
}

void main (void) {
    float time = mod(Time, duration);
    
    float scale = 1.2;
    float padding = 0.5 * (1.0 - 1.0 / scale);
    vec2 textureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
    
    float hideTime = 0.9;
    float timeGap = 0.2;
    
    float maxAlphaR = 0.5; // max R
    float maxAlphaG = 0.05; // max G
    float maxAlphaB = 0.05; // max B
    
    vec4 mask = getMask(time, textureCoords, padding);
    float alphaR = 1.0; // R
    float alphaG = 1.0; // G
    float alphaB = 1.0; // B
    
    vec4 resultMask = vec4(0, 0, 0, 0);
    
    for (float f = 0.0; f < duration; f += timeGap) {
        float tmpTime = f;
        vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
        float tmpAlphaR = maxAlphaR - maxAlphaR * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
        float tmpAlphaG = maxAlphaG - maxAlphaG * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
        float tmpAlphaB = maxAlphaB - maxAlphaB * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
     
        resultMask += vec4(tmpMask.r * tmpAlphaR,
                           tmpMask.g * tmpAlphaG,
                           tmpMask.b * tmpAlphaB,
                           1.0);
        alphaR -= tmpAlphaR;
        alphaG -= tmpAlphaG;
        alphaB -= tmpAlphaB;
    }
    resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);

    gl_FragColor = resultMask;
}

從代碼的行數(shù)可以看出寺庄,這個(gè)效果應(yīng)該是里面最復(fù)雜的。為了實(shí)現(xiàn)殘影,我們先讓圖片隨時(shí)間做圓周運(yùn)動(dòng)斗塘。

vec4 getMask(float time, vec2 textureCoords, float padding) 這個(gè)函數(shù)可以計(jì)算出赢织,在某個(gè)時(shí)刻圖片的具體位置。通過(guò)它我們可以每經(jīng)過(guò)一段時(shí)間馍盟,去生成一個(gè)新的層于置。

float maskAlphaProgress(float currentTime, float hideTime, float startTime) 這個(gè)函數(shù)可以計(jì)算出,某個(gè)時(shí)刻創(chuàng)建的層贞岭,在當(dāng)前時(shí)刻的透明度八毯。

maxAlphaRmaxAlphaG 瞄桨、 maxAlphaB 分別指定了新層初始的三個(gè)顏色通道的透明度话速。因?yàn)樽罱K的效果是殘留紅色,所以主要保留了紅色通道的值芯侥。

然后是疊加泊交,和兩層疊加的情況類似,這里通過(guò) for 循環(huán)來(lái)累加每一層的每個(gè)通道乘上自身的透明度的值筹麸,算出最終的顏色值 resultMask 活合。

注: 在 iOS 的模擬器上,只能用 CPU 來(lái)模擬 GPU 的功能物赶。所以在模擬器上運(yùn)行上面的代碼時(shí)白指,可能會(huì)十分卡頓。尤其是最后這個(gè)效果酵紫,由于計(jì)算量太大告嘲,親測(cè)模擬器顯示不出來(lái)。因此如果要跑代碼奖地,最好使用真機(jī)運(yùn)行橄唬。

源碼

請(qǐng)到 GitHub 上查看完整代碼。

參考

獲取更佳的閱讀體驗(yàn)参歹,請(qǐng)?jiān)L問(wèn)原文地址【Lyman's Blog】在 iOS 中使用 GLSL 實(shí)現(xiàn)抖音特效

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仰楚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子犬庇,更是在濱河造成了極大的恐慌僧界,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臭挽,死亡現(xiàn)場(chǎng)離奇詭異捂襟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)欢峰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門葬荷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涨共,“玉大人,你說(shuō)我怎么就攤上這事宠漩【俜矗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵扒吁,是天一觀的道長(zhǎng)照筑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瘦陈,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任波俄,我火速辦了婚禮晨逝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘懦铺。我一直安慰自己捉貌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布冬念。 她就那樣靜靜地躺著趁窃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪急前。 梳的紋絲不亂的頭發(fā)上醒陆,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音裆针,去河邊找鬼刨摩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛世吨,可吹牛的內(nèi)容都是我干的澡刹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼耘婚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼罢浇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起沐祷,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嚷闭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后戈轿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體凌受,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年思杯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胜蛉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挠进。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖誊册,靈堂內(nèi)的尸體忽然破棺而出领突,到底是詐尸還是另有隱情,我是刑警寧澤案怯,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布君旦,位于F島的核電站,受9級(jí)特大地震影響嘲碱,放射性物質(zhì)發(fā)生泄漏金砍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一麦锯、第九天 我趴在偏房一處隱蔽的房頂上張望恕稠。 院中可真熱鬧,春花似錦扶欣、人聲如沸鹅巍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)骆捧。三九已至,卻和暖如春髓绽,著一層夾襖步出監(jiān)牢的瞬間敛苇,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工梧宫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留接谨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓塘匣,卻偏偏與公主長(zhǎng)得像脓豪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忌卤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353