OpenGL 圖形庫(kù)的使用(四十九)—— 實(shí)戰(zhàn)之2D游戲 - 渲染精靈

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.01.20

前言

OpenGL 圖形庫(kù)項(xiàng)目中一直也沒用過,最近也想學(xué)著使用這個(gè)圖形庫(kù)丧肴,感覺還是很有意思,也就自然想著好好的總結(jié)一下胧后,希望對(duì)大家能有所幫助芋浮。下面內(nèi)容來自歡迎來到OpenGL的世界
1. OpenGL 圖形庫(kù)使用(一) —— 概念基礎(chǔ)
2. OpenGL 圖形庫(kù)使用(二) —— 渲染模式壳快、對(duì)象纸巷、擴(kuò)展和狀態(tài)機(jī)
3. OpenGL 圖形庫(kù)使用(三) —— 著色器镇草、數(shù)據(jù)類型與輸入輸出
4. OpenGL 圖形庫(kù)使用(四) —— Uniform及更多屬性
5. OpenGL 圖形庫(kù)使用(五) —— 紋理
6. OpenGL 圖形庫(kù)使用(六) —— 變換
7. OpenGL 圖形庫(kù)的使用(七)—— 坐標(biāo)系統(tǒng)之五種不同的坐標(biāo)系統(tǒng)(一)
8. OpenGL 圖形庫(kù)的使用(八)—— 坐標(biāo)系統(tǒng)之3D效果(二)
9. OpenGL 圖形庫(kù)的使用(九)—— 攝像機(jī)(一)
10. OpenGL 圖形庫(kù)的使用(十)—— 攝像機(jī)(二)
11. OpenGL 圖形庫(kù)的使用(十一)—— 光照之顏色
12. OpenGL 圖形庫(kù)的使用(十二)—— 光照之基礎(chǔ)光照
13. OpenGL 圖形庫(kù)的使用(十三)—— 光照之材質(zhì)
14. OpenGL 圖形庫(kù)的使用(十四)—— 光照之光照貼圖
15. OpenGL 圖形庫(kù)的使用(十五)—— 光照之投光物
16. OpenGL 圖形庫(kù)的使用(十六)—— 光照之多光源
17. OpenGL 圖形庫(kù)的使用(十七)—— 光照之復(fù)習(xí)總結(jié)
18. OpenGL 圖形庫(kù)的使用(十八)—— 模型加載之Assimp
19. OpenGL 圖形庫(kù)的使用(十九)—— 模型加載之網(wǎng)格
20. OpenGL 圖形庫(kù)的使用(二十)—— 模型加載之模型
21. OpenGL 圖形庫(kù)的使用(二十一)—— 高級(jí)OpenGL之深度測(cè)試
22. OpenGL 圖形庫(kù)的使用(二十二)—— 高級(jí)OpenGL之模板測(cè)試Stencil testing
23. OpenGL 圖形庫(kù)的使用(二十三)—— 高級(jí)OpenGL之混合Blending
24. OpenGL 圖形庫(kù)的使用(二十四)—— 高級(jí)OpenGL之面剔除Face culling
25. OpenGL 圖形庫(kù)的使用(二十五)—— 高級(jí)OpenGL之幀緩沖Framebuffers
26. OpenGL 圖形庫(kù)的使用(二十六)—— 高級(jí)OpenGL之立方體貼圖Cubemaps
27. OpenGL 圖形庫(kù)的使用(二十七)—— 高級(jí)OpenGL之高級(jí)數(shù)據(jù)Advanced Data
28. OpenGL 圖形庫(kù)的使用(二十八)—— 高級(jí)OpenGL之高級(jí)GLSL Advanced GLSL
29. OpenGL 圖形庫(kù)的使用(二十九)—— 高級(jí)OpenGL之幾何著色器Geometry Shader
30. OpenGL 圖形庫(kù)的使用(三十)—— 高級(jí)OpenGL之實(shí)例化Instancing
31. OpenGL 圖形庫(kù)的使用(三十一)—— 高級(jí)OpenGL之抗鋸齒Anti Aliasing
32. OpenGL 圖形庫(kù)的使用(三十二)—— 高級(jí)光照之高級(jí)光照Advanced Lighting
33. OpenGL 圖形庫(kù)的使用(三十三)—— 高級(jí)光照之Gamma校正Gamma Correction
34. OpenGL 圖形庫(kù)的使用(三十四)—— 高級(jí)光照之陰影 - 陰影映射Shadow Mapping
35. OpenGL 圖形庫(kù)的使用(三十五)—— 高級(jí)光照之陰影 - 點(diǎn)陰影Point Shadows
36. OpenGL 圖形庫(kù)的使用(三十六)—— 高級(jí)光照之法線貼圖Normal Mapping
37. OpenGL 圖形庫(kù)的使用(三十七)—— 高級(jí)光照之視差貼圖Parallax Mapping
38. OpenGL 圖形庫(kù)的使用(三十八)—— 高級(jí)光照之HDR
39. OpenGL 圖形庫(kù)的使用(三十九)—— 高級(jí)光照之泛光
40. OpenGL 圖形庫(kù)的使用(四十)—— 高級(jí)光照之延遲著色法Deferred Shading
41. OpenGL 圖形庫(kù)的使用(四十一)—— 高級(jí)光照之SSAO
42. OpenGL 圖形庫(kù)的使用(四十二)—— PBR之理論Theory
43. OpenGL 圖形庫(kù)的使用(四十三)—— PBR之光照Lighting
44. OpenGL 圖形庫(kù)的使用(四十四)—— PBR之幾篇沒有翻譯的英文原稿
45. OpenGL 圖形庫(kù)的使用(四十五)—— 實(shí)戰(zhàn)之調(diào)試Debugging
46. OpenGL 圖形庫(kù)的使用(四十六)—— 實(shí)戰(zhàn)之文本渲染Text Rendering
47. OpenGL 圖形庫(kù)的使用(四十七)—— 實(shí)戰(zhàn)之2D游戲 - Breakout
48. OpenGL 圖形庫(kù)的使用(四十八)—— 實(shí)戰(zhàn)之2D游戲 - 準(zhǔn)備工作

渲染精靈

為了給我們當(dāng)前這個(gè)黑漆漆的游戲世界帶來一點(diǎn)生機(jī),我們將會(huì)渲染一些精靈(Sprite)來填補(bǔ)這些空虛瘤旨。精靈有很多種定義梯啤,但這里主要是指一個(gè)2D圖片,它通常是和一些擺放相關(guān)的屬性數(shù)據(jù)一起使用存哲,比如位置因宇、旋轉(zhuǎn)角度以及二維的大小。簡(jiǎn)單來說祟偷,精靈就是那些可以在2D游戲中渲染的圖像/紋理對(duì)象察滑。

我們可以像前面大多數(shù)教程里做的那樣,用頂點(diǎn)數(shù)據(jù)創(chuàng)建2D形狀肩袍,將所有數(shù)據(jù)傳進(jìn)GPU并手動(dòng)變換圖形杭棵。然而,在我們這樣的大型應(yīng)用中氛赐,我們最好是對(duì)2D形狀渲染做一些抽象化魂爪。如果我們要對(duì)每一個(gè)對(duì)象手動(dòng)定義形狀和變換的話,很快就會(huì)變得非常凌亂了艰管。

在這個(gè)教程中滓侍,我們將會(huì)定義一個(gè)渲染類,讓我們用最少的代碼渲染大量的精靈牲芋。這樣撩笆,我們就可以從散沙一樣的OpenGL渲染代碼中抽象出游戲代碼,這也是在一個(gè)大型工程中常用的做法缸浦。雖然我們首先還要去配置一個(gè)合適的投影矩陣夕冲。


2D投影矩陣

從這個(gè)坐標(biāo)系統(tǒng)教程中,我們明白了投影矩陣的作用是把觀察空間坐標(biāo)轉(zhuǎn)化為標(biāo)準(zhǔn)化設(shè)備坐標(biāo)裂逐。通過生成合適的投影矩陣歹鱼,我們就可以在不同的坐標(biāo)系下計(jì)算,這可能比把所有的坐標(biāo)都指定為標(biāo)準(zhǔn)化設(shè)備坐標(biāo)(再計(jì)算)要更容易處理卜高。

我們不需要對(duì)坐標(biāo)系應(yīng)用透視弥姻,因?yàn)檫@個(gè)游戲完全是2D的,所以一個(gè)正射投影矩陣(Orthographic Projection Matrix)就可以了掺涛。由于正射投影矩陣幾乎直接變換所有的坐標(biāo)至裁剪空間庭敦,我們可以定義如下的投影矩陣指定世界坐標(biāo)為屏幕坐標(biāo):

glm::mat4 projection = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f);

前面的四個(gè)參數(shù)依次指定了投影平截頭體的左、右薪缆、下秧廉、上邊界。這個(gè)投影矩陣把所有在0到800之間的x坐標(biāo)變換到-1到1之間,并把所有在0到600之間的y坐標(biāo)變換到-1到1之間定血。這里我們指定了平截頭體頂部的y坐標(biāo)值為0赔癌,底部的y坐標(biāo)值為600诞外。所以澜沟,這個(gè)場(chǎng)景的左上角坐標(biāo)為(0,0),右下角坐標(biāo)為(800,600)峡谊,就像屏幕坐標(biāo)那樣茫虽。觀察空間坐標(biāo)直接對(duì)應(yīng)最終像素的坐標(biāo)。

這樣我們就可以指定所有的頂點(diǎn)坐標(biāo)為屏幕上的像素坐標(biāo)了既们,這對(duì)2D游戲來說相當(dāng)直觀濒析。


渲染精靈

渲染一個(gè)實(shí)際的精靈應(yīng)該不會(huì)太復(fù)雜。我們創(chuàng)建一個(gè)有紋理的四邊形啥纸,它在之后可以使用一個(gè)模型矩陣來變換号杏,然后我們會(huì)用之前定義的正射投影矩陣來投影它。

由于Breakout是一個(gè)靜態(tài)的游戲斯棒,這里不需要觀察/攝像機(jī)矩陣盾致,我們可以直接使用投影矩陣把世界空間坐標(biāo)變換到裁剪空間坐標(biāo)。

為了變換精靈我們會(huì)使用下面這個(gè)頂點(diǎn)著色器:

#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>

out vec2 TexCoords;

uniform mat4 model;
uniform mat4 projection;

void main()
{
    TexCoords = vertex.zw;
    gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}

注意荣暮,我們僅用了一個(gè)vec4變量來存儲(chǔ)位置和紋理坐標(biāo)數(shù)據(jù)庭惜。因?yàn)槲恢煤图y理坐標(biāo)數(shù)據(jù)都只包含了兩個(gè)float,所以我們可以把他們組合在一起作為一個(gè)單一的頂點(diǎn)屬性穗酥。

片段著色器也比較直觀护赊。我們會(huì)在這里獲取一個(gè)紋理和一個(gè)顏色向量,它們都會(huì)影響片段的最終顏色砾跃。我們?cè)O(shè)置了一個(gè)紋理和顏色向量骏啰,她們兩個(gè)都會(huì)對(duì)像素最后的顏色產(chǎn)生影響。有了這個(gè)uniform顏色向量抽高,我們就可以很方便地在游戲代碼中改變精靈的顏色了判耕。

#version 330 core
in vec2 TexCoords;
out vec4 color;

uniform sampler2D image;
uniform vec3 spriteColor;

void main()
{
    color = vec4(spriteColor, 1.0) * texture(image, TexCoords);
}

為了讓精靈的渲染更加有條理,我們定義了一個(gè)SpriteRenderer類厨内,有了它只需要一個(gè)函數(shù)就可以渲染精靈了祈秕。它的定義如下:

class SpriteRenderer
{
    public:
        SpriteRenderer(Shader &shader);
        ~SpriteRenderer();

        void DrawSprite(Texture2D &texture, glm::vec2 position, 
            glm::vec2 size = glm::vec2(10, 10), GLfloat rotate = 0.0f, 
            glm::vec3 color = glm::vec3(1.0f));
    private:
        Shader shader; 
        GLuint quadVAO;

        void initRenderData();
};

SpriteRenderer類封裝了一個(gè)著色器對(duì)象,一個(gè)頂點(diǎn)數(shù)組對(duì)象以及一個(gè)渲染和初始化函數(shù)雏胃。它的構(gòu)造函數(shù)接受一個(gè)著色器對(duì)象用于之后的渲染请毛。

1. 初始化

首先,讓我們深入研究一下負(fù)責(zé)配置quadVAOinitRenderData函數(shù):

void SpriteRenderer::initRenderData()
{
    // 配置 VAO/VBO
    GLuint VBO;
    GLfloat vertices[] = { 
        // 位置     // 紋理
        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 

        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 0.0f
    };

    glGenVertexArrays(1, &this->quadVAO);
    glGenBuffers(1, &VBO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindVertexArray(this->quadVAO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);  
    glBindVertexArray(0);
}

這里瞭亮,我們首先定義了一組以四邊形的左上角為(0,0)坐標(biāo)的頂點(diǎn)方仿。這意味著當(dāng)我們?cè)谒倪呅紊蠎?yīng)用一個(gè)位移或縮放變換的時(shí)候,它們會(huì)從四邊形的左上角開始進(jìn)行變換。這在2D圖形以及/或GUI系統(tǒng)中廣為接受仙蚜,元素的位置定義為元素左上角的位置此洲。

接下來我們簡(jiǎn)單地向GPU傳遞頂點(diǎn)數(shù)據(jù),并且配置頂點(diǎn)屬性委粉,當(dāng)然在這里僅有一個(gè)頂點(diǎn)屬性呜师。因?yàn)樗械木`共享著同樣的頂點(diǎn)數(shù)據(jù),我們只需要為這個(gè)精靈渲染器定義一個(gè)VAO就行了贾节。

2. 渲染

渲染精靈并不是太難汁汗;我們使用精靈渲染器的著色器,配置一個(gè)模型矩陣并且設(shè)置相關(guān)的uniform栗涂。這里最重要的就是變換的順序:

void SpriteRenderer::DrawSprite(Texture2D &texture, glm::vec2 position, 
  glm::vec2 size, GLfloat rotate, glm::vec3 color)
{
    // 準(zhǔn)備變換
    this->shader.Use();
    glm::mat4 model;
    model = glm::translate(model, glm::vec3(position, 0.0f));  

    model = glm::translate(model, glm::vec3(0.5f * size.x, 0.5f * size.y, 0.0f)); 
    model = glm::rotate(model, rotate, glm::vec3(0.0f, 0.0f, 1.0f)); 
    model = glm::translate(model, glm::vec3(-0.5f * size.x, -0.5f * size.y, 0.0f));

    model = glm::scale(model, glm::vec3(size, 1.0f)); 

    this->shader.SetMatrix4("model", model);
    this->shader.SetVector3f("spriteColor", color);

    glActiveTexture(GL_TEXTURE0);
    texture.Bind();

    glBindVertexArray(this->quadVAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
}  

當(dāng)試圖在一個(gè)場(chǎng)景中用旋轉(zhuǎn)矩陣和縮放矩陣放置一個(gè)對(duì)象的時(shí)候知牌,建議是首先做縮放變換,再旋轉(zhuǎn)斤程,最后才是位移變換角寸。因?yàn)榫仃嚦朔ㄊ菑挠蚁蜃髨?zhí)行的,所以我們變換的矩陣順序是相反的:移動(dòng)忿墅,旋轉(zhuǎn)扁藕,縮放。

旋轉(zhuǎn)變換可能看起來稍微有點(diǎn)讓人望而卻步球匕。我們從變換教程里面知道旋轉(zhuǎn)總是圍繞原點(diǎn)(0,0)轉(zhuǎn)動(dòng)的纹磺。因?yàn)槲覀冎付怂倪呅蔚淖笊辖菫?0,0),所有的旋轉(zhuǎn)都會(huì)圍繞這個(gè)(0,0)亮曹。簡(jiǎn)單來說橄杨,在四邊形左上角的旋轉(zhuǎn)原點(diǎn)(Origin of Rotation)會(huì)產(chǎn)生不想要的結(jié)果。我們想要做的是把旋轉(zhuǎn)原點(diǎn)移到四邊形的中心照卦,這樣旋轉(zhuǎn)就會(huì)圍繞四邊形中心而不是左上角了式矫。我們會(huì)在旋轉(zhuǎn)之前把旋轉(zhuǎn)原點(diǎn)移動(dòng)到四邊形中心來解決這個(gè)問題。

因?yàn)槲覀兪紫葧?huì)縮放這個(gè)四邊形役耕,我們?cè)谖灰凭`的中心時(shí)還需要把精靈的大小考慮進(jìn)來(這也是為什么我們乘以了精靈的size向量)采转。在旋轉(zhuǎn)變換應(yīng)用之后,我們會(huì)反轉(zhuǎn)之前的平移操作瞬痘。

把所有變換組合起來我們就能以任何想要的方式放置故慈、縮放并平移每個(gè)精靈了。下面你可以找到精靈渲染器完整的源代碼:

/*******************************************************************
** This code is part of Breakout.
**
** Breakout is free software: you can redistribute it and/or modify
** it under the terms of the CC BY 4.0 license as published by
** Creative Commons, either version 4 of the License, or (at your
** option) any later version.
******************************************************************/
#include "sprite_renderer.h"


SpriteRenderer::SpriteRenderer(Shader &shader)
{
    this->shader = shader;
    this->initRenderData();
}

SpriteRenderer::~SpriteRenderer()
{
    glDeleteVertexArrays(1, &this->quadVAO);
}

void SpriteRenderer::DrawSprite(Texture2D &texture, glm::vec2 position, glm::vec2 size, GLfloat rotate, glm::vec3 color)
{
    // Prepare transformations
    this->shader.Use();
    glm::mat4 model;
    model = glm::translate(model, glm::vec3(position, 0.0f));  // First translate (transformations are: scale happens first, then rotation and then finall translation happens; reversed order)

    model = glm::translate(model, glm::vec3(0.5f * size.x, 0.5f * size.y, 0.0f)); // Move origin of rotation to center of quad
    model = glm::rotate(model, rotate, glm::vec3(0.0f, 0.0f, 1.0f)); // Then rotate
    model = glm::translate(model, glm::vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); // Move origin back

    model = glm::scale(model, glm::vec3(size, 1.0f)); // Last scale

    this->shader.SetMatrix4("model", model);

    // Render textured quad
    this->shader.SetVector3f("spriteColor", color);

    glActiveTexture(GL_TEXTURE0);
    texture.Bind();

    glBindVertexArray(this->quadVAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
}

void SpriteRenderer::initRenderData()
{
    // Configure VAO/VBO
    GLuint VBO;
    GLfloat vertices[] = { 
        // Pos      // Tex
        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 

        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 0.0f
    };

    glGenVertexArrays(1, &this->quadVAO);
    glGenBuffers(1, &VBO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindVertexArray(this->quadVAO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

你好察绷,精靈

有了SpriteRenderer類,我們終于能夠渲染實(shí)際的圖像到屏幕上了津辩!讓我們來在游戲代碼里面初始化一個(gè)精靈并且加載我們最喜愛的紋理

SpriteRenderer  *Renderer;

void Game::Init()
{
    // 加載著色器
    ResourceManager::LoadShader("shaders/sprite.vs", "shaders/sprite.frag", nullptr, "sprite");
    // 配置著色器
    glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->Width), 
        static_cast<GLfloat>(this->Height), 0.0f, -1.0f, 1.0f);
    ResourceManager::GetShader("sprite").Use().SetInteger("image", 0);
    ResourceManager::GetShader("sprite").SetMatrix4("projection", projection);
    // 設(shè)置專用于渲染的控制
    Renderer = new SpriteRenderer(ResourceManager::GetShader("sprite"));
    // 加載紋理
    ResourceManager::LoadTexture("textures/awesomeface.png", GL_TRUE, "face");
}

然后拆撼,在渲染函數(shù)里面我們就可以渲染一下我們心愛的吉祥物來檢測(cè)是否一切都正常工作了:

void Game::Render()
{
    Renderer->DrawSprite(ResourceManager::GetTexture("face"), 
        glm::vec2(200, 200), glm::vec2(300, 400), 45.0f, glm::vec3(0.0f, 1.0f, 0.0f));
}

這里我們把精靈放置在靠近屏幕中心的位置容劳,它的高度會(huì)比寬度大一點(diǎn)。我們同樣也把它旋轉(zhuǎn)了45度并把它設(shè)置為綠色闸度。注意竭贩,我們?cè)O(shè)定的精靈的位置是精靈四邊形左上角的位置。

如果你一切都做對(duì)了你應(yīng)該可以看到下面的結(jié)果:

你可以在這里找到更新后的游戲類源代碼莺禁。

/*******************************************************************
** This code is part of Breakout.
**
** Breakout is free software: you can redistribute it and/or modify
** it under the terms of the CC BY 4.0 license as published by
** Creative Commons, either version 4 of the License, or (at your
** option) any later version.
******************************************************************/
#include "game.h"
#include "resource_manager.h"
#include "sprite_renderer.h"


// Game-related State data
SpriteRenderer  *Renderer;


Game::Game(GLuint width, GLuint height) 
    : State(GAME_ACTIVE), Keys(), Width(width), Height(height) 
{ 

}

Game::~Game()
{
    delete Renderer;
}

void Game::Init()
{
    // Load shaders
    ResourceManager::LoadShader("shaders/sprite.vs", "shaders/sprite.frag", nullptr, "sprite");
    // Configure shaders
    glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->Width), static_cast<GLfloat>(this->Height), 0.0f, -1.0f, 1.0f);
    ResourceManager::GetShader("sprite").Use().SetInteger("image", 0);
    ResourceManager::GetShader("sprite").SetMatrix4("projection", projection);
    // Load textures
    ResourceManager::LoadTexture("textures/awesomeface.png", GL_TRUE, "face");
    // Set render-specific controls
    Renderer = new SpriteRenderer(ResourceManager::GetShader("sprite"));
}

void Game::Update(GLfloat dt)
{

}


void Game::ProcessInput(GLfloat dt)
{

}

void Game::Render()
{
    Renderer->DrawSprite(ResourceManager::GetTexture("face"), glm::vec2(200, 200), glm::vec2(300, 400), 45.0f, glm::vec3(0.0f, 1.0f, 0.0f));
}

現(xiàn)在我們已經(jīng)讓渲染系統(tǒng)正常工作了留量,我們可以在下一節(jié)教程中用它來構(gòu)建游戲的關(guān)卡。

后記

本篇已結(jié)束睁宰,后面更精彩~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肪获,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子柒傻,更是在濱河造成了極大的恐慌,老刑警劉巖较木,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件红符,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡伐债,警方通過查閱死者的電腦和手機(jī)预侯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峰锁,“玉大人萎馅,你說我怎么就攤上這事『缃” “怎么了糜芳?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)魄衅。 經(jīng)常有香客問我峭竣,道長(zhǎng),這世上最難降的妖魔是什么晃虫? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任皆撩,我火速辦了婚禮,結(jié)果婚禮上哲银,老公的妹妹穿的比我還像新娘扛吞。我一直安慰自己,他們只是感情好荆责,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布滥比。 她就那樣靜靜地躺著,像睡著了一般草巡。 火紅的嫁衣襯著肌膚如雪守呜。 梳的紋絲不亂的頭發(fā)上型酥,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音查乒,去河邊找鬼弥喉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛玛迄,可吹牛的內(nèi)容都是我干的由境。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼蓖议,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼虏杰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勒虾,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤纺阔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后修然,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笛钝,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年愕宋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玻靡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡中贝,死狀恐怖囤捻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情邻寿,我是刑警寧澤蝎土,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站老厌,受9級(jí)特大地震影響瘟则,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜枝秤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一醋拧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淀弹,春花似錦丹壕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沐序,卻和暖如春琉用,著一層夾襖步出監(jiān)牢的瞬間堕绩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工邑时, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奴紧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓晶丘,卻偏偏與公主長(zhǎng)得像黍氮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浅浮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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