OpenGL ES 使用GLSL語法自定義著色器來加載圖片

準備工作:

  1. 使用XCode創(chuàng)建一個普通工程叙淌,
  2. 導入一張圖片,png或jpg圖片
  3. 創(chuàng)建一個CSView 繼承自UIView
  4. 創(chuàng)建2個空文件愁铺,自定義頂點著色器文件起名為 shader_v.vsh 和 自定義片元著色器起名為 shader_f.fsh凿菩,注意后綴名不能錯。
  • 自定義頂點著色器shader_v.vsh中的代碼如下:
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main() {
    varyTextCoord = textCoordinate;
    gl_Position = position;
}
  • 自定義片元著色器 shader_f.fsh 中的代碼如下:
precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main() {
    lowp vec4 temp = texture2D(colorMap, varyTextCoord);
    gl_FragColor = temp;
}
  • 我們已經(jīng)自定義了頂點著色器和片元著色器帜讲,那么接下來我們就用這兩種著色器來繪制圖片衅谷,具體思路流程如下圖:
image.png
  1. 設(shè)置圖層 setupLayer
- (void)setupLayer {
    //1.創(chuàng)建特殊圖層
    /*
    重寫layerClass,將CCView返回的圖層從CALayer替換成CAEAGLLayer
    */
    self.myEagLayer = (CAEAGLLayer *)self.layer;
    //2.設(shè)置scale
    [self setContentScaleFactor:[UIScreen mainScreen].scale];
    //3.設(shè)置描述屬性似将,這里設(shè)置不維持渲染內(nèi)容以及顏色格式為RGBA8
    /*
    kEAGLDrawablePropertyRetainedBacking  表示繪圖表面顯示后获黔,是否保留其內(nèi)容蚀苛。
    kEAGLDrawablePropertyColorFormat
        可繪制表面的內(nèi)部顏色緩存區(qū)格式,這個key對應(yīng)的值是一個NSString指定特定顏色緩存區(qū)對象玷氏。默認是kEAGLColorFormatRGBA8堵未;

        kEAGLColorFormatRGBA8:32位RGBA的顏色,4*8=32位
        kEAGLColorFormatRGB565:16位RGB的顏色盏触,
        kEAGLColorFormatSRGBA8:sRGB代表了標準的紅渗蟹、綠、藍赞辩,即CRT顯示器雌芽、LCD顯示器、投影機辨嗽、打印機以及其他設(shè)備中色彩再現(xiàn)所使用的三個基本色素世落。sRGB的色彩空間基于獨立的色彩坐標,可以使色彩在不同的設(shè)備使用傳輸中對應(yīng)于同一個色彩坐標體系糟需,而不受這些設(shè)備各自具有的不同色彩坐標的影響屉佳。
    */
    self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false, kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}

/*
重寫layerClass,將CCView返回的圖層從CALayer替換成CAEAGLLayer
*/
+ (Class)layerClass {
    return [CAEAGLLayer class];
}

  1. 設(shè)置上下文 setupContext
- (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]) {
        return;
    }
    self.myContext = context;
}
  1. 清空緩存區(qū) deleteRenderAndFrameBuffer
- (void)deleteRenderAndFrameBuffer {
    /*
    buffer分為frame buffer 和 render buffer2個大類洲押。
    其中frame buffer 相當于render buffer的管理者武花。
    frame buffer object即稱FBO。
    render buffer則又可分為3類杈帐。colorBuffer髓堪、depthBuffer、stencilBuffer娘荡。
    */
    glDeleteBuffers(1, &_myColorRenderBuffer);
    self.myColorRenderBuffer = 0;
    glDeleteBuffers(1, &_myColorFrameBuffer);
    self.myColorFrameBuffer = 0;
}
  1. 設(shè)置渲染緩存區(qū) setupRenderBuffer
- (void)setupRenderBuffer {
    //1.定義一個緩存區(qū)ID
    GLuint buffer;
    //2. 申請一個緩存區(qū)標志
    glGenRenderbuffers(1, &buffer);
    self.myColorRenderBuffer = buffer;
    //3.將標識符綁定到GL_RENDERBUFFER
    glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);
    //4.將繪制對象drawable object's  CAEAGLLayer的存儲綁定到OpenGL ESrenderBuffer對象
    [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];
}
  1. 設(shè)置幀緩存區(qū) setupFrameBuffer
- (void)setupFrameBuffer {
    //1. 定義一個緩存區(qū)ID
    GLuint buffer;
    //2.申請一個緩存區(qū)標志
    glGenFramebuffers(1, &buffer);
//    glGenBuffers(1, &buffer);
    self.myColorFrameBuffer = buffer;
    //3.綁定
    glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);

    /*生成幀緩存區(qū)之后,則需要將renderbuffer跟framebuffer進行綁定驶沼,
    調(diào)用glFramebufferRenderbuffer函數(shù)進行綁定到對應(yīng)的附著點上炮沐,后面的繪制才能起作用
    */

    //4.將渲染緩存區(qū)myColorRenderBuffer 通過glFramebufferRenderbuffer函數(shù)綁定到 GL_COLOR_ATTACHMENT0上。
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
}
  1. 開始繪制圖片 renderLayer
- (void)renderLayer {
    //設(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. 讀取頂點著色程序回怜,片元著色程序
    NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shader_v" ofType:@"vsh"];
    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shader_f" ofType:@"fsh"];
    NSLog(@"vertFile:%@",vertFile);
    NSLog(@"fragFile:%@",fragFile);

    //3. 加載shader
    self.myPrograme = [self loadShaders:vertFile frag:fragFile];

    //4.鏈接
    glLinkProgram(self.myPrograme);
    GLint linkStatus;
    //獲取鏈接狀態(tài)
    glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus);
    if (linkStatus == GL_FALSE) {
        GLchar message[512];
        glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"program link error: %@", messageString);
        return;
    }
    NSLog(@"program link success");
    //5. 使用program
    glUseProgram(self.myPrograme);

    //6. 設(shè)置頂點大年,紋理坐標 前3個頂點坐標,后2個是紋理坐標
    GLfloat attrArr[] =
    {
        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
        -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,

        0.5f, 0.5f, -1.0f,      1.0f, 1.0f,
        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
    };

    //7. 處理頂點數(shù)據(jù)
    //頂點緩存區(qū)
    GLuint attrBuffer;
    //申請一個緩存區(qū)標識符
    glGenBuffers(1, &attrBuffer);
    //將attrBuffer綁定到GL_ARRAY_BUFFER標識符上
    glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
    //把頂點數(shù)據(jù)從CPU內(nèi)存復制 到GPU上
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);

    //8. 將頂點數(shù)據(jù)通過myProgram中傳遞到頂點著色程序的position
    // glGetAttribLocation,用來獲取vertex玉雾, attribute的入口
    // 告訴OpenGL ES 通過glEnableVertexAttribArray
    // 最后數(shù)據(jù)是通過glVertexAttribPointer傳遞過去的

    // 注意:第二個參數(shù)字符串必須和shader.vsh中的輸入變量:position保持一致
    GLuint position = glGetAttribLocation(self.myPrograme, "position");
    // 設(shè)置合適的格式從buffer里面讀取數(shù)據(jù)
    glEnableVertexAttribArray(position);
    // 設(shè)置讀取方式
    //參數(shù)1:index,頂點數(shù)據(jù)的索引
    //參數(shù)2:size,每個頂點屬性的組件數(shù)量翔试,1,2复旬,3垦缅,或者4.默認初始值是4.
    //參數(shù)3:type,數(shù)據(jù)中的每個組件的類型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT驹碍。默認初始值為GL_FLOAT
    //參數(shù)4:normalized,固定點數(shù)據(jù)值是否應(yīng)該歸一化壁涎,或者直接轉(zhuǎn)換為固定值凡恍。(GL_FALSE)
    //參數(shù)5:stride,連續(xù)頂點屬性之間的偏移量,默認為0怔球;
    //參數(shù)6:指定一個指針嚼酝,指向數(shù)組中的第一個頂點屬性的第一個組件。默認為0
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);

    //9.處理紋理數(shù)據(jù)
    //(1).glGetAttribLocation,用來獲取vertex attribute的入口的.
    //注意:第二參數(shù)字符串必須和shaderv.vsh中的輸入變量:textCoordinate保持一致
    GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");
    // (2) 設(shè)置合適的格式從buffer里面讀取數(shù)據(jù)
    glEnableVertexAttribArray(textCoor);
    //(3) 設(shè)置讀取方式
    glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (float *)NULL + 3);

    //10. 加載紋理
    [self setupTexture:@"meinv"];

    //11.設(shè)置紋理采樣器 sampler2D
    glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);

    //12.繪圖
    glDrawArrays(GL_TRIANGLES, 0, 6);

    //13.從渲染緩存區(qū)顯示到屏幕上
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
}

//加載紋理
- (GLuint)setupTexture:(NSString *)fileName {
    //1.將圖片轉(zhuǎn)換為CGImageRef
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

    //判斷圖片是否獲取成功
    if (!spriteImage) {
        NSLog(@"Failed to load iamge %@", fileName);
        exit(1);
    }

    //2. 讀取圖片的大小和寬高
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);

    //3. 獲取圖片字節(jié)數(shù) 寬 * 高 (RGBA)
    GLubyte *spriteData = (GLubyte *)calloc(width * height * 4, sizeof(GLubyte));

    //4. 創(chuàng)建上下文
    /*
    參數(shù)1:data,指向要渲染的繪制圖像的內(nèi)存地址
    參數(shù)2:width,bitmap的寬度竟坛,單位為像素
    參數(shù)3:height,bitmap的高度闽巩,單位為像素
    參數(shù)4:bitPerComponent,內(nèi)存中像素的每個組件的位數(shù),比如32位RGBA担汤,就設(shè)置為8
    參數(shù)5:bytesPerRow,bitmap的沒一行的內(nèi)存所占的比特數(shù)
    參數(shù)6:colorSpace,bitmap上使用的顏色空間  kCGImageAlphaPremultipliedLast:RGBA
    */
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);

    //5.在CGContextRef上 將圖片繪制出來
    /*
    CGContextDrawImage 使用的是Core Graphics框架涎跨,坐標系與UIKit 不一樣。UIKit框架的原點在屏幕的左上角漫试,Core Graphics框架的原點在屏幕的左下角六敬。
    CGContextDrawImage
    參數(shù)1:繪圖上下文
    參數(shù)2:rect坐標
    參數(shù)3:繪制的圖片
    */
    CGRect rect = CGRectMake(0, 0, width, height);

    //6. 使用默認方式繪制
    CGContextDrawImage(spriteContext, rect, spriteImage);

    //7. 畫圖完畢就釋放上下文
    CGContextRelease(spriteContext);

    //8. 綁定紋理到默認的紋理ID
    glBindTexture(GL_TEXTURE_2D, 0);

    //9. 設(shè)置紋理屬性
    /*
    參數(shù)1:紋理維度
    參數(shù)2:線性過濾、為s,t坐標設(shè)置模式
    參數(shù)3:wrapMode,環(huán)繞模式
    */
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    float fw = width, fh = height;

    //10. 載入紋理數(shù)據(jù)
    /*
    參數(shù)1:紋理模式驾荣,GL_TEXTURE_1D外构、GL_TEXTURE_2D、GL_TEXTURE_3D
    參數(shù)2:加載的層次播掷,一般設(shè)置為0
    參數(shù)3:紋理的顏色值GL_RGBA
    參數(shù)4:寬
    參數(shù)5:高
    參數(shù)6:border审编,邊界寬度
    參數(shù)7:format
    參數(shù)8:type
    參數(shù)9:紋理數(shù)據(jù)
    */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

    //11. 釋放spriteData
    free(spriteData);
    return 0;
}

//加載shader
- (GLuint)loadShaders:(NSString *)vert frag:(NSString *)frag {
    //1. 定義2個零時著色器對象
    GLuint verShader, fragShader;
    //創(chuàng)建program
    GLint program = glCreateProgram();
    //2.編譯頂點著色程序、片元著色器程序
    //參數(shù)1:編譯完存儲的底層地址
    //參數(shù)2:編譯的類型歧匈,GL_VERTEX_SHADER(頂點)垒酬、GL_FRAGMENT_SHADER(片元)
    //參數(shù)3:文件路徑
    [self complieShader:&verShader type:GL_VERTEX_SHADER file:vert];
    [self complieShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];
    //3. 創(chuàng)建最終的程序
    glAttachShader(program, verShader);
    glAttachShader(program, fragShader);

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

    return program;

}

//編譯頂點著色程序、片元著色器程序
- (void)complieShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file {
    //1. 讀取文件路徑字符串
    NSString *content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
    const GLchar *source = (GLchar *)[content UTF8String];

    //2. 創(chuàng)建一個shader
    *shader = glCreateShader(type);
    //3.將著色器源碼附加到著色器對象上件炉。
    //參數(shù)1:shader,要編譯的著色器對象 *shader
    //參數(shù)2:numOfStrings,傳遞的源碼字符串數(shù)量 1個
    //參數(shù)3:strings,著色器程序的源碼(真正的著色器程序源碼)
    //參數(shù)4:lenOfStrings,長度勘究,具有每個字符串長度的數(shù)組,或NULL斟冕,這意味著字符串是NULL終止的
    glShaderSource(*shader, 1, &source, NULL);
    //4.把著色器源代碼編譯成目標代碼
    glCompileShader(*shader);
}
  1. 由于紋理的坐標原點是左下角口糕,而屏幕的原點坐標是左上角,所以如果不對圖片進行翻轉(zhuǎn)磕蛇,得到的圖片會是反的景描。可以通過以下5中方法進行翻轉(zhuǎn):
  • 第一種:解壓圖片時,將圖片源文件翻轉(zhuǎn)
//6. 使用默認方式繪制秀撇, 圖片是反的
//    CGContextDrawImage(spriteContext, rect, spriteImage);

    //6.第一種: 將圖片源文件翻轉(zhuǎn)超棺, 圖片是正的
    CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
    CGContextTranslateCTM(spriteContext, 0, rect.size.height);
    CGContextScaleCTM(spriteContext, 1.0, -1.0);
    CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
    CGContextDrawImage(spriteContext, rect, spriteImage);

    //7. 畫圖完畢就釋放上下文
    CGContextRelease(spriteContext);
  • 第二種:直接從源紋理坐標數(shù)據(jù)修改
//6. 設(shè)置頂點,紋理坐標 前3個頂點坐標呵燕,后2個是紋理坐標
   // GLfloat attrArr[] =
    //{
     //   0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
      //  -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
      //  -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,

      //  0.5f, 0.5f, -1.0f,      1.0f, 1.0f,
      //  -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,
      //  0.5f, -0.5f, -1.0f,     1.0f, 0.0f,
    //};
    //第二種:改變紋理坐標修改圖片為正的
    GLfloat attrArr[] =
     {
     0.5f, -0.5f, 0.0f,        1.0f, 1.0f, //右下
     -0.5f, 0.5f, 0.0f,        0.0f, 0.0f, // 左上
     -0.5f, -0.5f, 0.0f,       0.0f, 1.0f, // 左下
     0.5f, 0.5f, 0.0f,         1.0f, 0.0f, // 右上
     -0.5f, 0.5f, 0.0f,        0.0f, 0.0f, // 左上
     0.5f, -0.5f, 0.0f,        1.0f, 1.0f, // 右下
     };
  • 第三種:修改片元著色器,紋理坐標
void main() {
//    lowp vec4 temp = texture2D(colorMap, varyTextCoord);
//    gl_FragColor = temp;

    //第三種:直接修改片元著色器的紋理坐標來讓圖片為正的
    gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x, 1.0 - varyTextCoord.y));
}
  • 第四種:修改頂點著色器,紋理坐標
void main() {
//    varyTextCoord = textCoordinate;
//    gl_Position = position;

    //第四種:修改頂點著色器的紋理坐標來翻轉(zhuǎn)圖片為正
    varyTextCoord = vec2(textCoordinate.x, 1.0 - textCoordinate.y);
    gl_Position = position;
}
  • 第五種:旋轉(zhuǎn)矩陣翻轉(zhuǎn)圖形,不翻轉(zhuǎn)紋理, 并且要在頂點著色器中添加rotateMatrix, ju't
//旋轉(zhuǎn)矩陣翻轉(zhuǎn)圖形,不翻轉(zhuǎn)紋理
- (void)rotateTextureImage {
    //注意棠绘,想要獲取shader里面的變量,這里記得要在glLinkProgram后面,后面弄唧,后面适肠!
    //1. rotate等于shaderv.vsh中的uniform屬性,rotateMatrix
    GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");

    //2.獲取旋轉(zhuǎn)的弧度
    float radians = 180 * 3.14159f / 180.0f;
    //3.求得弧度對于的sin\cos值
    float s = sin(radians);
    float c = cos(radians);

    //4.因為在3D課程中用的是橫向量候引,在OpenGL ES用的是列向量
    /*
     參考Z軸旋轉(zhuǎn)矩陣
     */
    GLfloat zRotation[16] = {
        c, -s, 0, 0,
        s, c, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    };

    //5.設(shè)置旋轉(zhuǎn)矩陣
    /*
     glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
     location : 對于shader 中的ID
     count : 個數(shù)
     transpose : 轉(zhuǎn)置
     value : 指針
     */
    glUniformMatrix4fv(rotate, 1, GL_FALSE, zRotation);
}

結(jié)語:想看完整代碼請戳這里GLSL_LoadImage

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侯养,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子澄干,更是在濱河造成了極大的恐慌逛揩,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辩稽,死亡現(xiàn)場離奇詭異,居然都是意外死亡从媚,警方通過查閱死者的電腦和手機逞泄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拜效,“玉大人喷众,你說我怎么就攤上這事〗艉叮” “怎么了到千?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赴穗。 經(jīng)常有香客問我憔四,道長,這世上最難降的妖魔是什么般眉? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任了赵,我火速辦了婚禮,結(jié)果婚禮上甸赃,老公的妹妹穿的比我還像新娘柿汛。我一直安慰自己,他們只是感情好辑奈,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著已烤,像睡著了一般鸠窗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胯究,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天稍计,我揣著相機與錄音,去河邊找鬼裕循。 笑死臣嚣,一個胖子當著我的面吹牛净刮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硅则,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼淹父,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怎虫?” 一聲冷哼從身側(cè)響起暑认,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎大审,沒想到半個月后蘸际,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡徒扶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年粮彤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姜骡。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡导坟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出溶浴,到底是詐尸還是另有隱情乍迄,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布士败,位于F島的核電站闯两,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谅将。R本人自食惡果不足惜漾狼,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饥臂。 院中可真熱鬧逊躁,春花似錦、人聲如沸隅熙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽囚戚。三九已至酵熙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間驰坊,已是汗流浹背匾二。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人察藐。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓皮璧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親分飞。 傳聞我的和親對象是個殘疾皇子悴务,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348