重新自學(xué)學(xué)習(xí)openGL 之 深度測(cè)試

本章可以學(xué)到如何使用深度測(cè)試,以及參數(shù)選擇的效果

在繪制3D 圖像的時(shí)候,我們需要開啟深度測(cè)試, 來防止被阻擋的面渲染到其它面的前面. 本章將深入地討論這些儲(chǔ)存在深度緩沖(或z緩沖(z-buffer))中的深度值(Depth Value)迷殿,以及它們是如何確定一個(gè)片段是處于其它片段后方的厂镇。

深度緩沖就像顏色緩沖(Color Buffer)(儲(chǔ)存所有的片段顏色:視覺輸出)一樣隧饼,在每個(gè)片段中儲(chǔ)存了信息,并且(通常)和顏色緩沖有著一樣的寬度和高度。深度緩沖是由系統(tǒng)自動(dòng)創(chuàng)建的炸枣,它會(huì)以16、24或32位float的形式儲(chǔ)存它的深度值。在大部分的系統(tǒng)中旁蔼,深度緩沖的精度都是24位的。

當(dāng)深度測(cè)試(Depth Testing)被啟用的時(shí)候疙教,OpenGL會(huì)將一個(gè)片段的的深度值與深度緩沖的內(nèi)容進(jìn)行對(duì)比棺聊。OpenGL會(huì)執(zhí)行一個(gè)深度測(cè)試,如果這個(gè)測(cè)試通過了的話贞谓,深度緩沖將會(huì)更新為新的深度值限佩。如果深度測(cè)試失敗了,片段將會(huì)被丟棄。

深度緩沖是在片段著色器運(yùn)行之后以及模板測(cè)試(Stencil Testing)運(yùn)行之后在屏幕空間中運(yùn)行的祟同。

屏幕空間坐標(biāo)與通過OpenGL的glViewport所定義的視口密切相關(guān)作喘,并且可以直接使用GLSL內(nèi)建變量gl_FragCoord從片段著色器中直接訪問。gl_FragCoord的x和y分量代表了片段的屏幕空間坐標(biāo)(其中(0, 0)位于左下角)晕城。gl_FragCoord中也包含了一個(gè)z分量泞坦,它包含了片段真正的深度值。z值就是需要與深度緩沖內(nèi)容所對(duì)比的那個(gè)值砖顷。

現(xiàn)在大部分的GPU都提供一個(gè)叫做提前深度測(cè)試(Early Depth Testing)的硬件特性贰锁。提前深度測(cè)試允許深度測(cè)試在片段著色器之前運(yùn)行。只要我們清楚一個(gè)片段永遠(yuǎn)不會(huì)是可見的(它在其他物體之后)择吊,我們就能提前丟棄這個(gè)片段李根。
片段著色器通常開銷都是很大的,所以我們應(yīng)該盡可能避免運(yùn)行它們几睛。當(dāng)使用提前深度測(cè)試時(shí)房轿,片段著色器的一個(gè)限制是你不能寫入片段的深度值。如果一個(gè)片段著色器對(duì)它的深度值進(jìn)行了寫入所森,提前深度測(cè)試是不可能的囱持。OpenGL不能提前知道深度值。

深度測(cè)試默認(rèn)是禁用的焕济,所以如果要啟用深度測(cè)試的話纷妆,我們需要用GL_DEPTH_TEST選項(xiàng)來啟用它:

glEnable(GL_DEPTH_TEST);

當(dāng)它啟用的時(shí)候,如果一個(gè)片段通過了深度測(cè)試的話晴弃,OpenGL會(huì)在深度緩沖中儲(chǔ)存該片段的z值掩幢;如果沒有通過深度緩沖,則會(huì)丟棄該片段上鞠。如果你啟用了深度緩沖际邻,你還應(yīng)該在每個(gè)渲染迭代之前使用GL_DEPTH_BUFFER_BIT來清除深度緩沖,否則你會(huì)仍在使用上一次渲染迭代中的寫入的深度值:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

可以想象芍阎,在某些情況下你會(huì)需要對(duì)所有片段都執(zhí)行深度測(cè)試并丟棄相應(yīng)的片段世曾,但不希望更新深度緩沖∏聪蹋基本上來說轮听,你在使用一個(gè)只讀的(Read-only)深度緩沖。OpenGL允許我們禁用深度緩沖的寫入岭佳,只需要設(shè)置它的深度掩碼(Depth Mask)設(shè)置為GL_FALSE就可以了:

glDepthMask(GL_FALSE);

注意這只在深度測(cè)試被啟用的時(shí)候才有效果血巍。

開啟深度測(cè)試和關(guān)閉深度測(cè)試的效果

我們繪制一個(gè)正方體來測(cè)試開啟深度測(cè)試和關(guān)閉深度測(cè)試的效果

基礎(chǔ)類代碼
正方體坐標(biāo)

float cubeVerts[]={
    0.5, 0.5, 0.5,
    -0.5, 0.5, 0.5,
    -0.5,-0.5, 0.5,
    0.5,-0.5, 0.5,
    
    0.5, 0.5, -0.5,
    -0.5, 0.5, -0.5,
    -0.5,-0.5,-0.5,
    0.5,-0.5,-0.5,
};
float cubeColors[]={
    1.0,0.0,0.0,
    1.0,0.0,0.0,
    1.0,0.0,0.0,
    1.0,0.0,0.0,
    0.0,1.0,0.0,
    0.0,1.0,0.0,
    0.0,1.0,0.0,
    0.0,1.0,0.0,
};

#import "DepthTestIsOpenViewController.h"
#import "DepthTestIsOpenBindObject.h"
#import "CubeManager.h"

@interface DepthTestIsOpenViewController ()
@property (nonatomic ,strong) Vertex * vertex;
@property (nonatomic ,strong) VertexElement * vertexElement ;

@end

@implementation DepthTestIsOpenViewController
-(void)initSubObject{
    self.bindObject = [DepthTestIsOpenBindObject new];
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT);
    };
}

-(void)loadVertex{
    self.vertex= [Vertex new];
    int vertexNum =[CubeManager getVertexNum];
    [self.vertex allocVertexNum:vertexNum andEachVertexNum:6];
    for (int i=0; i<vertexNum; i++) {
        float onevertex[6];
        for (int j=0; j<3; j++) {
            onevertex[j]=[CubeManager getCubeVerts][i*3+j];
        }
        for (int j=0; j<3; j++) {
            onevertex[j+3]=[CubeManager cubeColors][i*3+j];
        }
        [self.vertex setVertex:onevertex index:i];
    }
    [self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
    [self.vertex enableVertexInVertexAttrib:DTIO_aPos numberOfCoordinates:3 attribOffset:0];
    [self.vertex enableVertexInVertexAttrib:DTIO_aColor numberOfCoordinates:3 attribOffset:sizeof(float)*3];

    self.vertexElement = [VertexElement new];
    [self.vertexElement allocWithIndexNum:[CubeManager getVertexElementsNum] indexArr:[CubeManager getVertexElements]];    
}



-(void)createTextureUnit{
   
    
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClearColor(1.0,1.0,1.0, 1);
    self.glDrawConfig();
    GLKMatrix4 viewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 3.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    glUniformMatrix4fv(self.bindObject->uniforms[DTIO_uniform_view], 1, 0,viewMatrix.m);
    
    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(85.0f),
                              aspectRatio,
                              0.1f,
                              100.0f);
    glUniformMatrix4fv(self.bindObject->uniforms[DTIO_uniform_projection], 1, 0,projectionMatrix.m);
    
    GLKMatrix4 mode = GLKMatrix4Identity;
    static GLfloat angle=30;
    angle +=3;
    mode =  GLKMatrix4Rotate(mode,angle*M_PI/180, 0, 1, 0);

    glUniformMatrix4fv(self.bindObject->uniforms[DTIO_uniform_model], 1, 0,mode.m);
    [self.vertexElement drawElementIndexWithMode:GL_TRIANGLES];

}


@end
#import "GLBaseViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface DepthTestIsOpenViewController : GLBaseViewController
@property (nonatomic ,strong) void(^glDrawConfig)(void) ;
@end

NS_ASSUME_NONNULL_END

shader

attribute vec3 aPos;
attribute vec3 aColor;
varying  vec3  vColor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;


void main (){
    vColor = aColor;
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}
precision mediump float;//mediump
varying  vec3 vColor;

void main(){
    lowp vec4 rgba = vec4(vColor,1);
    gl_FragColor = rgba;
    
}


#import "GLBaseViewController.h"

@interface GLBaseViewController ()
@property (nonatomic ,strong) TextureUnit * textureUnit0 ;

@end

@implementation GLBaseViewController

-(void)createEagContext{
    self.eagcontext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:self.eagcontext];
}

-(void)configure{
    GLKView *view = (GLKView*)self.view;
    view.context = self.eagcontext;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    
    
}
-(void)initCustom{
    
}

-(void)initSubObject{
    
}
-(void)createTextureUnit{
  
}

-(void)createShader{
    self.shader = [Shader new];
    [self.shader compileLinkSuccessShaderName:self.bindObject.getShaderName completeBlock:^(GLuint program) {
        [self.bindObject BindAttribLocation:program];
    }];
    [self.bindObject setUniformLocation:self.shader.program];
    
 
}

-(void)loadVertex{
    
    
}


-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    
  
}

-(void)viewDidLoad{
    [super viewDidLoad];
    [self createEagContext];
    [self initSubObject];
    [self configure];
    [self initCustom];
    [self createShader];
    [self createTextureUnit];
    [self loadVertex];
}


@end
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import "OpenGLUtilsHeader.h"
#import "GLBaseBindObject.h"


NS_ASSUME_NONNULL_BEGIN



@interface GLBaseViewController : GLKViewController
@property (nonatomic ,strong) EAGLContext * eagcontext;
@property (nonatomic ,assign) GLuint  program;
@property (nonatomic ,strong) Shader * shader ;
@property (nonatomic ,strong) GLBaseBindObject * bindObject ;

///眼的位置在 0,0,1 看向 原點(diǎn) ,眼的正方向是y軸,   看的區(qū)域是0.1 到20   角度是85
-(GLKMatrix4 )mvp;

-(void)loadVertex;
-(void)initSubObject;
-(void)createTextureUnit;
@end

我這里只貼了主要的代碼. 代碼不全,可以下載demo來看.

未開啟深度測(cè)試效果


我們發(fā)現(xiàn) 正方體是部分鏤空.

開啟深度測(cè)試效果

可以正常展示一個(gè)正方體了

#import "DepthTestOpenViewController.h"

@interface DepthTestOpenViewController ()

@end

@implementation DepthTestOpenViewController

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };

}

@end

glDepthMask的使用

該函數(shù)起作用必須是我們要開啟深度測(cè)試才行

測(cè)試代碼做的事情是我們繪制三張圖片,三張圖片按照 綠色圖片 ,箱子,紅色圖片的順序繪制. 我們看glDepthMask對(duì)三張圖片的影響

核心測(cè)試代碼


#import "DepthTestMaskViewController.h"
#import "DepthTestMaskBindObject.h"

@interface DepthTestMaskViewController ()
@property (nonatomic ,strong) Vertex * vertex;
@property (nonatomic ,strong) TextureUnit * unitFront ;
@property (nonatomic ,strong) TextureUnit * unitMiddle;
@property (nonatomic ,strong) TextureUnit * unitBack;
@end

@implementation DepthTestMaskViewController
-(void)initSubObject{
    //生命周期三秒鐘
    self.bindObject = [DepthTestMaskBindObject new];
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT);
    };
    self.glDrawMaskEndConfig = ^{
        
    };
    self.glDrawMaskBeginConfig = ^{
        
    };
    
}

#define VertexNum 4
#define eachVertexNum 4

static GLfloat s_vertex[4*4] = {
    0.5,0.5, 0,1, //1
    -0.5,0.5,1,1,//0
    -0.5,-0.5,1,0, //2
    0.5,-0.5,0,0//3
};

-(void)loadVertex{
    
    self.vertex = [Vertex new];
    [self.vertex allocVertexNum:VertexNum andEachVertexNum:eachVertexNum];
    for (int i =0; i<VertexNum; i++) {
        GLfloat vertex[4];
        vertex[0] = s_vertex[i*VertexNum];
        vertex[1] = s_vertex[i*VertexNum+1];
        vertex[2] = s_vertex[i*VertexNum+2];
        vertex[3] = s_vertex[i*VertexNum+3];
        [self.vertex setVertex:vertex index:i];
    }
    [self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
    [self.vertex enableVertexInVertexAttrib:DTM_aPos  numberOfCoordinates:2 attribOffset:0];
    [self.vertex enableVertexInVertexAttrib:DTM_aTexture numberOfCoordinates:2 attribOffset:2*sizeof(GLfloat)];
}




-(void)createTextureUnit{
    self.unitFront = [TextureUnit new];
    [self.unitFront setImage:[UIImage imageNamed:@"green.png"] IntoTextureUnit:GL_TEXTURE0 andConfigTextureUnit:nil];
    self.unitBack = [TextureUnit new];
    [self.unitBack setImage:[UIImage imageNamed:@"red.png"] IntoTextureUnit:GL_TEXTURE1 andConfigTextureUnit:nil];
    self.unitMiddle = [TextureUnit new];
    [self.unitMiddle setImage:[UIImage imageNamed:@"texture.jpg"] IntoTextureUnit:GL_TEXTURE2 andConfigTextureUnit:nil];


}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClearColor(1,1,1, 1);
    self.glDrawConfig();
    GLKMatrix4 viewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 3.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    glUniformMatrix4fv(self.bindObject->uniforms[DTM_uniform_view], 1, 0,viewMatrix.m);

    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(85.0f),
                              aspectRatio,
                              0.1f,
                              10.0);
    glUniformMatrix4fv(self.bindObject->uniforms[DTM_uniform_projection], 1, 0,projectionMatrix.m);
  
   
    
    //front
    {
        GLKMatrix4  mode = GLKMatrix4Identity;
        glUniformMatrix4fv(self.bindObject->uniforms[DTM_uniform_model], 1, 0,mode.m);
        [self.unitFront bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DTM_uniform_sam2D]];
        [self.vertex enableVertexInVertexAttrib:DTM_aPos numberOfCoordinates:2 attribOffset:0];
        [self.vertex enableVertexInVertexAttrib:DTM_aTexture numberOfCoordinates:2 attribOffset:sizeof(float)*2];
        
        [self.vertex drawVertexWithMode:GL_TRIANGLE_FAN startVertexIndex:0 numberOfVertices:VertexNum];
    }
    // middle
    self.glDrawMaskBeginConfig();
    {
        GLKMatrix4  mode = GLKMatrix4Identity;
        mode = GLKMatrix4Translate(mode, 0.25, 0, 0);
        glUniformMatrix4fv(self.bindObject->uniforms[DTM_uniform_model], 1, 0,mode.m);
        [self.unitMiddle bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DTM_uniform_sam2D]];
        [self.vertex enableVertexInVertexAttrib:DTM_aPos numberOfCoordinates:2 attribOffset:0];
        [self.vertex enableVertexInVertexAttrib:DTM_aTexture numberOfCoordinates:2 attribOffset:sizeof(float)*2];
        
        [self.vertex drawVertexWithMode:GL_TRIANGLE_FAN startVertexIndex:0 numberOfVertices:VertexNum];
    }
    //back
    {
        GLKMatrix4  mode = GLKMatrix4Identity;
        mode = GLKMatrix4Translate(mode, 0.5, 0, 0);
        glUniformMatrix4fv(self.bindObject->uniforms[DTM_uniform_model], 1, 0,mode.m);
        [self.unitBack bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DTM_uniform_sam2D]];
        [self.vertex enableVertexInVertexAttrib:DTM_aPos numberOfCoordinates:2 attribOffset:0];
        [self.vertex enableVertexInVertexAttrib:DTM_aTexture numberOfCoordinates:2 attribOffset:sizeof(float)*2];
        
        [self.vertex drawVertexWithMode:GL_TRIANGLE_FAN startVertexIndex:0 numberOfVertices:VertexNum];
    }
    self.glDrawMaskEndConfig();
}
@end

這里我們需要說下,深度值其實(shí)就是z值.深度測(cè)試就是測(cè)試z值的大小.

不開啟深度測(cè)試的測(cè)試效果

我們發(fā)現(xiàn) 圖片的圖層順序是 綠色最下,箱子中間 ,紅色圖片在上.

開啟深度測(cè)試測(cè)測(cè)試效果


我們發(fā)現(xiàn)圖片的順序正好和未開啟深度測(cè)試的順序是相反的.綠色在上,箱子中間 ,紅色在下.

這是因?yàn)?當(dāng)開始測(cè)試的時(shí)候,繪制的時(shí)候就需要進(jìn)行深度測(cè)試的比較了.
我們先繪制綠色圖片,綠色圖片所在屏幕上的像素點(diǎn)的深度值就大于0.
當(dāng)我們繪制箱子的時(shí)候,箱子和綠色重疊的部分深度值等于綠色圖片不繪制,而只繪制和綠色圖片不重疊的部分
紅色的圖片同樣的道理繪制

這里需要注意,我們繪制綠色圖片的時(shí)候,坐標(biāo)z軸是0,但是深度值不是0
沒有繪制的顏色的區(qū)域的深度值是0
深度值越小越繪制

圖例如下


開始深度測(cè)試并且使用遮罩效果

代碼如下

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthMask(GL_FALSE);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthMask(GL_TRUE);
    };
}

代碼具體做的事情如下

  • 1.我們開啟 glEnable(GL_DEPTH_TEST); 和 glDepthMask(GL_TRUE);
  • 2.繪制了綠色圖片
  • 3.關(guān)閉 glDepthMask(GL_FALSE);
  • 4.繪制箱子和紅色圖片 最終的結(jié)果如上

具體行為分析如下

當(dāng)開啟測(cè)試的時(shí)候并且遮罩(mask)開啟的時(shí)候,繪制的時(shí)候就需要進(jìn)行深度測(cè)試的比較了.
我們先繪制綠色圖片,綠色圖片所在屏幕上的像素點(diǎn)的深度值就大于0.
關(guān)閉mask,繪制箱子的時(shí)候,箱子對(duì)應(yīng)的深度值是0,那么,箱子和綠色重疊的部分進(jìn)行深度值比較,明顯小于深小于綠色圖片的深度值,不繪制,而只繪制和綠色圖片不重疊的部分,該部分深度值是默認(rèn)值.
接著繪制紅色圖片,紅色圖片和箱子重疊部分,由于該部分的深度值是默認(rèn)值,因此,紅色覆蓋該像素點(diǎn)了.

圖例


深度測(cè)試函數(shù)

OpenGL允許我們修改深度測(cè)試中使用的比較運(yùn)算符。這允許我們來控制OpenGL什么時(shí)候該通過或丟棄一個(gè)片段驼唱,什么時(shí)候去更新深度緩沖藻茂。我們可以調(diào)用glDepthFunc函數(shù)來設(shè)置比較運(yùn)算符(或者說深度函數(shù)(Depth Function)):

glDepthFunc(GL_LESS);

這個(gè)函數(shù)接受下面表格中的比較運(yùn)算符:

函數(shù) 描述
GL_ALWAYS 永遠(yuǎn)通過深度測(cè)試
GL_NEVER 永遠(yuǎn)不通過深度測(cè)試
GL_LESS 在片段深度值小于緩沖的深度值時(shí)通過測(cè)試
GL_EQUAL 在片段深度值等于緩沖區(qū)的深度值時(shí)通過測(cè)試
GL_LEQUAL 在片段深度值小于等于緩沖區(qū)的深度值時(shí)通過測(cè)試
GL_GREATER 在片段深度值大于緩沖區(qū)的深度值時(shí)通過測(cè)試
GL_NOTEQUAL 在片段深度值不等于緩沖區(qū)的深度值時(shí)通過測(cè)試
GL_GEQUAL 在片段深度值大于等于緩沖區(qū)的深度值時(shí)通過測(cè)試

默認(rèn)情況下使用的深度函數(shù)是GL_LESS,它將會(huì)丟棄深度值大于等于當(dāng)前深度緩沖值的所有片段。

測(cè)試基本代碼

#import "DepthTestFuncViewController.h"
#import "DepthTestFuncBindObject.h"
@interface DepthTestFuncViewController ()
@property (nonatomic ,strong) Vertex * vertex;
@property (nonatomic ,strong) TextureUnit * unitFront ;
@property (nonatomic ,strong) TextureUnit * unitMiddle;
@property (nonatomic ,strong) TextureUnit * unitBack;
@end

@implementation DepthTestFuncViewController
-(void)initSubObject{
    //生命周期三秒鐘
    self.bindObject = [DepthTestFuncBindObject new];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskEndConfig = ^{
        
    };
    self.glDrawMaskBeginConfig = ^{
        
    };
    
}

#define DTF_VertexNum 4
#define DTF_eachVertexNum 4

static GLfloat dtf_s_vertex[4*4] = {
    0.5,0.5, 0,1, //1
    -0.5,0.5,1,1,//0
    -0.5,-0.5,1,0, //2
    0.5,-0.5,0,0//3
};

-(void)loadVertex{
    
    self.vertex = [Vertex new];
    [self.vertex allocVertexNum:DTF_VertexNum andEachVertexNum:DTF_eachVertexNum];
    for (int i =0; i<DTF_VertexNum; i++) {
        GLfloat vertex[4];
        vertex[0] = dtf_s_vertex[i*DTF_VertexNum];
        vertex[1] = dtf_s_vertex[i*DTF_VertexNum+1];
        vertex[2] = dtf_s_vertex[i*DTF_VertexNum+2];
        vertex[3] = dtf_s_vertex[i*DTF_VertexNum+3];
        [self.vertex setVertex:vertex index:i];
    }
    [self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
    [self.vertex enableVertexInVertexAttrib:DTF_aPos  numberOfCoordinates:2 attribOffset:0];
    [self.vertex enableVertexInVertexAttrib:DTF_aTexture numberOfCoordinates:2 attribOffset:2*sizeof(GLfloat)];
}




-(void)createTextureUnit{
    self.unitFront = [TextureUnit new];
    [self.unitFront setImage:[UIImage imageNamed:@"green.png"] IntoTextureUnit:GL_TEXTURE0 andConfigTextureUnit:nil];
    self.unitBack = [TextureUnit new];
    [self.unitBack setImage:[UIImage imageNamed:@"red.png"] IntoTextureUnit:GL_TEXTURE1 andConfigTextureUnit:nil];
    self.unitMiddle = [TextureUnit new];
    [self.unitMiddle setImage:[UIImage imageNamed:@"texture.jpg"] IntoTextureUnit:GL_TEXTURE2 andConfigTextureUnit:nil];
    
    
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClearColor(1,1,1, 1);
    self.glDrawConfig();
    GLKMatrix4 viewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 3.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    glUniformMatrix4fv(self.bindObject->uniforms[DTF_uniform_view], 1, 0,viewMatrix.m);
    
    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(85.0f),
                              aspectRatio,
                              0.1f,
                              10.0);
    glUniformMatrix4fv(self.bindObject->uniforms[DTF_uniform_projection], 1, 0,projectionMatrix.m);
     self.glDrawMaskBeginConfig();
    //front
    {
        GLKMatrix4  mode = GLKMatrix4Identity;
        glUniformMatrix4fv(self.bindObject->uniforms[DTF_uniform_model], 1, 0,mode.m);
        [self.unitFront bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DTF_uniform_sam2D]];
        [self.vertex enableVertexInVertexAttrib:DTF_aPos numberOfCoordinates:2 attribOffset:0];
        [self.vertex enableVertexInVertexAttrib:DTF_aTexture numberOfCoordinates:2 attribOffset:sizeof(float)*2];
        
        [self.vertex drawVertexWithMode:GL_TRIANGLE_FAN startVertexIndex:0 numberOfVertices:DTF_eachVertexNum];
    }
    // middle
    {
        GLKMatrix4  mode = GLKMatrix4Identity;
        mode = GLKMatrix4Translate(mode, 0.25, 0, 0);
        glUniformMatrix4fv(self.bindObject->uniforms[DTF_uniform_model], 1, 0,mode.m);
        [self.unitMiddle bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DTF_uniform_sam2D]];
        [self.vertex enableVertexInVertexAttrib:DTF_aPos numberOfCoordinates:2 attribOffset:0];
        [self.vertex enableVertexInVertexAttrib:DTF_aTexture numberOfCoordinates:2 attribOffset:sizeof(float)*2];
        
        [self.vertex drawVertexWithMode:GL_TRIANGLE_FAN startVertexIndex:0 numberOfVertices:DTF_eachVertexNum];
    }
     self.glDrawMaskEndConfig();
    //back
    {
        GLKMatrix4  mode = GLKMatrix4Identity;
        mode = GLKMatrix4Translate(mode, 0.5, 0, 0);
        glUniformMatrix4fv(self.bindObject->uniforms[DTF_uniform_model], 1, 0,mode.m);
        [self.unitBack bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DTF_uniform_sam2D]];
        [self.vertex enableVertexInVertexAttrib:DTF_aPos numberOfCoordinates:2 attribOffset:0];
        [self.vertex enableVertexInVertexAttrib:DTF_aTexture numberOfCoordinates:2 attribOffset:sizeof(float)*2];
        
        [self.vertex drawVertexWithMode:GL_TRIANGLE_FAN startVertexIndex:0 numberOfVertices:DTF_eachVertexNum];
    }
  
}


@end

該測(cè)試代碼和測(cè)試mask代碼比較,只是更改了glDrawMaskBeginConfigglDrawMaskEndConfig 的測(cè)試位置

GL_ALWAYS

永遠(yuǎn)通過深度測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{

    };
}

測(cè)試結(jié)果


GL_NEVER

永遠(yuǎn)不通過深度測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
         glDepthFunc(GL_NEVER);
    };
}

測(cè)試結(jié)果


GL_LESS

在片段深度值小于緩沖的深度值時(shí)通過測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthFunc(GL_LESS);
    };
}

GL_EQUAL

在片段深度值等于緩沖區(qū)的深度值時(shí)通過測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthFunc(GL_EQUAL);
    };
}
GL_EQUAL

GL_LEQUAL

在片段深度值小于等于緩沖區(qū)的深度值時(shí)通過測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthFunc(GL_LEQUAL);
    };
}
GL_LEQUAL

GL_GREATER

在片段深度值大于緩沖區(qū)的深度值時(shí)通過測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthFunc(GL_GREATER);
    };
}
GL_GREATER

GL_NOTEQUAL

在片段深度值不等于緩沖區(qū)的深度值時(shí)通過測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthFunc(GL_NOTEQUAL);
    };
}
GL_NOTEQUAL

GL_GEQUAL

在片段深度值大于等于緩沖區(qū)的深度值時(shí)通過測(cè)試

-(void)initSubObject{
    //生命周期三秒鐘
    [super initSubObject];
    glEnable(GL_DEPTH_TEST);
    self.glDrawConfig = ^{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    };
    self.glDrawMaskBeginConfig = ^{
        glDepthFunc(GL_ALWAYS);
    };
    self.glDrawMaskEndConfig = ^{
        glDepthFunc(GL_GEQUAL);
    };
}
GL_GEQUAL

深度值精度

深度緩沖包含了一個(gè)介于0.0和1.0之間的深度值辨赐,它將會(huì)與觀察者視角所看見的場(chǎng)景中所有物體的z值進(jìn)行比較优俘。觀察空間的z值可能是投影平截頭體的近平面(Near)和遠(yuǎn)平面(Far)之間的任何值。我們需要一種方式來將這些觀察空間的z值變換到[0, 1]范圍之間掀序,其中的一種方式就是將它們線性變換到[0, 1]范圍之間帆焕。下面這個(gè)(線性)方程將z值變換到了0.0到1.0之間的深度值:


深度值與z軸成正相關(guān)

這里的near和far值是我們之前提供給投影矩陣設(shè)置可視平截頭體的那個(gè) near 和 far 值



這個(gè)方程需要平截頭體中的一個(gè)z值,并將它變換到了[0, 1]的范圍中不恭。z值和對(duì)應(yīng)的深度值之間的關(guān)系可以在下圖中看到:


然而叶雹,在實(shí)踐中是幾乎永遠(yuǎn)不會(huì)使用這樣的線性深度緩沖(Linear Depth Buffer)的。要想有正確的投影性質(zhì)换吧,需要使用一個(gè)非線性的深度方程折晦,它是與 1/z 成正比的。它做的就是在z值很小的時(shí)候提供非常高的精度沾瓦,而在z值很遠(yuǎn)的時(shí)候提供更少的精度满着。

花時(shí)間想想這個(gè):我們真的需要對(duì)1000單位遠(yuǎn)的深度值和只有1單位遠(yuǎn)的充滿細(xì)節(jié)的物體使用相同的精度嗎?線性方程并不會(huì)考慮這一點(diǎn)贯莺。

由于非線性方程與 1/z 成正比风喇,在1.0和2.0之間的z值將會(huì)變換至1.0到0.5之間的深度值,這就是一個(gè)float提供給我們的一半精度了缕探,這在z值很小的情況下提供了非常大的精度魂莫。在50.0和100.0之間的z值將會(huì)只占2%的float精度,這正是我們所需要的爹耗。這樣的一個(gè)考慮了遠(yuǎn)近距離的方程是這樣的:


其實(shí)就是線性關(guān)系的變種.更接近現(xiàn)實(shí)

如果你不知道這個(gè)方程是怎么回事也不用擔(dān)心耙考。重要的是要記住深度緩沖中的值在屏幕空間中不是線性的(在透視矩陣應(yīng)用之前在觀察空間中是線性的)。深度緩沖中0.5的值并不代表著物體的z值是位于平截頭體的中間了潭兽,這個(gè)頂點(diǎn)的z值實(shí)際上非常接近近平面琳骡!你可以在下圖中看到z值和最終的深度緩沖值之間的非線性關(guān)系:


可以看到,深度值很大一部分是由很小的z值所決定的讼溺,這給了近處的物體很大的深度精度。這個(gè)(從觀察者的視角)變換z值的方程是嵌入在投影矩陣中的最易,所以當(dāng)我們想將一個(gè)頂點(diǎn)坐標(biāo)從觀察空間至裁剪空間的時(shí)候這個(gè)非線性方程就被應(yīng)用了怒坯。

深度緩沖的可視化

我們知道片段著色器中,內(nèi)建gl_FragCoord向量的z值包含了那個(gè)特定片段的深度值藻懒。如果我們將這個(gè)深度值輸出為顏色剔猿,我們可以顯示場(chǎng)景中所有片段的深度值。我們可以根據(jù)片段的深度值返回一個(gè)顏色向量來完成這一工作:

precision mediump float;
varying vec2 vTexCoords;
uniform sampler2D uTexture;

void main()
{
    vec4 textureColor = texture2D(uTexture, vTexCoords);
   
    gl_FragColor = vec4(vec3(gl_FragCoord.z), 1.0);;
}

代碼含義:
+ 生成了一個(gè)地面和兩個(gè)正方體.

測(cè)試結(jié)果


這很清楚地展示了深度值的非線性性質(zhì)嬉荆。近處的物體比起遠(yuǎn)處的物體對(duì)深度值有著更大的影響归敬。只需要移動(dòng)幾厘米就能讓顏色從暗完全變白。

如何變成線性關(guān)系呢?

深度沖突

一個(gè)很常見的視覺錯(cuò)誤會(huì)在兩個(gè)平面或者三角形非常緊密地平行排列在一起時(shí)會(huì)發(fā)生,深度緩沖沒有足夠的精度來決定兩個(gè)形狀哪個(gè)在前面汪茧。結(jié)果就是這兩個(gè)形狀不斷地在切換前后順序椅亚,這會(huì)導(dǎo)致很奇怪的花紋。這個(gè)現(xiàn)象叫做深度沖突(Z-fighting)舱污,因?yàn)樗雌饋硐袷沁@兩個(gè)形狀在爭(zhēng)奪(Fight)誰該處于頂端呀舔。

在我們一直使用的場(chǎng)景中,有幾個(gè)地方的深度沖突還是非常明顯的扩灯。箱子被放置在地板的同一高度上媚赖,這也就意味著箱子的底面和地板是共面的(Coplanar)。這兩個(gè)面的深度值都是一樣的珠插,所以深度測(cè)試沒有辦法決定應(yīng)該顯示哪一個(gè)惧磺。

深度沖突是深度緩沖的一個(gè)常見問題,當(dāng)物體在遠(yuǎn)處時(shí)效果會(huì)更明顯(因?yàn)樯疃染彌_在z值比較大的時(shí)候有著更小的精度)捻撑。深度沖突不能夠被完全避免磨隘,但一般會(huì)有一些技巧有助于在你的場(chǎng)景中減輕或者完全避免深度沖突、

防止深度沖突

第一個(gè)也是最重要的技巧是永遠(yuǎn)不要把多個(gè)物體擺得太靠近布讹,以至于它們的一些三角形會(huì)重疊琳拭。通過在兩個(gè)物體之間設(shè)置一個(gè)用戶無法注意到的偏移值,你可以完全避免這兩個(gè)物體之間的深度沖突描验。在箱子和地板的例子中白嘁,我們可以將箱子沿著正y軸稍微移動(dòng)一點(diǎn)。箱子位置的這點(diǎn)微小改變將不太可能被注意到膘流,但它能夠完全減少深度沖突的發(fā)生絮缅。然而,這需要對(duì)每個(gè)物體都手動(dòng)調(diào)整呼股,并且需要進(jìn)行徹底的測(cè)試來保證場(chǎng)景中沒有物體會(huì)產(chǎn)生深度沖突耕魄。

第二個(gè)技巧是盡可能將近平面設(shè)置遠(yuǎn)一些。在前面我們提到了精度在靠近近平面時(shí)是非常高的彭谁,所以如果我們將近平面遠(yuǎn)離觀察者泡仗,我們將會(huì)對(duì)整個(gè)平截頭體有著更大的精度。然而盲链,將近平面設(shè)置太遠(yuǎn)將會(huì)導(dǎo)致近處的物體被裁剪掉妈拌,所以這通常需要實(shí)驗(yàn)和微調(diào)來決定最適合你的場(chǎng)景的近平面距離。

另外一個(gè)很好的技巧是犧牲一些性能狭园,使用更高精度的深度緩沖读处。大部分深度緩沖的精度都是24位的,但現(xiàn)在大部分的顯卡都支持32位的深度緩沖唱矛,這將會(huì)極大地提高精度罚舱。所以井辜,犧牲掉一些性能,你就能獲得更高精度的深度測(cè)試管闷,減少深度沖突粥脚。

我們上面討論的三個(gè)技術(shù)是最普遍也是很容易實(shí)現(xiàn)的抗深度沖突技術(shù)了。還有一些更復(fù)雜的技術(shù)渐北,但它們依然不能完全消除深度沖突阿逃。深度沖突是一個(gè)常見的問題,但如果你組合使用了上面列舉出來的技術(shù)赃蛛,你可能不會(huì)再需要處理深度沖突了恃锉。

測(cè)試代碼 核心代碼

#import "DepthTestViewController.h"
#import "DepthTestBindObject.h"
#import "CubeManager.h"
float planeVertices[] = {
    // positions          // texture Coords (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). this will cause the floor texture to repeat)
    5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
    -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
    -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
    
    5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
    -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
    5.0f, -0.5f, -5.0f,  2.0f, 2.0f
};

@interface DepthTestViewController ()
@property (nonatomic ,strong) Vertex * vertex;
@property (nonatomic ,strong) Vertex * planeVertex ;
@property (nonatomic ,strong) TextureUnit * cubeUnit ;
@property (nonatomic ,strong) TextureUnit * floorUnit ;
@end

@implementation DepthTestViewController

-(void)initSubObject{
    //生命周期三秒鐘
    glEnable(GL_DEPTH_TEST);
    self.bindObject = [DepthTestBindObject new];
}

-(void)loadVertex{
    self.vertex= [Vertex new];
    int vertexNum =[CubeManager getTextureNormalVertexNum];
    [self.vertex allocVertexNum:vertexNum andEachVertexNum:5];
    for (int i=0; i<vertexNum; i++) {
        float onevertex[5];
        for (int j=0; j<3; j++) {
            onevertex[j]=[CubeManager getTextureNormalVertexs][i*8+j];
        }
        for (int j=0; j<2; j++) {
            onevertex[j+3]=[CubeManager getTextureNormalVertexs][i*8+6+j];
        }
        [self.vertex setVertex:onevertex index:i];
    }
    [self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
  
    
    self.planeVertex= [Vertex new];
     vertexNum =6;
    [self.planeVertex allocVertexNum:vertexNum andEachVertexNum:5];
    for (int i=0; i<vertexNum; i++) {
        float onevertex[5];
        for (int j=0; j<3; j++) {
            onevertex[j]=planeVertices[i*5+j];
        }
        for (int j=0; j<2; j++) {
            onevertex[j+3]=planeVertices[i*5+3+j];
        }
        [self.planeVertex setVertex:onevertex index:i];
    }
    [self.planeVertex bindBufferWithUsage:GL_STATIC_DRAW];
   
    

}




-(void)createTextureUnit{
    self.cubeUnit = [TextureUnit new];
    [self.cubeUnit setImage:[UIImage imageNamed:@"marble.jpg"] IntoTextureUnit:GL_TEXTURE0 andConfigTextureUnit:nil];
    self.floorUnit = [TextureUnit new];
    [self.floorUnit setImage:[UIImage imageNamed:@"metal.png"] IntoTextureUnit:GL_TEXTURE1 andConfigTextureUnit:^{
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    }];


}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    glClearColor(0,0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    GLKMatrix4 viewMatrix =
    GLKMatrix4MakeLookAt(
                         0.0, 0.0, 3.0,   // Eye position
                         0.0, 0.0, 0.0,   // Look-at position
                         0.0, 1.0, 0.0);  // Up direction
    glUniformMatrix4fv(self.bindObject->uniforms[DT_uniform_view], 1, 0,viewMatrix.m);
    
    GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
    GLKMatrix4 projectionMatrix =
    GLKMatrix4MakePerspective(
                              GLKMathDegreesToRadians(85.0f),
                              aspectRatio,
                             1.0f,
                              20.0f);
    glUniformMatrix4fv(self.bindObject->uniforms[DT_uniform_projection], 1, 0,projectionMatrix.m);
    [self drawFloor];
    [self drawCubeLocation:GLKVector3Make(-1.0f, 0.0f, -1.0f)];
    [self drawCubeLocation:GLKVector3Make(0.0f, 0.0f, 1.0f)];

}

-(void)drawCubeLocation:(GLKVector3)location{
    GLKMatrix4  mode = GLKMatrix4Identity;
    mode =  GLKMatrix4TranslateWithVector3(mode, location);
    mode = GLKMatrix4Rotate(mode, 30*M_PI/180.0, 0, 1, 0);
    glUniformMatrix4fv(self.bindObject->uniforms[DT_uniform_model], 1, 0,mode.m);
    
    [self.cubeUnit bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DT_uniform_Texture]];
    [self.vertex enableVertexInVertexAttrib:DT_aPos numberOfCoordinates:3 attribOffset:0];
    [self.vertex enableVertexInVertexAttrib:DT_aTexCoords numberOfCoordinates:2 attribOffset:sizeof(float)*3];
    
    [self.vertex drawVertexWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:[CubeManager getTextureNormalVertexNum]];
}

-(void)drawFloor{
    
    GLKMatrix4 mode = GLKMatrix4Identity;
    glUniformMatrix4fv(self.bindObject->uniforms[DT_uniform_model], 1, 0,mode.m);
    
     [self.floorUnit bindtextureUnitLocationAndShaderUniformSamplerLocation:self.bindObject->uniforms[DT_uniform_Texture]];
    [self.planeVertex enableVertexInVertexAttrib:DT_aPos numberOfCoordinates:3 attribOffset:0];
    [self.planeVertex enableVertexInVertexAttrib:DT_aTexCoords numberOfCoordinates:2 attribOffset:sizeof(float)*3];
    
    [self.planeVertex drawVertexWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:6];
}
@end

深度介紹文章
參考博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市呕臂,隨后出現(xiàn)的幾起案子破托,更是在濱河造成了極大的恐慌,老刑警劉巖歧蒋,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件土砂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡谜洽,警方通過查閱死者的電腦和手機(jī)萝映,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阐虚,“玉大人序臂,你說我怎么就攤上這事∈凳” “怎么了奥秆?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咸灿。 經(jīng)常有香客問我构订,道長,這世上最難降的妖魔是什么避矢? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任悼瘾,我火速辦了婚禮,結(jié)果婚禮上审胸,老公的妹妹穿的比我還像新娘分尸。我一直安慰自己,他們只是感情好歹嘹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著孔庭,像睡著了一般尺上。 火紅的嫁衣襯著肌膚如雪材蛛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天怎抛,我揣著相機(jī)與錄音卑吭,去河邊找鬼。 笑死马绝,一個(gè)胖子當(dāng)著我的面吹牛豆赏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播富稻,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼掷邦,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了椭赋?” 一聲冷哼從身側(cè)響起抚岗,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哪怔,沒想到半個(gè)月后宣蔚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡认境,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年胚委,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叉信。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亩冬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出茉盏,到底是詐尸還是另有隱情鉴未,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布鸠姨,位于F島的核電站铜秆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏讶迁。R本人自食惡果不足惜连茧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巍糯。 院中可真熱鬧啸驯,春花似錦、人聲如沸祟峦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宅楞。三九已至针姿,卻和暖如春袱吆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背距淫。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國打工绞绒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人榕暇。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓蓬衡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親彤枢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狰晚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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