计算机图形学与Shader

一、计算机图形学

1. 概述

  1. Unity的代码在CPU中运行,图形学的代码在GPU中运行
  2. 图形学使用CG(C Graph)语言,是英伟达和微软联合开发的跨平台语言
  3. 操作系统中的图形处理软件DX12,使用GLSL(OpenGL Shading Language)、DX语言
  4. shader 1.0实现的功能很少,更像设置参数;shader 2.0,为开发者留下了开发接口,可以进行可编程式的开发;Unity的shader,表面着色器,介于1.0和2.0之间,翻译成2.0然后发给GPU
  5. shader 1.0 :固定管线着色器、shader 2.0:顶点片段着色器、Unity shader:表面着色器
  6. shader:着色器,使用纹理、数据、颜色等原材料,通过编程的方式进行一些逻辑运算,设置到材质球上
  7. 写shader,要使用的原材料尽量可以变化,适应多种平台多种需求

2. 渲染绘图管线

  • 图像从GPU里的体现过程:一个个顶点连线,组成三角形作为面,由面拼成一个图形。
  • 绘图流程:顶点处理、面处理、光栅化、像素处理

2.1 顶点处理

顶点处理就是坐标转换,将物体的本地坐标最终转换成屏幕坐标

  • 坐标按这四种坐标系的顺序进行转换:本地坐标,世界坐标,观察坐标系,投影坐标系
  • unity中拼合的顶点分开算顶点,例如一个Cube有4 * 6 = 24个顶点

2.2 面的处理

  1. 面组装:将顶点处理得到的点集合进行处理,把点连成面
  2. 面截取:连成面之后,判断哪些在屏幕范围,将这些面截取
  3. 面剔除:面截取后,判断哪些面会被别的面挡住,显示不出来,将这些面剔除

2.3 光栅化

  • 将面处理得到的面转换成一个个像素,称为光栅化
  • 边缘锯齿等问题出在这步

2.4 像素处理

输入像素的位置、深度、贴图坐标、法线、切线、颜色等,给像素着色,使用四通道RGBA

2.5 shader各版本能做的事情

  • shader 1.0:像素处理
  • shader 2.0:像素处理、顶点处理

3. 固定管线着色器(Fixed Shader、Shader 1.0)

每有一个像素,就执行一次

3.1 结构

// Shader关键字 路径
Shader "AShader/FixedShader/Base001"{
    // 属性模块
    Properties
    {
    
    }
    
    // 子着色器,可以有多个,作用是面对不同的设备,从上到下做尝试
    // 质量高,渲染效果好的,性能消耗大的
    SubShader
    {
        // 通道1
        Pass
        {
            
        }
        
        // 通道2
        Pass
        {
            
        }
    }
    
    // 中等质量
    SubShader
    {
        Pass
        {
            
        }
    }
    
    // 质量差
    SubShader
    {
        Pass
        {
            
        }
    }
    
    // 最基础的,Unity 4.x 预设的漫反射
    Fallback "Diffuse"
}

3.2 属性

Properties
{
    // 属性定义语法:属性名("面板显示名称",属性类型) = 初值
    
    // 浮点型(使用较少)
    _FloatValue("浮点数", float) = 0.5
    // 范围浮点型(常用)
    _RangeValue("范围浮点数", Range(0, 100)) = 30
    // 四维数 (x, y, z, w) (使用较少)
    _VectorValue("四维数", Vector) = (1, 1, 1, 1)
    // 颜色,范围[0 - 1](常用)
    _ColorValue("颜色值", Color) = (1, 0, 0, 1)
    // 2阶贴图,材质的长宽是2的多少次幂 2x2 4x4 8x8 16x16(常用)
    // Tiling x, y :平铺
    // Offset x, y :起始位置
    _MainTexture("主纹理", 2D) = ""{}
    // 非2阶贴图(使用较少)
    _RectTexture("非2阶纹理", Rect) = ""{}
    // 立方体贴图 6个纹理,每个纹理表示一个面(使用很少)
    _CubeTexture("3D纹理", Cube) = ""{}
}

3.3 命令

  • Tag命令
    写在SubShader中
// 标签
Tags
{
    // 渲染队列,数字越小越先渲染,数字大的会挡住数字小的
    // 队列在赋值的时候可以使用运算,但是是字符串赋值,所以+号左右不能有空格
    "Queue" = "Transparent+1"
}

预设的四种渲染队列级别

级别 翻译 代表数字
Background 后台 1000
Geometry(默认) 几何体 2000
Transparent 透明 3000
Overlay 覆盖 4000
  • 渲染命令
    写在Pass(通道)中
命令 作用
Color(r, g, b, a) 用指定颜色渲染
Color[Color] 用属性颜色渲染
Lighting On/Off 开启/关闭顶点光照
Cull Front/Back/Off 剔除正面/剔除背面/关闭剔除
ZWrite On/Off(默认为On) 是否要将像素的深度写入深度缓存中
ZTest Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off(默认为LEqual) 通过比较深度来更改深度缓存的值,Always指的是直接将当前像素颜色(不是深度)写进颜色缓冲区中,Never指的是永远不会将当前像素颜色写进颜色缓冲区中,相当于消失,Off指的是关闭深度测试
SeparateSpecular On/Off 镜面反射开启/关闭

利用渲染队列修改显示顺序

Shader "AShader/FixedShader/Fixed003"
{
    Properties
    {
        _MainColor("主颜色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {

        // 标签
        Tags
        {
            // 渲染队列
            "Queue" = "Transparent+1"
        }

        Pass
        {
            // 关闭深度测试
            ZTest Off

            Lighting On

            Material
            {
                Diffuse[_MainColor]
            }
        }
    }
}
  • 透明混合命令
命令 作用
Blend SrcAlpha OneMinusSrcAlpha 透明混合,有时候后面的东西会消失,不稳定,基本不在shader 1.0中使用
Blend One One 相加,主颜色更亮
Blend One OneMinusDstColor 更柔和的相加
Blend DstColor Zero 相乘
Blend DstColor SrcColor 2倍乘法
Shader "AShader/FixedShader/Fixed009"{

    Properties
    {
        _MainTexture("主纹理", 2D) = ""{}

    }

    SubShader
    {
        // 透明混合
        //Blend SrcAlpha OneMinusSrcAlpha
        //Blend One One
        //Blend One OneMinusDstColor
        //Blend DstColor Zero
        Blend DstColor SrcColor

        Pass
        {
            SetTexture[_MainTexture]
            {
                combine texture
            }
        }
    }
}
  • Alpha测试命令
命令 作用
AlphaTest Off 关闭
AlphaTest Greater 大于
AlphaTest GEqual 大于等于
AlphaTest Less 小于
AlphaTest LEqual 小于等于
AlphaTest Equal 等于
AlphaTest NotEqual 不等于
AlphaTest Always 渲染所有像素
AlphaTest Never 不渲染任何像素
Shader "AShader/FixedShader/Fixed008"{

    Properties
    {
        _AlphaTest("透明测试", Range(0, 1)) = 1

        _MainTexture("主纹理", 2D) = ""{}
    }

    SubShader
    {
        Pass
        {
            // 溶解效果
            AlphaTest Greater [_AlphaTest]

            SetTexture[_MainTexture]
            {
                combine texture
            }
        }
    }
}
  • Material 材质命令
    写在Pass -> Material中
命令 作用
Diffuse[Color] 漫反射颜色
Ambient[Color] 环境光反射颜色
Shininess[float] 光泽度
Specular[Color] 高光颜色
Emission[Color] 自发光颜色
Shader "AShader/FixedShader/Fixed006"{

    Properties
    {
        _MainColor("主颜色", Color) = (1, 1, 1, 1)
        _SpecularColor("高光颜色", Color) = (1, 1, 1 ,1)
        _Shininess("光泽度", Range(0.1, 1)) = 0.5
        _Ambient("环境光颜色", Color) = (1, 1, 1, 1)
        _Emission("自发光颜色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            Color[_MainColor]
            Lighting On
            SeparateSpecular On
            Material
            {
                Diffuse[_MainColor]
                Specular[_SpecularColor]
                Shininess[_Shininess]
                Ambient[_AmbientColor]
                Emission[_EmissionColor]
            }
        }
    }
}
  • Texture 纹理命令
    纹理命令写在Pass中,纹理命令不区分大小写
SetTexture[Texture]
{
    // 定义constantColor
    constantColor(r, g, b, a)
    constantColor[Color]
    // 合并命令
    // 因为RGBA的值范围是[0 - 1],所以 + 更趋向于(1, 1, 1, 1)(白色)更亮,* 更趋向于(0, 0, 0, 0)(黑色)更暗
    combine src1 + src2
    combine src1 * src2
    
    // -src 为补色
    combine src1 - src2
    // 使用src2的透明通道值在src1和src3之间取插值,插值是反向的,透明度为0的时候取src3,透明度为1的时候取src1
    combine src1 lerp(src2) src3
}
源类型(src) 描述
primary 来自光照计算的颜色或是当它绑定时的顶点颜色
texture 在SetTexture中定义的纹理的颜色
previous 上一次SetTexture的结果
constant 被constantColor定义的颜色
  • 两张纹理图渐变切换

Fixed007.shader

Shader "AShader/FixedShader/Fixed007"{

    Properties
    {
        _LerpScale("插值比例", Range(0, 1)) = 1
        _MainTexture("主纹理", 2D) = ""{}
        _DetailTexture("细节纹理", 2D) = ""{}
    }

    SubShader
    {
        Pass
        {
            SetTexture[_MainTexture]
            {
                constantColor(1, 0, 0, 0)
            }

            SetTexture[_DetailTexture]
            {
                constantColor(1, 1, 1, [_LerpScale])

                combine texture lerp(constant) previous
            }
        }
    }
}

SkinLerp.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SkinLerp : MonoBehaviour 
{
    // 拿到meshRenderer
    private MeshRenderer _meshRenderer;
    // 当前的lerpScale
    private float lerpScale;
    // 目标lerpScale
    private float targetScale;

    private void Awake()
    {
        _meshRenderer = GetComponent<MeshRenderer>();
    }

    private void Update()
    {
        // 取插值
        lerpScale = Mathf.Lerp(lerpScale, targetScale, Time.deltaTime * 2);
        // 0 - 1 之间来回切换
        if (Mathf.Abs(lerpScale - targetScale) < 0.05)
            targetScale = (targetScale == 0) ? 1 : 0;

        // 使用代码控制
        // name : 属性名
        // value : 值
        _meshRenderer.material.SetFloat("_LerpScale", lerpScale);

        // 修改Offset使图片动起来
        _meshRenderer.material.SetTextureOffset("_MainTexture", new Vector2(Time.time, 0));
        _meshRenderer.material.SetTextureOffset("_DetailTexture", new Vector2(-Time.time, 0));

    }
}

4. 表面着色器(Surface Shader)

4.1 CG语言

  • 基本数据类型(所有的数据类型后面都可以加数字,表示多个该类型的,类似Vector)

    • float:32位 浮点数
      • float2:2个浮点数
      • float3:3个浮点数
      • float4:4个浮点数
    • half:16位 浮点数
    • int:32位 整型
    • fixed:12位 定点数,取值范围 [0 - 1] 的小数 或 整数
    • bool
    • sampler2D:纹理对象
    • string
  • 预设的Structure

    • 输入

      变量名 代表内容
      float2 uv_MainTex 纹理贴图UV,模型上每个像素对应到纹理图的坐标,_MainTex为纹理图的名字
      float3 viewDir 像素的视图方向
      float3 worldPos 像素的世界坐标位置
      float4 screenPos 屏幕空间位置,是float4类型,只需用前两个值
      float4 color:COLOR 每个顶点的内插值颜色
    • 输出

      变量名 代表内容
      half3 Albedo 反射率,即颜色纹理RGB
      half3 Normal 法线,即法向量(x, y, z)
      half3 Emission 自发光颜色RGB
      half Specular 镜面反射度
      half Gloss 光泽度
      half Alpha 透明度
  • 语义绑定
    语法:变量名:语义定义,表示这个变量代表着某种指定的值,例:color:COLOR 表示color这个变量是颜色

4.2 结构

  • 表面着色器没有Pass通道
  • 外部是Shader Lab,内部嵌入CG语言
Shader "Ashader/SurfaceShader/Shader001"
{
    Properties
    {
        
    }
    
    SubShader
    {
        // 不需要Pass通道

        // 预编译指令 粉色高亮
        // --------- CG语言开始 ---------
        CGPROGRAM

        // 表面着色器 入口函数名称 兰伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 输入结构体
        struct Input
        {
            float3 viewDir;
        };              // CG语言结构体定义后要加";"

        // 声明外部属性,要求和属性名字相同
        fixed4 _MainColor;

        // 入口函数
        // 参数
        // Input IN : 输入结构体
        // in/out/inout SurfaceOutput o : 常用于输出
        // in:输入 out:输出 inout:既能输入又能输出
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 输出纯色
            o.Albedo = float3(1, 0, 0);
            // 四个数字rgba或xyzw 转三个数字:变量.rgb .gba .xyz .yzw,用到哪个写哪个
            o.Albedo = _MainColor.rgb;
        }
        
        // --------- CG语言结束 ---------
        ENDCG
    }
}

4.3 方法使用

  • 设置纹理图
Shader "AShader/SurfaceShader/Surface002"
{
    Properties
    {
        _MainTexture("主纹理", 2D) = ""{}
        _MainColor("主颜色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        // --------- CG语言开始 ---------
        CGPROGRAM

        // 表面着色器 入口函数名称 兰伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 声明外部属性
        sampler2D _MainTexture;
        fixed4 _MainColor;

        // 输入结构体
        struct Input
        {
            // 主纹理的UV坐标
            float2 uv_MainTexture;
        };

        // 入口函数
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 渲染纹理图,通过UV坐标在纹理贴图中获取当前像素点的颜色值
            // 参数
            // _MainTexture:纹理图
            // IN.uv_MainTexture:纹理图UV
            o.Albedo = tex2D(_MainTexture, IN.uv_MainTexture).rgb;
            // 与颜色进行混合
            o.Albedo *= _MainColor.rgb;
        }

        // --------- CG语言结束 ---------
        ENDCG
    }
}
  • 设置法线贴图
Shader "AShader/SurfaceShader/Surface003"
{
    Properties
    {
        _MainTexture("主纹理", 2D) = ""{}
        _NormalTexture("法线纹理", 2D) = ""{}
    }

    SubShader
    {
        // --------- CG语言开始 ---------
        CGPROGRAM

        // 表面着色器 入口函数名称 兰伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 声明外部属性
        sampler2D _MainTexture;
        sampler2D _NormalTexture;

        // 输入结构体
        struct Input
        {
            // 主纹理的UV坐标
            float2 uv_MainTexture;
            float2 uv_NormalTexture;
        };

        // 入口函数
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 渲染纹理图,通过UV坐标在纹理贴图中获取当前像素点的颜色值
            // 参数
            // _MainTexture:纹理图
            // IN.uv_MainTexture:纹理图UV
            o.Albedo = tex2D(_MainTexture, IN.uv_MainTexture).rgb;
            // 设置法线贴图
            o.Normal = UnpackNormal(tex2D(_NormalTexture, IN.uv_NormalTexture));
        }

        // --------- CG语言结束 ---------
        ENDCG
    }
}
  • 边缘发光
Shader "AShader/SurfaceShader/Surface004"
{
    Properties
    {
        _MainTexture("主纹理", 2D) = ""{}
        _NormalTexture("法线纹理", 2D) = ""{}

        _RimColor("发光颜色", Color) = (1, 1, 1, 1)
        _RimPower("发光强度", Range(1, 10)) = 1
    }

    SubShader
    {
        // --------- CG语言开始 ---------
        CGPROGRAM

        // 表面着色器 入口函数名称 兰伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 声明外部属性
        sampler2D _MainTexture;
        sampler2D _NormalTexture;
        fixed4 _RimColor;
        half _RimPower;

        // 输入结构体
        struct Input
        {
            // 主纹理的UV坐标
            float2 uv_MainTexture;
            float2 uv_NormalTexture;
            // 视图方向
            float3 viewDir;
        };

        // 入口函数
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 渲染纹理图,通过UV坐标在纹理贴图中获取当前像素点的颜色值
            // 参数
            // _MainTexture:纹理图
            // IN.uv_MainTexture:纹理图UV
            o.Albedo = tex2D(_MainTexture, IN.uv_MainTexture).rgb;
            // 设置法线贴图
            o.Normal = UnpackNormal(tex2D(_NormalTexture, IN.uv_NormalTexture));

            // 计算边缘发光系数
            float rim = 1 - saturate(dot(normalize(IN.viewDir), normalize(o.Normal)));
            // 系数直接乘
            //o.Emission =  _RimColor * rim * _RimPower;
            // 系数的光强次幂
            o.Emission = _RimColor * pow(rim, 10 - _RimPower);
        }

        // --------- CG语言结束 ---------
        ENDCG
    }
}

5. 顶点片段着色器(Shader 2.0)

5.1 顶点语义

* model本地坐标
* view观察坐标
* projection投影坐标
语义 代表内容
float4 POSITION 顶点坐标位置
float3 NORMAL 顶点法线向量坐标
float4 TEXCOORD0 第一个UV坐标(用作临时变量,存坐标存颜色等)
float4 TEXCOORD1/2/3... 第二/三/四...个UV坐标
float4 TENGENT 顶点切线向量坐标
float4 COLOR 顶点颜色值

5.2 常用函数库

库名 作用
HLSLSupport.cginc 辅助为跨平台的着色器编译宏和定义
UnityShaderVariables.cginc 常用全局变量
UnityCG.cginc 常用辅助函数
AutoLight.cginc 光、影函数
Lighting.cginc 光照模型相关
TerrainEngine.cginc 地形植被辅助

5.3 结构

Shader "AShader/VFShader/VF001"
{
    Properties
    {
        _MainColor("主颜色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM

            //      着色器类型 入口函数名称
            #pragma vertex vert
            #pragma fragment frag
            // 声明外部属性
            fixed4 _MainColor;

            // 顶点着色器,进行顶点处理
            // 返回值 入口函数名称(参数类型 参数名:语义绑定):返回值语义绑定
            float4 vert(float4 vertexPos:POSITION):SV_POSITION
            {
                // 完成顶点变换,返回投影坐标
                // 5.4之前
                //return mul(UNITY_MATRIX_MVP, vertexPos);
                // 5.4之后
                return UnityObjectToClipPos(vertexPos);
            }

            // 片段着色器,着色
            fixed4 frag():COLOR
            {
                //return fixed4(1, 0, 0, 1);
                return _MainColor;
            }

            ENDCG
        }
    }
}

5.4 案例

  • 彩虹颜色
    将物体的坐标作为颜色值,会呈现彩虹效果
Shader "AShader/VFShader/VF002"
{
    Properties
    {
        _ColorOffset("颜色偏移量", Range(0, 1)) = 0
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            // 声明外部属性变量
            fixed _ColorOffset;
            // 由于return只能返回一个变量,所以当想返回多个值的时候使用结构体
            // 顶点着色器输出的结构体
            struct v2f
            {
                // 0级纹理坐标(临时变量,用于存储顶点着色器算出来的顶点坐标,给片段着色器用)
                float4 col:TEXCOORD0;
                // 屏幕坐标
                float4 pos:SV_POSITION;
            };

            // 顶点着色器入口函数
            v2f vert(float4 vertexPos:POSITION)
            {
                // 定义结构体对象
                v2f content;
                // 执行顶点变换
                content.pos = UnityObjectToClipPos(vertexPos);
                // 获取顶点坐标
                content.col = vertexPos + float4(_ColorOffset, _ColorOffset, _ColorOffset, 0);

                return content;
            }

            // 片段着色器入口函数
            float4 frag(v2f content):COLOR
            {
                // 将顶点坐标当成颜色值输出
                return content.col;
            }

            ENDCG
        }
    }
}
  • 设定漫反射
Shader "AShader/VFShader/VF003"
{
    Properties
    {
        _MainColor("漫反射颜色", COLOR) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            // 引入库
            #include "UnityCG.cginc"

            // 声明外部变量
            fixed4 _MainColor;
            // 声明内置变量
            fixed4 _LightColor0;

            // 顶点着色器输入结构体
            struct appdata
            {
                // 顶点坐标
                float4 vertexPos:POSITION;
                // 顶点法线
                float3 vertexNormal:NORMAL;
            };

            // 顶点着色器输出结构体
            struct v2f
            {
                // 屏幕坐标
                float4 pos:SV_POSITION;
                // 屏幕法线
                float3 normal:NORMAL;
            };

            // 顶点着色器入口函数
            v2f vert(appdata data)
            {
                v2f content;
                content.pos = UnityObjectToClipPos(data.vertexPos);
                // 计算法线
                content.normal = mul(float4(data.vertexNormal, 1), unity_WorldToObject).xyz;
                return content;
            }

            // 片段着色器入口函数
            fixed4 frag(v2f content):COLOR
            {
                // 求法线的标准化向量
                float3 lightNormal = normalize(content.normal);
                // 求入射光的标准化向量
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                // 计算漫反射颜色
                float3 diffuseColor = _MainColor * _LightColor0 * -min(0, dot(lightNormal, lightDir));

                return fixed4(diffuseColor, 1) + UNITY_LIGHTMODEL_AMBIENT;
            }


            ENDCG
        }
    }
}
  • 技能释放范围
Shader "SkillShader/Skill1"
{
    Properties
    {
        // 技能释放原点
        _BossPosition("BossPosition", Vector) = (1, 1, 1, 1)
        // 透明通道值
        _Alpha("BossSkillAlpha", Range(0, 1)) = 0
        // 用于代码控制显示范围的值
        _Dis("SkillDis", Range(0, 10)) = 0
    }

    SubShader
    {
        Pass
        {
            // 开启透明混合
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            float4 _BossPosition;
            float _Alpha;
            float _Dis;

            struct v2f
            {
                float4 vertPos:TEXCOORD0;
                float4 pos:SV_POSITION;
            };

            v2f vert(float4 vertexPos:POSITION)
            {
                v2f content;
                content.pos = UnityObjectToClipPos(vertexPos);
                content.vertPos = vertexPos;

                return content;
            }

            float4 frag(v2f content):COLOR
            {
                // 根据传入坐标计算需要渲染的地方
                if (distance(content.vertPos.z, _BossPosition.z) < _Dis && abs(distance(content.vertPos.x, _BossPosition.x)) < 1)
                {
                    return float4(1, 0, 0, _Alpha);
                }
                else
                {
                    return float4(1, 0, 0, 0);
                }
            }

            ENDCG
        }
    }
}

6. 小知识点

  • 法线贴图:法线决定光的反射方向,法线是一个向量,向量是vector3,颜色的rgb也是vector3,所以法线贴图使用颜色来代表向量(例:红色(1, 0, 0)代表右)
  • 边缘发光公式:
    RimColor = EmissionColor * (1 - clamp01(dot(normalize(normal), normalize(viewDir))))

附:Shader词典

单词 描述 单词 描述 单词 描述
Shader 着色器 Properties 属性 SubShader 子着色器
Pass 通道 Color 颜色 Cull 剔除
ZTest 深度测试 SeparateSpecular 镜面反射 Diffuse 漫反射
Ambient 环境光 Shininess 光泽度 Specular 高光
Emission 自发光 Combine 结合 Primary 基本的
Previous 之前的 Constant 恒定的 Gloss 光泽度
Vertex 顶点 Fragment 片段
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容