自定義著色器的編寫到使用(附圖片加載demo)

GLSL

GLSL語(yǔ)言就是編寫自定義著色器的語(yǔ)言,Xcode并不支持編譯和鏈接,需要開發(fā)者手動(dòng)去設(shè)置。GLSL語(yǔ)言編寫的著色器其本質(zhì)就是一個(gè)字符串,一般用.vsh和.fsh做后綴區(qū)分頂點(diǎn)著色器和片元著色器。
*在著色器中,盡可能不要用中文注釋,否則可能會(huì)報(bào)錯(cuò)

GLSL語(yǔ)言常用的API

  • 向量數(shù)據(jù)類型(vec2,vec3,vec4比較常用)
類型 描述
vec2,vec3,vec4 2分量、3分量、4分量浮點(diǎn)向量
ivec2,ivec3,ivec4 2分量、3分量、4分量整型向量
uvec2,uvec3,uvec4 2分量、3分量、4分量無(wú)符號(hào)整型向量
bvec2,bvec3,bvec4 2分量、3分量、4分量bool型向量
  • 矩陣數(shù)據(jù)類型
類型(mat列×行) 描述
mat2,mat2x2 兩?兩列
mat3,mat3x3 三行三列
mat4,mat4x4 四行四列
mat2x3 三行兩列
mat2x4 四行兩列
mat3x2 兩行三列
mat3x4 四行三列
mat4x2 兩行四列
mat4x3 三行四列
  • 變量存儲(chǔ)限定符

varying:當(dāng)片元著色器中用到頂點(diǎn)著色器中的某個(gè)變量時(shí),只需要在片元著色器中定義一樣的變量名然后用該限定符修飾即可。

attribute:該修飾符主要用于客戶端想頂點(diǎn)著色器傳遞頂點(diǎn)、紋理、顏色、法線等數(shù)據(jù)。

uniform:在著色器中該修飾符常用來(lái)修飾常量,在著色器中該修飾符修飾的屬性一般不建議修改,在客戶端傳入數(shù)據(jù)的時(shí)候修改。(例如視圖矩陣,投影矩陣,投影視圖矩陣等)

常用限定符

限定符 描述
<none> 只是普通的本地變量,外部不見,外部不可訪問(wèn)
const ?個(gè)編譯常量,或者說(shuō)是?個(gè)對(duì)函數(shù)來(lái)說(shuō)為只讀的參數(shù)
in/varying 從以前階段傳遞過(guò)來(lái)的變量
in/varying centroid ?個(gè)從以前的階段傳遞過(guò)來(lái)的變量,使?質(zhì)?插值
out/attribute 傳遞到下?個(gè)處理階段或者在?個(gè)函數(shù)中指定?個(gè)返回值
out/attribute centroid 傳遞到下?個(gè)處理階段,質(zhì)心插值
uniform ?個(gè)從客戶端代碼傳遞過(guò)來(lái)的變量,在頂點(diǎn)之間不做改變

自定義著色器創(chuàng)建及使用流程

一、創(chuàng)建

頂點(diǎn)著色器

  • 創(chuàng)建頂點(diǎn)坐標(biāo)和紋理坐標(biāo)的變量,用attribute修飾
  • 創(chuàng)建一個(gè)用varying修飾的紋理坐標(biāo),使得片元著色器能夠從頂點(diǎn)著色器獲取紋理坐標(biāo)
  • 創(chuàng)建內(nèi)建變量gl_Position(用于存放頂點(diǎn)著色器處理后的結(jié)構(gòu))
  • 創(chuàng)建main函數(shù),用于頂點(diǎn)坐標(biāo)的轉(zhuǎn)換處理及處理結(jié)果的賦值
//頂點(diǎn)坐標(biāo)
attribute vec4 position;
紋理坐標(biāo)
attribute vec2 textCoordinate;
//紋理坐標(biāo)
varying lowp vec2 varyTextCoord;

void main(){
    //通過(guò)????varying 修飾的??????varyTextCoord,??????????????????????????將紋理坐標(biāo)傳遞到片元著色器
    varyTextCoord = textCoordinate;
    //給內(nèi)江變量gl_Position賦值
    gl_Position = position;
}

片元著色器

  • 設(shè)置片元著色器float類型數(shù)據(jù)的默認(rèn)精度
  • 定義紋理坐標(biāo)變量,用varying修飾,變量名必須跟頂點(diǎn)著色器中的紋理坐標(biāo)變量名相同,否則獲取不到數(shù)據(jù)。
  • 定義紋理采樣器,用unifom修飾,用于獲取紋理坐標(biāo)每個(gè)像素點(diǎn)的紋素(紋理坐標(biāo)點(diǎn)的像素)
  • 創(chuàng)建內(nèi)建變量gl_FragColor(用于存放頂點(diǎn)著色器處理后的結(jié)構(gòu))
  • 創(chuàng)建main函數(shù),用于處理紋理的填充,并將處理后的顏色值賦值
//指定float的默認(rèn)精度
precision highp float;
//紋理坐標(biāo)
varying lowp vec2 varyTextCoord;
//紋理采樣器(獲取對(duì)應(yīng)的紋理ID)
uniform sampler2D colorMap;

void main(){
    //texture2D(紋理采樣器,紋理坐標(biāo)),獲取對(duì)應(yīng)坐標(biāo)紋素
    //紋理坐標(biāo)添加到對(duì)應(yīng)像素點(diǎn)上,即將讀取的紋素賦值給內(nèi)建變量 gl_FragColor
    gl_FragColor = texture2D(colorMap, varyTextCoord);
}

二、初始化
1、 創(chuàng)建圖層setupLayer

//1、創(chuàng)建圖層
- (void)setupLayer{
//    1、創(chuàng)建特殊圖層

    self.myEagLayer = (CAEAGLLayer*)self.layer;
    
//    2、設(shè)置scale
    [self setContentScaleFactor:[[UIScreen mainScreen] scale]];
    
//    3、設(shè)置描述屬性
    self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false, kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}

+ (Class)layerClass{
    return [CAEAGLLayer class];
}

參數(shù)說(shuō)明

屬性 說(shuō)明 默認(rèn)值
kEAGLDrawablePropertyRetainedBacking 表示繪圖表面顯示后,是否保留其內(nèi)容 false
kEAGLDrawablePropertyColorFormat 可繪制表面的內(nèi)部顏色緩存區(qū)格式 kEAGLColorFormatRGBA8

2、 創(chuàng)建上下文setupContext
上下文主要是用于保存OpenGL ES中的狀態(tài),是一個(gè)狀態(tài)機(jī),不論是GLKIt還是GLSL,都是需要context的

//2、創(chuàng)建上下文
- (void)setupContext{
//    1、指定OpenGL ES 渲染API版本
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
//    2、創(chuàng)建圖形上下文
    EAGLContext *context = [[EAGLContext alloc] initWithAPI:api];
//    3、判斷是否創(chuàng)建成功
    if (!context) {
        NSLog(@"Create context failed!");
        return;
    }
//    4、設(shè)置圖形上下文
    if (![EAGLContext setCurrentContext:context]) {
        NSLog(@"setCurrentContext failed");
        return;
    }
//    5、將局部變量賦值給全局變量
    self.myContext = context;
}

3、 清理緩沖區(qū)deleteRenderAndFrameBuffer

//3、清空緩存區(qū)
- (void)deleteRenderAndFrameBuffer{
//    清空渲染緩存區(qū)
    glDeleteBuffers(1, &_myColorRenderBuffer);
    self.myColorRenderBuffer = 0;
    
//    清空幀緩存區(qū)
    glDeleteBuffers(1, &_myColorFrameBuffer);
    self.myColorFrameBuffer = 0;
}

4、 申請(qǐng)標(biāo)識(shí)符并綁定到緩沖區(qū)

  • RenderBuffer:是一個(gè)通過(guò)應(yīng)用分配的2D圖像緩沖區(qū),需要附著在FrameBuffer上
  • FrameBuffer:是一個(gè)收集顏色、深度和模板緩存區(qū)的附著點(diǎn),簡(jiǎn)稱FBO,即是一個(gè)管理者,用來(lái)管理RenderBuffer,且FrameBuffer沒有實(shí)際的存儲(chǔ)功能,真正實(shí)現(xiàn)存儲(chǔ)的是RenderBuffer

FrameBuffer有3個(gè)附著點(diǎn)

  • 顏色附著點(diǎn)(Color Attachment):管理紋理、顏色緩沖區(qū)
  • 深度附著點(diǎn)(depth Attachment):會(huì)影響顏色緩沖區(qū),管理深度緩沖區(qū)(Depth Buffer)
  • 模板附著點(diǎn)(Stencil Attachment):管理模板緩沖區(qū)(Stencil Buffer)
    RenderBuffer有3種緩存區(qū)
  • 深度緩存區(qū)(Depth Buffer):存儲(chǔ)深度值等
  • 紋理緩存區(qū):存儲(chǔ)紋理坐標(biāo)中對(duì)應(yīng)的紋素、顏色值等
  • 模板緩存區(qū)(Stencil Buffer):存儲(chǔ)模板

設(shè)置RenderBuffer


- (void)setupRenderBuffer{
//    1、定義一個(gè)緩存區(qū)ID
    GLuint buffer;
    
//    2、申請(qǐng)一個(gè)緩存區(qū)標(biāo)識(shí)符
    glGenRenderbuffers(1, &buffer);
    
//    3、賦值給全局變量
    self.myColorRenderBuffer = buffer;
    
//    4、將標(biāo)識(shí)符綁定到GL_RENDERBUFFER
    glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);
    
//    5、將可繪制對(duì)象drawable object的CAEAGLLayer的存儲(chǔ)綁定到OpenGL ES renderBuffer對(duì)象
    [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];
}

設(shè)置FrameBuffer,將RenderBuffer通過(guò)glFramebufferRenderbuffer函數(shù)綁定到FrameBuffer中的GL_COLOR_ATTACHMENT0附著點(diǎn)上,通過(guò)FrameBuffer來(lái)管理RenderBuffer,RenderBuffer存儲(chǔ)相關(guān)數(shù)據(jù)到相應(yīng)緩存區(qū)

//5、設(shè)置FrameBuffer
- (void)setupFrameBuffer{
//    1、定義一個(gè)ID
    GLuint buffer;
    
//    2、申請(qǐng)一個(gè)緩存區(qū)標(biāo)識(shí)符
    glGenBuffers(1, &buffer);
    
//    3、賦值給全局變量
    self.myColorFrameBuffer = buffer;
    
//    4、將標(biāo)識(shí)符綁定到GL_FRAMEBUFFER
    glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);
    
//    5、將渲染緩存區(qū)的myColorRenderBuffer 通過(guò) glFramebufferRenderbuffer函數(shù)綁定到GL_COLOR_ATTACHMENT0上
    /*
     glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
     參數(shù)1:綁定到的目標(biāo)
     參數(shù)2:FrameBuffer的附著點(diǎn)
     參數(shù)3:需要綁定的渲染緩沖區(qū)目標(biāo)
     參數(shù)4:渲染緩沖區(qū)
     */
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
}

二、著色器的鏈接

1、初始化
初始化背景顏色,清理緩存,需要將視口大小設(shè)置為屏幕大小

//    設(shè)置清屏顏色 & 清除屏幕
    glClearColor(0.3f, 0.45f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
//    1、設(shè)置視口大小
    CGFloat scale = [[UIScreen mainScreen] scale];
    glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale);

2、加載自定義著色器


自定義著色器的加載流程.png
  • 讀取自定義著色器文件的前提是需要獲得文件的路徑,將其傳入loadShaders函數(shù)進(jìn)行加載
NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"vsh"]; 
NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"fsh"];

3、編譯shader

  • 根據(jù)文件路徑讀取著色器文件中的源碼字符串,并將其轉(zhuǎn)換為c中的字符串,類型為GLchar
  • 根據(jù)傳入的著色器類型type,調(diào)用glCreateShader函數(shù)創(chuàng)建一個(gè)帶有唯一標(biāo)識(shí)ID的著色器,此時(shí)著色器中并沒有附加相對(duì)應(yīng)的源碼
  • 將讀取的著色器源碼通過(guò)glShaderSource函數(shù)附加到創(chuàng)建的shader上,并將shader的ID返回給loadShaders函數(shù)中shader,以ID來(lái)獲取并使用對(duì)應(yīng)的著色器
  • 通過(guò)glCompileShader函數(shù)將shader上附加的源碼編譯成目標(biāo)代碼
- (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file{
    //1.讀取文件路徑字符串
    NSString* content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
    const GLchar* source = (GLchar *)[content UTF8String];

    NSLog(@"content %@, source %s", content, source);
    //2.創(chuàng)建一個(gè)shader(根據(jù)type類型)
    *shader = glCreateShader(type);

    //3.將著色器源碼附加到著色器對(duì)象上。
    //參數(shù)1:shader,要編譯的著色器對(duì)象 *shader
    //參數(shù)2:numOfStrings,傳遞的源碼字符串?dāng)?shù)量 1個(gè)
    //參數(shù)3:strings,著色器程序的源碼(真正的著色器程序源碼)
    //參數(shù)4:lenOfStrings,長(zhǎng)度,具有每個(gè)字符串長(zhǎng)度的數(shù)組,或NULL,這意味著字符串是NULL終止的
    glShaderSource(*shader, 1, &source,NULL);
    
    NSLog(@"shader %d", *shader);

    //4.把著色器源代碼編譯成目標(biāo)代碼
    glCompileShader(*shader);
}

4、加載著色器
分別將頂點(diǎn)著色器和片元著色器編譯完成后,并返回著色器對(duì)應(yīng)的ID,然后通過(guò)glAttachShader函數(shù)將頂點(diǎn)和片元的shader分別附著到program上,然后釋放不再使用的shader,并賦值給全局的program。

-(GLuint)loadShaders:(NSString *)vert Withfrag:(NSString *)frag
{
    //1.定義2個(gè)零時(shí)著色器對(duì)象
    GLuint verShader, fragShader;
    //創(chuàng)建program
    GLint program = glCreateProgram();

    //2.編譯頂點(diǎn)著色程序、片元著色器程序
    //參數(shù)1:編譯完存儲(chǔ)的底層地址
    //參數(shù)2:編譯的類型,GL_VERTEX_SHADER(頂點(diǎn))、GL_FRAGMENT_SHADER(片元)
    //參數(shù)3:文件路徑
    [self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];
    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];
    
    NSLog(@"verShader %d, fragShader: %d", verShader, fragShader);

    //3.創(chuàng)建最終的程序
    glAttachShader(program, verShader);
    glAttachShader(program, fragShader);

    //4.釋放不需要的shader
    glDeleteShader(verShader);
    glDeleteShader(fragShader);

    return program;
}

5、鏈接program

  • 通過(guò)glLinkProgram函數(shù)鏈接program
  • 可以通過(guò)glGetProgramiv函數(shù)通過(guò)制定值GL_LINK_STATUS獲取鏈接的狀態(tài),判斷鏈接是成功還是失敗
  • 如果鏈接失敗,可以通過(guò)glGetProgramIngoLog函數(shù)獲取錯(cuò)誤信息日志,根據(jù)錯(cuò)誤信息一致去排查問(wèn)題
    6、使用鏈接成功的program
glUseProgram(self.myPrograme);

三、設(shè)置參數(shù)

1、處理頂點(diǎn)數(shù)據(jù)

  • 設(shè)置頂點(diǎn)數(shù)據(jù):主要是初始化頂點(diǎn)坐標(biāo)和紋理坐標(biāo)
  • 開辟頂點(diǎn)緩存區(qū):用于將頂點(diǎn)數(shù)據(jù)從CPU拷貝至GPU
  • 打開頂點(diǎn)/片元的通道
    2、開辟頂點(diǎn)緩沖區(qū)
  • 通過(guò)GLuint定義一個(gè)頂點(diǎn)緩存區(qū)ID
  • 通過(guò)glGenBuffers函數(shù),申請(qǐng)一個(gè)頂點(diǎn)緩存區(qū)標(biāo)識(shí)符
  • 通過(guò)glBindBuffers函數(shù),將緩存區(qū)的標(biāo)識(shí)符綁定到GL_ARRAY_BUFFER
  • 通過(guò)glBufferData函數(shù),將頂點(diǎn)數(shù)據(jù)copy到GPU中
 GLuint attrBuffer;
    glGenBuffers(1, &attrBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);

3、打開頂點(diǎn)、片元通道

  • 通過(guò)glGetAttribLocation函數(shù),獲取vertex attribute的入口,需要傳入兩個(gè)參數(shù),一個(gè)是program,一個(gè)是自定義著色器文件中變量名字符串,這里著重強(qiáng)調(diào)下!??!第二個(gè)參數(shù)的字符串必須與著色器文件中對(duì)應(yīng)的變量名保持一致!
  • 通過(guò)glEnableVertexAttribArray函數(shù),設(shè)置合適的格式從buffer里讀取數(shù)據(jù),即設(shè)置讀取入口
  • 通過(guò)glVertexAttribPointer函數(shù),設(shè)置讀取方式
//     (1)注意:第二參數(shù)字符串必須和shaderv.vsh中的輸入變量:position保持一致
    GLuint position = glGetAttribLocation(self.myPrograme, "position");
//     (2).設(shè)置合適的格式從buffer里面讀取數(shù)據(jù)
    glEnableVertexAttribArray(position);
//     (3).設(shè)置讀取方式
//          參數(shù)1:index,頂點(diǎn)數(shù)據(jù)的索引
//          參數(shù)2:size,每個(gè)頂點(diǎn)屬性的組件數(shù)量,1,2,3,或者4.默認(rèn)初始值是4.
//                 參數(shù)3:type,數(shù)據(jù)中的每個(gè)組件的類型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默認(rèn)初始值為GL_FLOAT
//          參數(shù)4:normalized,固定點(diǎn)數(shù)據(jù)值是否應(yīng)該歸一化,或者直接轉(zhuǎn)換為固定值。(GL_FALSE)
//          參數(shù)5:stride,連續(xù)頂點(diǎn)屬性之間的偏移量,默認(rèn)為0;
//          參數(shù)6:指定一個(gè)指針,指向數(shù)組中的第一個(gè)頂點(diǎn)屬性的第一個(gè)組件。默認(rèn)為0
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);
    
//    9、處理紋理數(shù)據(jù)
//    (1).glGetAttribLocation,用來(lái)獲取vertex attribute的入口的.
//    注意:第二參數(shù)字符串必須和shaderv.vsh中的輸入變量:textCoordinate保持一致
//    (2).設(shè)置合適的格式從buffer里面讀取數(shù)據(jù)
//    (3).設(shè)置讀取方式
    GLuint textColor = glGetAttribLocation(self.myPrograme, "textCoordinate");
    glEnableVertexAttribArray(textColor);

4、加載紋理
將png/jpg圖片解壓成位圖,并通過(guò)自定義著色器讀取紋理每個(gè)像素點(diǎn)的紋素

  • 紋理解壓縮:將UIImage轉(zhuǎn)換為CGImageRef
  • 圖片重繪:使用CGContextRef常見的上下文,調(diào)用CGContextDrawImage函數(shù)使用默認(rèn)方式進(jìn)行繪制,再繪制之前,需要獲取圖片的大小、寬、高等數(shù)據(jù),因?yàn)槔L制時(shí)需要使用這些數(shù)據(jù)
  • 綁定紋理:通過(guò)glBindTexture函數(shù)綁定,當(dāng)只有一個(gè)紋理的時(shí)候,默認(rèn)的紋理ID是0,且0一直是激活狀態(tài),因此是可以省略glGenTexture的
  • 設(shè)置紋理屬性:通過(guò)glTexParameteri函數(shù)分別設(shè)置 放大/縮小的過(guò)濾方式 和 S/T的環(huán)繞模式
  • 載入紋理:通過(guò)glTexImage2D函數(shù)載入紋理,載入完成后,釋放指向紋理數(shù)據(jù)的指針
    5、設(shè)置紋理采樣器
    主要是獲取紋理中對(duì)應(yīng)像素點(diǎn)的的顏色值,即紋素
  • 通過(guò)glGetUniformLocation函數(shù),獲取fragment uniform的入口,需要傳入兩個(gè)參數(shù),一個(gè)是program,一個(gè)是自定義片元著色器文件中變量名字符串colorMap,這里著重強(qiáng)調(diào)下?。?!第二個(gè)參數(shù)的字符串必須與著色器文件中對(duì)應(yīng)的變量名保持一致!
  • 通過(guò)glUniform1i函數(shù)獲取紋素,有兩個(gè)參數(shù),第一個(gè)參數(shù)是 fragment uniform的入口,本質(zhì)也是一個(gè)ID,第二個(gè)參數(shù)是紋理的ID,使用的是默認(rèn)的ID 0

四、繪制

  • 調(diào)用glDrawArrays函數(shù)指定圖元連接方式進(jìn)行繪制
  • context調(diào)用presentRenderbuffer函數(shù)將繪制好的圖片渲染到屏幕上進(jìn)行顯示

完整demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,365評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,346評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,118評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,558評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,739評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,980評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,347評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,702評(píng)論 2 370