《Shader 入门精要》之环境光+漫反射+高光反射

UnityCG.cginc 部分结构体

struct appdata_base {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct appdata_tan {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct appdata_full {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    float4 texcoord1 : TEXCOORD1;
    float4 texcoord2 : TEXCOORD2;
    float4 texcoord3 : TEXCOORD3;
    fixed4 color : COLOR;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

可视化

测试


Shader "Unlit/01TestShader"
{
    Properties
    {

    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 color:COLOR0;
            };

            v2f vert(appdata_base i) 
            {
                v2f o;
                o.position  = UnityObjectToClipPos(i.vertex); // 模型坐标转换到裁剪坐标
                o.color = fixed3(0.5,1,1); // 每个顶点都是蓝色的
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {   
                return fixed4(i.color,1);              
            }

            ENDCG
        }
    }
}

运行结果

UV 可视化


Shader "Unlit/01TestShader"
{
    Properties
    {

    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 color:COLOR0;
            };

            v2f vert(appdata_base i) 
            {
                v2f o;
                o.position  = UnityObjectToClipPos(i.vertex);
                o.color = fixed3(i.texcoord.xy,0);
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {   // r,b 取 uv 坐标,如果超过了 [0,1],那么加蓝调。
                fixed3 c = frac(i.color); // 取小数部分
                if(any(saturate(i.color.xy)-i.color.xy)) // saturate,限制在 [0,1] 之间,any,全部为 0 ,返回 false
                {
                    c.b = 0.5;
                    // return fixed4(0,0,1,1); // 超过了 [0,1],直接变成蓝色。
                }
                return fixed4(c,1);              
            }

            ENDCG
        }
    }
}
运行结果

法线可视化


Shader "Unlit/01TestShader"
{
    Properties
    {

    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 color:COLOR0;
            };

            v2f vert(appdata_full  i) 
            {
                v2f o;
                o.position  = UnityObjectToClipPos(i.vertex);
                o.color = i.normal * 0.5 + 0.5; // 把法线映射到 [0,1] 的范围
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {   
                return fixed4(i.color,1);
            }

            ENDCG
        }
    }
}
运行效果

切线可视化


Shader "Unlit/01TestShader"
{
    Properties
    {

    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 color:COLOR0;
            };

            v2f vert(appdata_full  i) 
            {
                v2f o;
                o.position  = UnityObjectToClipPos(i.vertex);
                o.color = i.tangent * 0.5 + 0.5; // 把切线映射到 [0,1] 的范围
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {   
                return fixed4(i.color,1);
            }

            ENDCG
        }
    }
}

运行结果

副切线可视化


Shader "Unlit/01TestShader"
{
    Properties
    {

    }
    SubShader
    {
        Pass
        {
            Fog { Mode Off }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

           struct appdata {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float4 tangent : TANGENT;
            };

            struct v2f {
            float4 pos : SV_POSITION;
            float3 color : COLOR;
            };

            v2f vert(appdata_full  i) 
            {
                v2f o;
                o.pos  = UnityObjectToClipPos(i.vertex);
                float3 bitangent = cross( i.normal, i.tangent.xyz ) * i.tangent.w; // w 为 1 或者 -1,用来确定副切线的方向
                o.color.xyz = bitangent * 0.5 + 0.5; // 把副切线映射到 [0,1] 的范围
                // o.color.xyz = fixed3(-1,-1,-1); 

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {   
                return fixed4(i.color,1);
            }

            ENDCG
        }
    }
}

运行结果

漫反射模型

逐顶点

Shader "MyShader/MyDiffuseShader"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"
            fixed4 _Diffuse;

            struct appdate
            {
                float4 position:POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 color:COLOR0; 
            };

            v2f vert (appdate i)
            {
                v2f o;
                o.position = UnityObjectToClipPos(i.position);

                // 环境光
                fixed4 ambient = UNITY_LIGHTMODEL_AMBIENT;

                // 漫反射光源
                float3 normal = normalize(mul(i.normal,(float3x3)unity_WorldToObject)); // 计算法线,这种方式避免法线直接通过矩阵变换之后与表面不垂直的情况。
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz); // 光照方向
                o.color = ambient + _LightColor0 * _Diffuse * saturate(dot(normal,lightDirection)); // 颜色 * 就是对应位置相乘
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.color,1);
            }
            ENDCG
        }
    }
}
运行结果

最后有个颜色相乘,其实就是对应位置相乘,比如说 Diffuse 为 (1,0,0),然后直射光颜色为 (0,1,0)。那么结果就是 (0,0,0),显示出来也就是黑色的。而且不能随着光源的远近有不同亮度的变化,并且应该是被完全遮挡的地方也可能会很亮,比如嘴巴那边,光是从背照过来的。

逐像素

Shader "MyShader/MyDiffuseShader"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"
            fixed4 _Diffuse;

            struct appdate
            {
                float4 position:POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 normal:COLOR0; 
            };

            v2f vert (appdate i)
            {
                v2f o;
                o.position = UnityObjectToClipPos(i.position);
                o.normal = normalize(mul(i.normal,(float3x3)unity_WorldToObject)); // 计算法线
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz); // 光照的方向
                fixed3 lightColor = _LightColor0.rgb; // 光源的颜色
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; // 计算环境光
                fixed3 color = ambient + _Diffuse.rgb * lightColor * saturate(dot(i.normal,lightDirection)); // 计算最终的颜色
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}
运行结果

半兰伯特模型

Shader "MyShader/MyDiffuseShaderHalfLambert"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
        _HalfLambert("HalfLambert",float) = 0
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"
            fixed4 _Diffuse;
            float _HalfLambert;

            struct appdate
            {
                float4 position:POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float4 position:SV_POSITION;
                fixed3 normal:COLOR0; 
            };

            v2f vert (appdate i)
            {
                v2f o;
                o.position = UnityObjectToClipPos(i.position);
                o.normal = normalize(mul(i.normal,(float3x3)unity_WorldToObject)); // 计算法线
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz); // 光照的方向
                fixed3 lightColor = _LightColor0.rgb; // 光源的颜色
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; // 计算环境光
                fixed3 color = ambient + _Diffuse.rgb * lightColor *(_HalfLambert * dot(i.normal,lightDirection) + _HalfLambert); // 使用半兰伯特模型模型
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}

半波兰特模型没有物理依据,只是单纯的视觉增强效果,将原来光线方向的单位向量在法线上的投影小于零就使用 0,改成将 [-1,1] 投影到 [0,1] 的范围。

三种漫反射模型对比

  • 最左:逐顶点,也就是计算每个顶点的值,然后在每个三角面进行插值,好处是顶点少的话,计算量少,坏处是顶点少的话过度比较生硬。
  • 第二个:逐像素,计算每一个像素的颜色,相较于逐顶点,过度会更顺滑,代价是计算量更大一点。但如果模型足够细腻,顶点个数足够多,那从效果和计算量上来说,两者几乎一致。
  • 第三个,两个系数都是 0.5 的半兰伯特模型,背部也能看到颜色了。
  • 第四个,两个系数都是 0.25 的半兰伯特模型,要更亮了一些。


    渲染结果对比

高光模型

高光逐顶点

Shader "Unlit/SpecularVertexLevelMat"
{
    Properties
    {   
        _DiffuseColor("DiffuseColor",Color) = (1,1,1,1)
        _Spacular("Spacular",Color) = (1,1,1,1)
        _Gloss("Gloss",float) = 0
    }
    SubShader
    {
        Tags { "LightMode"="ForwardBase" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"

            fixed4 _DiffuseColor;
            fixed4 _Spacular;
            float _Gloss;

            struct appdata
            {
                float4 vertex : POSITION;
                fixed3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 color:COLOR0;
            };


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

                // 环境光
                fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.xyz;

                // 漫反射光
                float3 normal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); // 计算法线
                fixed3 lightColor = _LightColor0.rgb; // 光源的颜色
                float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); // 光照的方向,是从模型出发的,也就是跟场景中看到的光照方向相反
                fixed3 diffuseColor = _DiffuseColor * lightColor * saturate(dot(normal,worldLightDir));

                // 计算高光
                float3 reflectDir = normalize(reflect(-worldLightDir,normal)); // 计算光的反射方向
                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz); // 计算观察的方向
                fixed3 spacularColor = _Spacular * lightColor * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
                o.color = ambientColor + diffuseColor + spacularColor;
                // o.color = reflectDir;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.color,1);
            }
            ENDCG
        }
    }
}
运行结果

高光部分会跟随视角的变换改变强度和位置。_Gloss 越大,高光越小。观察点的位置不是摄像机的位置,而是我们在 Scene 人眼的位置。

高光逐像素

Shader "Unlit/SpecularVertexLevelMat"
{
    Properties
    {   
        _DiffuseColor("DiffuseColor",Color) = (1,1,1,1)
        _Spacular("Spacular",Color) = (1,1,1,1)
        _Gloss("Gloss",float) = 0
    }
    SubShader
    {
        Tags { "LightMode"="ForwardBase" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"

            fixed4 _DiffuseColor;
            fixed4 _Spacular;
            float _Gloss;

            struct appdata
            {
                float4 vertex : POSITION;
                fixed3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); // 计算法线
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 环境光
                fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.xyz;

                // 漫反射光
                float3 normal = i.worldNormal; // 计算法线
                fixed3 lightColor = _LightColor0.rgb; // 光源的颜色
                float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); // 光照的方向,是从模型出发的,也就是跟场景中看到的光照方向相反
                fixed3 diffuseColor = _DiffuseColor * lightColor * saturate(dot(normal,worldLightDir));

                // 计算高光
                float3 reflectDir = normalize(reflect(-worldLightDir,normal)); // 计算光的反射方向
                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); // 计算观察的方向
                fixed3 spacularColor = _Spacular * lightColor * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
                fixed3 color = ambientColor + diffuseColor + spacularColor;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}

运行结果

运行结果

逐像素 BlinnPhong 模型

Shader "MyShader/BlinnPhongMat"
{
    Properties
    {   
        _DiffuseColor("DiffuseColor",Color) = (1,1,1,1)
        _Spacular("Spacular",Color) = (1,1,1,1)
        _Gloss("Gloss",float) = 0
    }
    SubShader
    {
        Tags { "LightMode"="ForwardBase" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"

            fixed4 _DiffuseColor;
            fixed4 _Spacular;
            float _Gloss;

            struct appdata
            {
                float4 vertex : POSITION;
                fixed3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); // 计算法线
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 环境光
                fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.xyz;

                // 漫反射光
                float3 normal = i.worldNormal; // 计算法线
                fixed3 lightColor = _LightColor0.rgb; // 光源的颜色
                float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); // 光照的方向,是从模型出发的,也就是跟场景中看到的光照方向相反
                fixed3 diffuseColor = _DiffuseColor * lightColor * saturate(dot(normal,worldLightDir));

                // 使用 BlinnPhone 模型,因为计算简单很多
                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); // 计算观察的方向
                float3 h_normal = normalize(viewDir.xyz + worldLightDir.xyz); // 计算视角方向和光源方向的中间方向,用它和法线的夹角来确定光强
                fixed3 spacularColor = _Spacular * lightColor * pow(max(0,dot(normal,h_normal)),_Gloss);
                fixed3 color = ambientColor + diffuseColor + spacularColor;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}
BlinnPhong 模型

从下面的对比图可以看到相同的 _Gloss ,BlinnPhong 的光圈要更大一点,BlinnPhong 也是一种经验模型,因为可以简化求反射角的计算,而且可能在某些场景更加的真实。

左:BlinnPhong 右:基本光照模型

使用 Unity 里面自带的函数

// File: UnityCG.cginc
// Transforms direction from object to world space
inline float3 UnityObjectToWorldDir( in float3 dir )
{
    return normalize(mul((float3x3)unity_ObjectToWorld, dir));
}

// Transforms direction from world to object space
inline float3 UnityWorldToObjectDir( in float3 dir )
{
    return normalize(mul((float3x3)unity_WorldToObject, dir));
}

// Transforms normal from object to world space
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
    return UnityObjectToWorldDir(norm);
#else
    // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
    return normalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}

// Computes world space view direction, from object space position
inline float3 UnityWorldSpaceViewDir( in float3 worldPos )
{
    return _WorldSpaceCameraPos.xyz - worldPos;
}

// Computes world space view direction, from object space position
// *Legacy* Please use UnityWorldSpaceViewDir instead
inline float3 WorldSpaceViewDir( in float4 localPos ) // 如果这里的 w 为 0,那么跟直接调用 UnityWorldSpaceViewDir 是一样的
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceViewDir(worldPos);
}

修改之后的 BlinnPhone 模型:

Shader "MyShader/BlinnPhongMat"
{
    Properties
    {   
        _DiffuseColor("DiffuseColor",Color) = (1,1,1,1)
        _Spacular("Spacular",Color) = (1,1,1,1)
        _Gloss("Gloss",float) = 0
    }
    SubShader
    {
        Tags { "LightMode"="ForwardBase" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityShaderVariables.cginc"
            #include "Lighting.cginc"

            fixed4 _DiffuseColor;
            fixed4 _Spacular;
            float _Gloss;

            struct appdata
            {
                float4 vertex : POSITION;
                fixed3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal); // 使用 UnityObjectToWorldNormal 计算法线
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 环境光
                fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.xyz;

                // 漫反射光
                float3 normal = i.worldNormal; 
                fixed3 lightColor = _LightColor0.rgb; 
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // 使用 UnityWorldSpaceLightDir获取光照的方向
                fixed3 diffuseColor = _DiffuseColor * lightColor * saturate(dot(normal,worldLightDir));

                // 使用 BlinnPhone 模型,因为计算简单很多
                float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // 使用 UnityWorldSpaceViewDir获取观察的方向
                float3 h_normal = normalize(viewDir.xyz + worldLightDir.xyz); 
                fixed3 spacularColor = _Spacular * lightColor * pow(max(0,dot(normal,h_normal)),_Gloss);
                fixed3 color = ambientColor + diffuseColor + spacularColor;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352