Metal框架詳細(xì)解析(三) —— 渲染簡單的2D三角形(一)

版本記錄

版本號 時間
V1.0 2018.10.05 星期五

前言

很多做視頻和圖像的喷兼,相信對這個框架都不是很陌生,它渲染高級3D圖形,并使用GPU執(zhí)行數(shù)據(jù)并行計算琅绅。接下來的幾篇我們就詳細(xì)的解析這個框架。感興趣的看下面幾篇文章鹅巍。
1. Metal框架詳細(xì)解析(一)—— 基本概覽
2. Metal框架詳細(xì)解析(二) —— 器件和命令(一)

Overview

在上一篇中千扶,您學(xué)習(xí)了如何編寫使用Metal的應(yīng)用程序并向GPU發(fā)出基本渲染命令料祠。

在本示例中,您將學(xué)習(xí)如何在Metal中渲染基本幾何體澎羞。 特別是髓绽,您將學(xué)習(xí)如何使用頂點數(shù)據(jù)和SIMD類型,配置圖形渲染管道妆绞,編寫GPU函數(shù)以及發(fā)出繪制調(diào)用顺呕。


The Metal Graphics Rendering Pipeline - Metal圖形渲染管道

Metal圖形渲染管道由多個圖形處理單元(GPU)階段組成,一些是可編程的摆碉,一些是固定的塘匣,用于執(zhí)行繪圖命令。 Metal將管道的輸入巷帝,過程和輸出定義為應(yīng)用于某些數(shù)據(jù)的一組渲染命令忌卤。 在最基本的形式中,管道接收頂點作為輸入并將像素渲染為輸出楞泼。 此示例主要關(guān)注管道的三個主要階段:頂點函數(shù)驰徊,光柵化階段和片段函數(shù)。 頂點函數(shù)和片段函數(shù)是可編程階段堕阔。 光柵化階段是固定的棍厂。

MTLRenderPipelineState對象表示圖形渲染管道。 可以使用MTLRenderPipelineDescriptor對象配置此管道的許多階段超陆,該對象定義了Metal處理輸入頂點到渲染輸出像素的大部分方式牺弹。


Vertex Data - 頂點數(shù)據(jù)

頂點只是兩個或多個線相交的空間中的一個點。 通常时呀,頂點表示為定義特定幾何的笛卡爾坐標(biāo)的集合张漂,以及與每個坐標(biāo)相關(guān)聯(lián)的可選數(shù)據(jù)。

此示例呈現(xiàn)由三個頂點組成的簡單2D三角形谨娜,每個頂點包含三角形角的位置和顏色航攒。

Position是必需的頂點屬性,而color是可選的趴梢。 對于此示例漠畜,管道使用兩個頂點屬性將彩色三角形渲染到drawable的特定區(qū)域。


Use SIMD Data Types - 使用SIMD數(shù)據(jù)類型

頂點數(shù)據(jù)通常從包含從專用建模軟件導(dǎo)出的3D模型數(shù)據(jù)的文件加載坞靶。詳細(xì)模型可能包含數(shù)千個具有許多屬性的頂點憔狞,但最終它們都以某種形式的數(shù)組陣列結(jié)束,這些陣列經(jīng)過特殊打包彰阴,編碼并發(fā)送到GPU躯喇。

示例的三角形為其三個頂點中的每一個定義了2D位置(x,y)和RGBA顏色(紅色,綠色廉丽,藍(lán)色倦微,alpha)。這種相對少量的數(shù)據(jù)被直接硬編碼到結(jié)構(gòu)數(shù)組中正压,其中數(shù)組的每個元素代表單個頂點欣福。用作數(shù)組元素的數(shù)據(jù)類型的結(jié)構(gòu)定義了每個頂點的內(nèi)存布局。

頂點數(shù)據(jù)和一般的3D圖形數(shù)據(jù)通常用矢量數(shù)據(jù)類型定義焦履,簡化了常見的圖形算法和GPU處理拓劝。此示例使用SIMD庫提供的優(yōu)化矢量數(shù)據(jù)類型來表示三角形的頂點。 SIMD庫獨立于MetalMetalKit嘉裤,但強烈建議用于開發(fā)Metal應(yīng)用程序郑临,主要是因為它的便利性和性能優(yōu)勢。

三角形的2D位置組件由vector_float2 SIMD數(shù)據(jù)類型聯(lián)合表示屑宠,該類型包含兩個32位浮點值厢洞。類似地,三角形的RGBA顏色分量用vector_float4 SIMD數(shù)據(jù)類型聯(lián)合表示典奉,該數(shù)據(jù)類型包含四個32位浮點值躺翻。然后將這兩個屬性組合成單個AAPLVertex結(jié)構(gòu)。

typedef struct
{
    // Positions in pixel space
    // (e.g. a value of 100 indicates 100 pixels from the center)
    vector_float2 position;

    // Floating-point RGBA colors
    vector_float4 color;
} AAPLVertex;

三角形的三個頂點直接硬編碼為AAPLVertex元素數(shù)組卫玖,從而定義每個頂點的精確屬性值公你。

static const AAPLVertex triangleVertices[] =
{
    // 2D positions,    RGBA colors
    { {  250,  -250 }, { 1, 0, 0, 1 } },
    { { -250,  -250 }, { 0, 1, 0, 1 } },
    { {    0,   250 }, { 0, 0, 1, 1 } },
};

Set a Viewport - 設(shè)置視口

視口指定Metal渲染內(nèi)容的drawable區(qū)域。 視口是具有x和y偏移假瞬,寬度和高度以及近和遠(yuǎn)平面的3D區(qū)域(盡管這里不需要這兩個陕靠,因為此示例僅渲染2D內(nèi)容)。

為管道分配自定義視口需要通過調(diào)用setViewport:方法將MTLViewport結(jié)構(gòu)編碼為渲染命令編碼器脱茉。 如果未指定視口剪芥,Metal會設(shè)置一個默認(rèn)視口,其大小與用于創(chuàng)建渲染命令編碼器的drawable相同芦劣。


Write a Vertex Function - 寫一個頂點函數(shù)

頂點函數(shù)(也稱為頂點著色器vertex shader)的主要任務(wù)是處理傳入的頂點數(shù)據(jù)并將每個頂點映射到視口中的位置。 這樣说榆,管道中的后續(xù)階段可以引用此視口位置并將像素渲染到drawable中的精確位置虚吟。 頂點函數(shù)通過將任意頂點坐標(biāo)轉(zhuǎn)換為標(biāo)準(zhǔn)化設(shè)備坐標(biāo)(也稱為剪輯空間坐標(biāo)clip-space coordinates)來完成此任務(wù)。

剪輯空間Clip space是一個2D坐標(biāo)系签财,它將視口區(qū)域沿x軸和y軸映射到[-1.0,1.0]范圍串慰。 視口的左下角映射到(-1.0,-1.0)唱蒸,右上角映射到(1.0,1.0)邦鲫,中心映射到(0.0,0.0)。

頂點函數(shù)對于繪制的每個頂點執(zhí)行一次。 在此示例中庆捺,對于每個幀古今,繪制三個頂點以構(gòu)成三角形。 因此滔以,頂點函數(shù)每幀執(zhí)行三次。

頂點函數(shù)是用Metal著色語言Metal shading language編寫的,它基于C ++ 14率触。Metal著色語言代碼可能看起來類似于傳統(tǒng)的C / C ++代碼豹储,但兩者根本不同。 傳統(tǒng)的C / C ++代碼通常在CPU上執(zhí)行坏匪,而Metal著色語言代碼專門在GPU上執(zhí)行拟逮。 GPU提供了更大的處理帶寬,并且可以在大量頂點和片段上并行工作适滓。 但是敦迄,它具有比CPU少的內(nèi)存,不能有效地處理控制流操作粒竖,并且通常具有更高的延遲颅崩。

此示例中的頂點函數(shù)稱為vertexShader,這是它的聲明蕊苗。

vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
             constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],
             constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]])

1. Declare Vertex Function Parameters - 聲明頂點函數(shù)參數(shù)

第一個參數(shù)vertexID使用[[vertex_id]]屬性限定符并保存當(dāng)前正在執(zhí)行的頂點的索引沿后。當(dāng)繪制調(diào)用使用此頂點函數(shù)時,此值從0開始朽砰,并在每次調(diào)用vertexShader函數(shù)時遞增尖滚。使用[[vertex_id]]屬性限定符的參數(shù)通常用于索引包含頂點的數(shù)組。

第二個參數(shù)vertices是包含頂點的數(shù)組瞧柔,每個頂點定義為AAPLVertex數(shù)據(jù)類型漆弄。指向此結(jié)構(gòu)的指針定義了這些頂點的數(shù)組。

第三個也是最后一個參數(shù)viewportSizePointer包含視口的大小造锅,并具有vector_uint2數(shù)據(jù)類型撼唾。

verticesviewportSizePointer參數(shù)都使用SIMD數(shù)據(jù)類型,這些類型是C和Metal著色語言代碼都能理解的類型哥蔚。因此倒谷,示例可以在共享AAPLShaderTypes.h標(biāo)頭中定義AAPLVertex結(jié)構(gòu),該結(jié)構(gòu)包含在AAPLRenderer.mAAPLShaders.metal代碼中糙箍。因此渤愁,共享頭確保三角形頂點的數(shù)據(jù)類型在Objective-C聲明(triangleVertices)中與在Metal著色語言聲明(vertices)中相同。在Metal應(yīng)用程序中使用SIMD數(shù)據(jù)類型可確保內(nèi)存布局在CPU / GPU聲明中完全匹配深夯,并有助于將頂點數(shù)據(jù)從CPU發(fā)送到GPU抖格。

注意:對AAPLVertex結(jié)構(gòu)的任何更改都會同等地影響AAPLRenderer.mAAPLShaders.metal代碼。

verticesviewportSizePointer參數(shù)都使用[[buffer(index)]]屬性限定符。 AAPLVertexInputIndexVerticesAAPLVertexInputIndexViewportSize的值是用于在AAPLRenderer.mAAPLShaders.metal代碼中標(biāo)識和設(shè)置頂點函數(shù)輸入的索引雹拄。

2. Declare Vertex Function Return Values - 聲明頂點函數(shù)返回值

typedef struct
{
    // The [[position]] attribute of this member indicates that this value is the clip space
    // position of the vertex when this structure is returned from the vertex function
    float4 clipSpacePosition [[position]];

    // Since this member does not have a special attribute, the rasterizer interpolates
    // its value with the values of the other triangle vertices and then passes
    // the interpolated value to the fragment shader for each fragment in the triangle
    float4 color;

} RasterizerData;

頂點函數(shù)必須通過[[position]]屬性限定符為clipSpacePosition成員使用返回每個頂點的剪輯空間位置值收奔。 聲明此屬性后,管道的下一個階段(柵格化rasterization)使用clipSpacePosition值來標(biāo)識三角形角的位置办桨,并確定要渲染的像素筹淫。

3. Process Vertex Data - 處理頂點數(shù)據(jù)

示例頂點函數(shù)的主體對輸入頂點做兩件事:

  • 1) 執(zhí)行坐標(biāo)系轉(zhuǎn)換,將生成的頂點剪輯空間位置寫入out.clipSpacePosition返回值呢撞。
  • 2) 將頂點顏色傳遞給out.color返回值损姜。

要獲取輸入頂點,vertexID參數(shù)用于索引頂點數(shù)組殊霞。

float2 pixelSpacePosition = vertices[vertexID].position.xy;

此示例從每個vertices元素的position成員獲取2D頂點坐標(biāo)摧阅,并將其轉(zhuǎn)換為寫入out.clipSpacePosition返回值的剪輯空間位置。 每個頂點輸入位置相對于從視口中心開始的x和y方向上的像素數(shù)定義绷蹲。 因此棒卷,為了將這些像素空間位置轉(zhuǎn)換為剪輯空間位置,頂點函數(shù)除以視口大小的一半祝钢。

out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0);

最后比规,頂點函數(shù)訪問每個vertices元素的color成員并將其傳遞給out.color返回值,而不執(zhí)行任何修改拦英。

out.color = vertices[vertexID].color;

RasterizerData返回值的內(nèi)容現(xiàn)在已完成蜒什,結(jié)構(gòu)將傳遞到管道中的下一個階段。


Rasterization - 光柵化

頂點函數(shù)執(zhí)行三次后疤估,對于每個三角形的頂點執(zhí)行一次灾常,管道中的下一個階段,即柵格化開始铃拇。

光柵化是管道光柵化器單元產(chǎn)生碎片的階段钞瀑。 片段包含原始預(yù)像素數(shù)據(jù),用于生成渲染到drawable的像素慷荔。 對于由頂點函數(shù)生成的每個完整三角形雕什,光柵化器確定目標(biāo)可繪制的哪些像素被三角形覆蓋。 它通過測試drawable中每個像素的中心是否在三角形內(nèi)部來實現(xiàn)显晶。 在下圖中贷岸,僅生成像素中心位于三角形內(nèi)部的片段。 這些片段顯示為灰色方塊吧碾。

柵格化還確定發(fā)送到管道中下一個階段的值:片段函數(shù)凰盔。在管道的早期墓卦,頂點函數(shù)輸出RasterizerData結(jié)構(gòu)的值倦春,該結(jié)構(gòu)包含剪輯空間位置(clipSpacePosition)和顏色(color)clipSpacePosition成員使用所需的[[position]]屬性限定符,指示這些值直接用于確定三角形的片段覆蓋區(qū)域睁本。color成員沒有屬性限定符尿庐,表示應(yīng)該在三角形的片段中插入這些值。

在將每個頂點值轉(zhuǎn)換為每個片段值之后呢堰,光柵化器將color值傳遞給片段函數(shù)抄瑟。此轉(zhuǎn)換使用固定插值函數(shù),該函數(shù)計算從三角形的三個頂點的color值派生的單個加權(quán)顏色枉疼。插值函數(shù)的權(quán)重(也稱為重心坐標(biāo)barycentric coordinates)是每個頂點位置與片段中心的相對距離皮假。例如:

  • 如果片段正好位于三角形的中間,與每個三角形的三個頂點等距骂维,則每個頂點的顏色加權(quán)1/3惹资。 在下圖中,這顯示為三角形中心的灰色片段(0.33,0.33,0.33)航闺。

  • 如果一個片段非惩什猓靠近一個頂點并且距離另外兩個非常遠(yuǎn),則將近頂點的顏色加權(quán)為1潦刃,將遠(yuǎn)點的顏色加權(quán)為0侮措。在下圖中,這顯示為偏紅色 片段(0.5,0.25,0.25)靠近三角形的右下角乖杠。

  • 如果片段位于三角形的邊緣分扎,在三個頂點中的兩個頂點的中間,則每個邊緣定義頂點的顏色加權(quán)1/2滑黔,非邊緣頂點的顏色加權(quán)0笆包。在下圖中, 這顯示為三角形左邊緣的青色片段(0.0,0.5,0.5)略荡。

由于光柵化是固定的管道階段庵佣,因此無法通過自定義Metal著色語言代碼修改其行為。 在光柵化器創(chuàng)建片段及其關(guān)聯(lián)值之后汛兜,結(jié)果將傳遞到管道中的下一個階段巴粪。


Write a Fragment Function - 寫一個片段函數(shù)

片段函數(shù)(也稱為片段著色器fragment shader)的主要任務(wù)是處理傳入的片段數(shù)據(jù)并計算可繪制像素的顏色值。

此示例中的片段函數(shù)稱為fragmentShader粥谬,這是它的簽名肛根。

fragment float4 fragmentShader(RasterizerData in [[stage_in]])

該函數(shù)有一個參數(shù)in,它使用由頂點函數(shù)返回的相同RasterizerData結(jié)構(gòu)漏策。 [[stage_in]]屬性限定符表示此參數(shù)來自光柵化器派哲。 該函數(shù)返回一個四分量浮點向量,其中包含要呈現(xiàn)給drawable的最終RGBA顏色值掺喻。

此示例演示了一個非常簡單的片段函數(shù)芭届,該函數(shù)返回光柵化器的插值color值储矩,無需進一步處理。 每個片段將其插值color值渲染到三角形中的對應(yīng)像素褂乍。

return in.color;

Obtain Function Libraries and Create a Pipeline - 獲取函數(shù)庫并創(chuàng)建管道

在構(gòu)建示例時持隧,Xcode會編譯AAPLShaders.metal文件以及Objective-C代碼。但是逃片,Xcode無法在構(gòu)建時鏈接vertexShaderfragmentShader函數(shù)屡拨;相反,應(yīng)用程序需要在運行時顯式鏈接這些函數(shù)褥实。

Metal著色語言代碼分兩個階段編譯:

  • 1) 前端編譯在構(gòu)建時在Xcode中發(fā)生.metal文件從高級源代碼編譯為中間表示(IR)文件呀狼。

  • 2) 后端編譯在運行時在物理設(shè)備中進行。然后將IR文件編譯為低級機器代碼损离。

每個GPU系列都有不同的指令集赠潦。因此,Metal shading語言代碼只能在運行時由物理設(shè)備本身完全編譯為本機GPU代碼草冈。前端編譯通過將IR存儲在打包在示例的.app包中的default.metallib文件中來減少一些編譯開銷她奥。

default.metallib文件是Metal著色語言函數(shù)庫,由運行時通過調(diào)用newDefaultLibrary方法檢索的MTLLibrary對象表示怎棱。從該庫中哩俭,可以檢索由MTLFunction對象表示的特定函數(shù)。

// Load all the shader files with a .metal file extension in the project
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];

// Load the vertex function from the library
id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];

// Load the fragment function from the library
id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];

這些MTLFunction對象用于創(chuàng)建表示圖形渲染管道的MTLRenderPipelineState對象拳恋。調(diào)用MTLDevice對象的newRenderPipelineStateWithDescriptor:error:方法開始后端編譯過程凡资,該過程鏈接vertexShaderfragmentShader函數(shù),從而產(chǎn)生完全編譯的管道谬运。

MTLRenderPipelineState對象包含由MTLRenderPipelineDescriptor對象配置的其他管道設(shè)置隙赁。除頂點和片段函數(shù)外,此示例還配置colorAttachments數(shù)組中第一個條目的pixelFormat值梆暖。此示例僅渲染到單個目標(biāo)伞访,即視圖的drawable(colorAttachments [0]),其像素格式由視圖本身(colorPixelFormat)配置轰驳。視圖的像素格式定義了每個像素的內(nèi)存布局厚掷;在創(chuàng)建管道時,Metal必須能夠引用此布局级解,以便它可以正確呈現(xiàn)fragment函數(shù)生成的顏色值冒黑。

MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.label = @"Simple Pipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;

_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor
                                                         error:&error];

Send Vertex Data to a Vertex Function - 將頂點數(shù)據(jù)發(fā)送到頂點函數(shù)

創(chuàng)建管道后,可以將其分配給渲染命令編碼器勤哗。 此操作將由該特定管道處理所有后續(xù)渲染命令抡爹。

[renderEncoder setRenderPipelineState:_pipelineState];

此示例使用setVertexBytes:length:atIndex:方法將頂點數(shù)據(jù)發(fā)送到頂點函數(shù)。如前所述芒划,示例的vertexShader函數(shù)的簽名有兩個參數(shù)冬竟,verticesviewportSizePointer昙篙,它們使用[[buffer(index)]]屬性限定符。 setVertexBytes:length:atIndex:方法中index參數(shù)的值映射到[[buffer(index)]]屬性限定符中具有相同index值的參數(shù)诱咏。因此,調(diào)用setVertexBytes:length:atIndex:方法為特定的頂點函數(shù)參數(shù)設(shè)置特定的頂點數(shù)據(jù)缴挖。

AAPLVertexInputIndexVerticesAAPLVertexInputIndexViewportSize值在AAPLRenderer.mAAPLShaders.metal文件之間共享的AAPLShaderTypes.h標(biāo)頭中定義袋狞。該示例將這些值用于setVertexBytes:length:atIndex:方法的index參數(shù)以及與同一頂點函數(shù)對應(yīng)的[[buffer(index)]]屬性限定符。通過減少由于硬編碼整數(shù)(可能將錯誤的數(shù)據(jù)發(fā)送到錯誤的參數(shù))導(dǎo)致的潛在索引不匹配映屋,可以跨不同文件共享這些值苟鸯,從而使示例更加健壯。

此示例將以下頂點數(shù)據(jù)發(fā)送到頂點函數(shù):

  • 使用AAPLVertexInputIndexVertices索引值將triangleVertices指針發(fā)送到vertices參數(shù)
  • 使用AAPLVertexInputIndexViewportSize索引值將_viewportSize指針發(fā)送到viewportSizePointer參數(shù)
// You send a pointer to the `triangleVertices` array also and indicate its size
// The `AAPLVertexInputIndexVertices` enum value corresponds to the `vertexArray`
// argument in the `vertexShader` function because its buffer attribute also uses
// the `AAPLVertexInputIndexVertices` enum value for its index
[renderEncoder setVertexBytes:triangleVertices
                       length:sizeof(triangleVertices)
                      atIndex:AAPLVertexInputIndexVertices];

// You send a pointer to `_viewportSize` and also indicate its size
// The `AAPLVertexInputIndexViewportSize` enum value corresponds to the
// `viewportSizePointer` argument in the `vertexShader` function because its
//  buffer attribute also uses the `AAPLVertexInputIndexViewportSize` enum value
//  for its index
[renderEncoder setVertexBytes:&_viewportSize
                       length:sizeof(_viewportSize)
                      atIndex:AAPLVertexInputIndexViewportSize];

Draw the Triangle - 繪制三角形

設(shè)置管道及其關(guān)聯(lián)的頂點數(shù)據(jù)后棚点,發(fā)出繪制調(diào)用會執(zhí)行管道并繪制樣本的單個三角形早处。該示例將單個繪圖命令編碼到渲染命令編碼器(render command encoder)中。

三角形是Metal中的幾何圖元瘫析,需要繪制三個頂點砌梆。其他基元包括需要兩個頂點的線,或者只需要一個頂點的點贬循。 drawPrimitives:vertexStart:vertexCount:方法允許您準(zhǔn)確指定要繪制的基元類型以及要使用的從先前設(shè)置的頂點數(shù)據(jù)派生的頂點數(shù)據(jù)咸包。為vertexStart參數(shù)設(shè)置0表示繪圖應(yīng)以頂點數(shù)組中的第一個頂點開始。這意味著頂點函數(shù)的vertexID參數(shù)的第一個值(使用[[vertex_id]]屬性限定符)將為0杖虾。設(shè)置為vertexCount參數(shù)的3表示應(yīng)繪制三個頂點烂瘫,從而生成一個三角形。 (也就是說奇适,對于vertexID參數(shù)坟比,頂點函數(shù)執(zhí)行三次,值為0,1和2)嚷往。

// Draw the 3 vertices of our triangle
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
                  vertexStart:0
                  vertexCount:3];

此調(diào)用是對單個三角形的渲染命令進行編碼所需的最后一次調(diào)用葛账。 繪圖完成后,渲染循環(huán)可以結(jié)束編碼皮仁,提交命令緩沖區(qū)注竿,并呈現(xiàn)包含渲染三角形的drawable

后記

本篇主要講述了您學(xué)習(xí)如何在Metal中渲染基本幾何體魂贬,感興趣的給個贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末巩割,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子付燥,更是在濱河造成了極大的恐慌宣谈,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件键科,死亡現(xiàn)場離奇詭異闻丑,居然都是意外死亡漩怎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門嗦嗡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來勋锤,“玉大人,你說我怎么就攤上這事侥祭∪矗” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵矮冬,是天一觀的道長谈宛。 經(jīng)常有香客問我,道長胎署,這世上最難降的妖魔是什么吆录? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮琼牧,結(jié)果婚禮上恢筝,老公的妹妹穿的比我還像新娘。我一直安慰自己巨坊,他們只是感情好滋恬,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抱究,像睡著了一般恢氯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鼓寺,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天勋拟,我揣著相機與錄音,去河邊找鬼妈候。 笑死敢靡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的苦银。 我是一名探鬼主播啸胧,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼幔虏!你這毒婦竟也來了纺念?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤想括,失蹤者是張志新(化名)和其女友劉穎陷谱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡烟逊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年渣窜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宪躯。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡乔宿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出访雪,到底是詐尸還是另有隱情详瑞,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布冬阳,位于F島的核電站,受9級特大地震影響党饮,放射性物質(zhì)發(fā)生泄漏肝陪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一刑顺、第九天 我趴在偏房一處隱蔽的房頂上張望氯窍。 院中可真熱鬧,春花似錦蹲堂、人聲如沸狼讨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽政供。三九已至,卻和暖如春朽基,著一層夾襖步出監(jiān)牢的瞬間布隔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工稼虎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留衅檀,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓霎俩,卻偏偏與公主長得像哀军,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子打却,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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