Unity强化篇(九) —— Shader Graph简介(一)

版本记录

版本号 时间
V1.0 2019.12.18 星期三

前言

Unity是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。Unity类似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的图型化开发环境为首要方式的软件。其编辑器运行在Windows 和Mac OS X下,可发布游戏至WindowsMacWiiiPhoneWebGL(需要HTML5)、Windows phone 8和Android平台。也可以利用Unity web player插件发布网页游戏,支持Mac和Windows的网页浏览。它的网页播放器也被Mac 所支持。网页游戏 坦克英雄和手机游戏王者荣耀都是基于它的开发。感兴趣的看下面几篇文章。
1. Unity强化篇(一) —— 如何使用Vuforia制作AR游戏(一)
2. Unity强化篇(二) —— 适用于Unity的HTC Vive教程(一)
3. Unity强化篇(三) —— 适用于Unity的HTC Vive教程(二)
4. Unity强化篇(四) —— Unity 和 Ethereum(一)
5. Unity强化篇(五) —— Unity 和 Ethereum(二)
6. Unity强化篇(六) —— 使用Unity和Photon进行多人游戏简介(一)
7. Unity强化篇(七) —— Unity Sprite Shapes简介(一)
8. Unity强化篇(八) —— 使用Unity运行时网格操作(一)

开始

首先看下主要内容

着色器(shader)是一个小型程序,包含用于GPU的指令。 它们描述了如何计算特定材料的屏幕颜色。 尽管Unity提供了标准着色器,但有时您可能需要做出超越现成的着色器所能提供的效果。 从历史上看,这需要一种特殊的着色语言,例如Cg

下面看写作环境

Unity 2019.2, Unity

着色器是一个小型程序,包含用于GPU的指令。 它们描述了如何计算特定材料的屏幕颜色。

尽管Unity提供了标准着色器,但有时您可能需要做出超越现成的着色器所能提供的效果。

从历史上看,这需要一种特殊的着色语言,例如CgHLSL,其约定与典型的游戏脚本有所不同。 对于许多人来说,仅因为涉及额外的学习曲线,着色器编写是游戏开发中被忽略的领域。

Unity引入了Shader Graph,以使您可以更轻松地编写着色器,而几乎不需要编写代码。 最重要的是,Shader Graph使得通过可视化的交互式界面轻松上手。

在本教程中,您将立即在Unity中创建第一个shader graph

本教程使用Unity 2019.1或更高版本。 您可以在此处here获取您的Unity版本。

在Unity中打开Intro to Shader Graph Starter入门项目。

“项目”Project窗口中的RW文件夹的组织方式如下:

  • Fonts - 字体:场景中使用的字体。
  • Materials - 材料:场景材料。
  • Models - 模型:游戏零件和背景的3D网格。
  • PostFX:场景渲染的后处理效果。
  • Prefabs - 预制件:各种预制组件。
  • Scenes - 场景:游戏场景。
  • Scripts - 脚本:自定义脚本游戏逻辑。
  • Shaders - 着色器:为本教程创建的着色器图。
  • Sprites - Sprites:用作说明一部分的Sprite。
  • Textures - 纹理:游戏片段和背景的纹理贴图。

现在,从Scenes文件夹中加载名为TangramPuzzle的场景。

这是一个名为七巧板的简单游戏,它起源于1800年代的中国。 目标是将七个平面几何形状重新排列为风格化的象形图或轮廓。

在编辑器中进入Play模式以测试演示游戏。

您可以单击并拖动形状。 使用光标键旋转片段。 旋转并移动碎片,以免重叠。

您能弄清楚如何将这七个形状转变为这些图案吗?

好的,该游戏在技术上是可行的,但它不会为您提供有关所选游戏作品的任何视觉反馈。

如果您可以在鼠标接触时让游戏发光,该怎么办? 这可能会改善用户界面。

这是炫耀Shader Graph的绝佳机会!


Checking Pipeline Settings For Shader Graph

Shader Graph仅适用于相对较新的可脚本化渲染管线(Scriptable Render Pipeline),即“高清晰度”渲染管线(High-Definition Render Pipeline)或“轻量级”渲染管线(Lightweight Render Pipeline)

创建用于Shader Graph的新项目时,请确保选择正确的模板。

您的示例项目已配置为使用“轻量级渲染管道”(Lightweight Render Pipeline)。 首先,在PackageManager中,选择Window►PackageManager,确认已安装Lightweight RPShaderGraph软件包。

然后,从可用版本中进行选择,并在必要时使用Update to按钮。 最新的经过验证的版本通常是最安全的选择。

更新软件包后,请在Edit ► Project Settings下再次检查管道设置是否正确。

Graphics选项卡中,Scriptable Render Pipeline Settings应显示为LWRP-HighQuality。 这会将您的项目设置为使用“轻量级渲染管道”的最高默认设置。

确认您正在使用脚本编写的渲染管道资源(Scriptable Render Pipeline )之一后,关闭此窗口。


Creating a PBR Graph

材质和着色器始终一起工作以在屏幕上渲染3d网格。 因此,在构建着色器之前,还需要一种材料。

首先,使用“项目”视图中的Create按钮在RW / Materials文件夹中生成新材料。 选择Create ► Material,然后将其重命名为Glow_Mat

然后,在RW / Shaders文件夹中,通过选择Create ► Shader ► PBR Graph来创建PBR Graph。 这是一个着色器图,支持基于物理的渲染或PBR

将其命名为HighlightShaderGraph

Glow_Mat材质当前为LightweightRenderPipeline使用默认着色器,称为LightweightRenderPipeline / Lit

更改它以使用刚创建的新着色器图。 选择Glow_Mat后,单击检查器顶部的Shader下拉菜单,然后选择Shader Graphs ► HighlightShaderGraph

Glow_Mat材质将变为稍微更浅的灰色阴影,但否则保持相当单调。 不用担心 您会尽快补救。

现在,双击HighlightShaderGraph资产或在检查器中单击Open Shader Editor。 这将打开Shader Graph窗口。

您应该熟悉此界面的主要部分:

  • 主工作区(main workspace)是此深灰色区域,您将在其中存储图形操作。您可以在工作空间上单击鼠标右键以查看上下文菜单。
  • 节点(node)是图形的单个单位。每个节点根据其端口保留输入,输出或操作。节点使用边缘彼此连接。
  • 主节点(Master node)是图形的最终输出节点。在此示例中,您使用的是基于物理的渲染变体,也称为PBR主节点。您可能会从Unity的标准着色器中识别出多个属性,例如反照率,法线,发射和金属(Albedo, Normal, Emission and Metallic)
  • Blackboard可以将图形的某些部分显示给检查器。这允许用户自定义某些设置,而无需直接编辑图形。
  • 主预览(Main Preview)以交互方式显示球体上当前着色器的输出。

通过将各个节点连接在一起,您可以创建一个着色器图(shader graph),Unity将该着色器图编译并发送到GPU


Creating a Color Node

首先,给您的着色器一些基础颜色。这是通过将颜色节点输入PBR主节点的Albedo组件来完成的。右键单击工作区,从上下文菜单中选择Create Node ► Input ► Basic ► Color,以创建第一个节点。

请注意,Create Node菜单中有数百个节点! 乍一看似乎有些让人不知所措,但是您很快就会熟悉最常用的那些。

接下来,使用其标题栏在工作空间周围拖动节点。 然后,将其放在PBR主节点左侧的某个位置。

Color节点允许您定义一种颜色。 单击色片,然后选择漂亮的红色,例如R:128,G:5,B:5

要将颜色输出到PBR Master node,请将Out端口拖到Albedo端口中,该端口代表着色器的基本颜色。

将节点与边缘连接后,您应该会看到Main Preview球体变为红色。

成功! 在着色器编写中,制作一个简单的纯色着色器等同于编码Hello,world!

尽管您可能没有意识到,但是您创建了第一个自定义着色器!


Navigating the Interface

尽管图形中只有几个节点,但是现在是习惯Shader Graph界面的好时机。

拖动节点,注意边缘在Color的输出端口和PBR Master的输入端口之间保持连接状态。

节点可以包含不同类型的数据。 创建包含颜色输入的节点时,还可以通过选择Create Node ► Input ► Basic ► Integer来创建表示单个数字的节点。 您实际上不会对这个新节点做任何事情,仅用于说明目的。

Integer Out端口连接到PBR MasterAlpha端口。

您的图形仍然很小,但是现在您有足够的节点来尝试一些热键。 选择几个节点,然后按以下快捷键:

  • F:框住选定的一个或多个节点。
  • A:构图整个图。

您还可以使用窗口顶部的按钮来切换Main PreviewBlackboardShow in Project按钮将帮助在Project窗口中找到当前着色器图形。

导航完图形后,请进行一些清理。 您仅需要Color节点和PBR Master节点。

右键单击IntegerMaster节点之间的连接,然后选择Delete。 这样就可以从图中断开节点的连接。

同样,您可以完全删除Integer节点。 右键单击该节点,然后选择Delete

完成后,单击界面左上方的Save Asset按钮。 Unity将保存所有更改,然后将编译并激活着色器。 每当您要在编辑器中查看最新更改时,都需要执行此步骤。

现在,返回到Project窗口,然后选择Glow_Mat材质。

由于着色器正在传播到材质,因此Inspector预览中的球体应显示为红色。

现在,将Glow_Mat材质拖到Scene窗口中的七巧板块之一上。

如您所料,材质和着色器使网格变成了漂亮的均匀红色。


Adding a Glow Effect

如果要使Glow_Mat材质具有更生动的发光效果,请再次编辑着色器图。

目前,您可以将Color的输出输入到PBR MasterAlbedo中。

您也可以将另一条边从Out拖到Emission。 现在,相同的颜色已被使用两次:一次用于基础颜色,另一次用于发光颜色。

输出端口可以有多个边,但是输入端口只能有一个。

现在,将Color节点中的Mode下拉列表切换为HDR。 这可以利用色彩的高动态范围。

接下来,编辑色卡。 在HDR模式下,您会获得Intensity的额外选项。 单击底部样本中的+1两次,或将滑块拖动到约2.5。 然后,保存您的更改并返回到编辑器。

在编辑器中,您的游戏作品会发出明亮的红橙色。 场景中的后处理已设置,并增强了高动态范围颜色。

现在,在“层次结构”中选择PostProcessing游戏对象。 发光源于Bloom效果。

接下来,打开Bloom参数,并调整Intensity或发光的强度,以及Threshold或“截止”以开始发光。 本示例分别显示值为3和2。

哇,真是太流行了!


Making the Highlighter Script

您不希望游戏作品一直发光。 您只想根据鼠标位置启用它。

当鼠标悬停在游戏上时,您将切换到Glow_Mat材料。 否则,游戏将显示默认的Wood_Mat材料。

首先,在RW/Scripts中创建一个名为Highlighter的新C#脚本。 这将帮助您在运行时在两种材料之间交换。 将脚本中的所有行替换为以下内容:

using UnityEngine;

// 1
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(Collider))]
public class Highlighter : MonoBehaviour
{
    // 2
    // reference to MeshRenderer component
    private MeshRenderer meshRenderer;

    [SerializeField]
    private Material originalMaterial;

    [SerializeField]
    private Material highlightedMaterial;

    void Start()
    {
        // 3
        // cache a reference to the MeshRenderer
        meshRenderer = GetComponent<MeshRenderer>();

        // 4
        // use non-highlighted material by default
        EnableHighlight(false);
    }

    // toggle betweeen the original and highlighted materials
    public void EnableHighlight(bool onOff)
    {
        // 5
        if (meshRenderer != null && originalMaterial != null && 
            highlightedMaterial != null)
        {
            // 6
            meshRenderer.material = onOff ? highlightedMaterial : originalMaterial;
        }
    }
}

让我们仔细看一下脚本:

  • 1) 该脚本只能应用于包含MeshRendererCollider组件的对象。这是通过在脚本顶部添加[RequireComponent]属性来控制的。
  • 2) 这些是对MeshRendereroriginalMaterialHighlightedMaterial的引用。使用[SerializeField]属性标记材料,使它们可以从检查器中分配。
  • 3) 在Start中,您将自动用GetComponent填充MeshRenderer
  • 4) 您调用EnableHighlight(false)。这样可以确保默认情况下显示未突出显示的材料。下方显示的是名为EnableHighlight的公共方法,用于切换渲染器的材质。它需要一个名为onOff的布尔参数来确定突出显示的启用状态。
  • 5) 您谨防任何NullReference错误
  • 6) 使用三元运算符来节省空间。

Adding Mouse Events

因为您将把它应用于附加了MeshColliders的游戏,所以可以利用内置的OnMouseOverOnMouseExit方法。在EnableHighlight方法之后添加以下内容:

    private void OnMouseOver()
    {
        EnableHighlight(true);
    }

    private void OnMouseExit()
    {
        EnableHighlight(false);
    }

当鼠标悬停在游戏上时,它将调用EnableHighlight(true)。 同样,当鼠标退出Collider时,它将调用EnableHighlight(false)

就这些!

保存脚本。


Highlighting the Game Piece

如果将Glow_Mat应用于本教程前面部分中的任何作品,则需要将所有游戏作品切换回编辑器中的Wood_Mat材质。 您将使用Highlighter在运行时启用发光。

首先,在Tangram变换中选择代表单个游戏棋子形状的七个对象。 然后,一次将Highlighter脚本添加到所有脚本中。

接下来,在Original Material字段中,拖动Wood_Mat材质。 然后,在Highlighted Material字段中,拖动Glow_Mat材质。 最后,进入Play模式并检查您的工作。

不错! 将鼠标悬停在七巧板片上时,它会发出明亮的红色。 将鼠标移开,它会返回到其原始的木制状态。

您仍然可以正常玩游戏,但是现在突出显示效果增加了一点视觉趣味,吸引了用户的注意力。


Using Texture Nodes

当前,简单的着色器是明亮的纯红色。您将要修改着色器,以免丢失原始的木材纹理。相反,您将使高光显示为围绕表面细节的发光边缘。

首先,双击它或在检查器中选择Open Shader Editor来编辑HighlightShaderGraph

删除Color节点,右键单击它,然后选择Delete。您将从头开始创建所有内容。

您将使用Sample Texture 2D节点插入纹理而不是单色。

右键单击从上下文菜单创建节点,然后选择Create Node或使用空格键热键。选择Input ► Texture ► Sample Texture 2D

Sample Texture 2D节点从纹理资源读取颜色信息,然后输出其RGB值。

Texture输入端口中选择一个纹理。单击空白字段旁边的点以打开文件浏览器。

选择WoodAlbedo纹理资源。

Sample Texture 2DRGBA输出端口连接到PBR Master Albedo端口。

瞧! 现在,您的预览球体将显示表面上的木材纹理。

如果添加法线贴图(normal map),则可以添加更多表面细节。 首先,通过选择Create Node ► Input ► Texture ► Sample Texture 2D来创建另一个Sample Texture 2D节点。

在“纹理”输入端口中选择WoodNormal纹理。

Type下拉菜单从Default调整为Normal

RGBA值输出到PBR Master设备的Normal端口。

现在,Main Preview应该看起来更粗糙。法线贴图伪造表面上的小凹痕和凹痕。这有助于出现木纹外观。

注意:每个端口的数据类型在端口旁边的括号中列出。 (T2)表示该端口与二维纹理兼容,而(4)表示该端口使用Vector4。根据上下文,Shader Graph足够聪明,可以忽略额外的浮点值。


Adding a Fresnel Effect

现在您已经有了基本的纹理和法线贴图,可以替代以前的纯红色,让我们使用另一种方法添加高光效果。

可以使发光仅限于边缘,而不是使整个对象均匀发光。这可以通过菲涅耳效应(Fresnel effect)来实现。

右键单击或使用空格键热键创建一个新节点,然后选择Create Node ► Math ► Vector ► Fresnel Effect

这个新节点显示了一个球体,该球体的圆周上有一个白色的发光环。您可以使用Power输入端口调整其光晕宽度。单击并将X标签拖动到该字段的左侧,或输入特定的数字。

较大的值会使光晕非常薄,而较小的值会使光晕非常宽。您可以将值4用作更薄的边缘发光。

为了将此光晕传递给您的材料,请将Fresnel Effect输出连接到PBR Master控的Emission

现在,您的MainPreview显示了一个木制球体,该球体带有菲涅耳效果产生的明亮的白色光晕。

注意:菲涅耳效应是以法国物理学家奥古斯丁·让·菲涅尔命名的。 他观察到,当观察者接近接近掠过的角度时,光线会使表面非常明亮且像镜子一样。

您可以在厨房的桌子上尝试。 您正在使用Unity的这种现象版本来使几何图形的边缘发光。


Multiplying by Color

向发光的边缘添加颜色就像进行一些基本的颜色数学运算一样容易。

创建一个新的颜色节点,该节点将指定发光环的颜色。 使用右键
或空格键打开上下文菜单,然后选择Create node ► Input ► Basic ► Color。 将色彩模式切换为HDR

选择一种颜色来代表您的突出显示颜色。 例如,在此处选择漂亮的亮绿色,即R:5,G:255,B:5

将强度增加到3.5

您无法将新颜色插入菲涅耳效果,因为它没有颜色输入。 相反,您需要将菲涅耳输出与颜色节点的输出结合起来。 这是通过使用Multiply节点来实现的。

右键单击创建一个Multiply节点,然后选择Create node ► Math ► Basic ► Multiply

删除菲涅耳效果和PBR Master之间的现有边缘。 而是将Fresnel Effect Out连接到Multiply节点的A输入。

Color节点的Out连接到Multiply节点的B输入。

最后,将Multiply Out端口连接到PBR Master端口的Emission。 瞧! 您可以看到Main Preview球周围的鲜绿色HDR颜色。

请记住,您可以使用菲涅耳效果增强或缩小光晕。 较小的1.5值可使您发出泛绿色的光。

对于此示例游戏,介于45之间的值将很好地工作,但是可以随意尝试使用自己的值。

将着色器图形保存起来,然后将其返回到编辑器,您可以随时查看HighlightShaderGraph

进入Play模式。

当您将鼠标悬停在游戏板上时,它会保留其原始的木质纹理。 但是,它的边缘周围现在发出鲜绿色的光。 再一次,您现在就可以玩游戏了,只有更加微妙的亮点。


Adding Blackboard Properites

如果要修改发光效果的外观,则必须返回到Shader Graph编辑器窗口并进行那些更改。 例如,您可能想使用Fresnel Effect Power来增大或缩小明亮的光环。

如果要测试各种更改,这不是很方便。 幸运的是,Shader Graph具有属性的概念。

您可以在Inspector中公开显示部分图形,以便您可以交互方式进行小的更改。 这是通过使用Blackboard界面完成的。

返回到Shader Graph并确保Blackboard可见。 如果隐藏,则切换右上角的Blackboard按钮。

1. Adding Base Texture and Normal Map properties

现在,您将公开基础纹理和法线贴图,以便可以从Inspector访问。

单击Blackboard右上方的+图标。 从下拉列表中选择Texture 2D。 条目应出现在Blackboard上。 重命名为BaseTexture

确保已检查exposed。 如果您选择公开某个属性,则该属性是公开的,并且可以在检查器中使用。

要将属性添加到图形,只需将其拖动到标签旁边,然后将其放入工作区即可。 将其放在Sample Texture 2D节点左侧的某个位置。

BaseTexture端口连接到插入AlbedoSampleTexture 2D上的Texture输入端口。 这将替换先前的设置值。

同样对法线贴图(Normal Map)重复相同的过程。 单击+图标,然后创建一个新的Texture 2D。 重命名法线贴图(Normal Map)

将其拖到工作区中,然后将其插入到法线贴图的Sample Texture 2D中。

单击Save Asset,然后返回到主编辑器窗口。

选择Glow_Mat材质,然后不使用检查器中的两个附加字段:Base Texture and Normal Map

因为它们当前没有设置纹理,所以预览窗口在灰色球体上显示绿色高光。

分别为BaseTextureNormalMap选择WoodAlbedoWoodNormal纹理。

现在,木质纹理可以正确显示在发光边缘的下方。

Exposed属性允许用户直接将数据输入到着色器中,而无需编辑着色器图本身。 自己尝试选择不同的基本纹理和法线贴图。

2. Adding Glow Size and Glow Color properties

现在,您还将在Blackboard上显示其他类型的属性。 例如,允许用户调整菲涅耳效应功率值将很有用。

单击Blackboard上的+图标,然后创建一个Vector1属性。 这表示单个float参数。

将其重命名为GlowSize

您可以通过将其转换为滑块来限制可以在该属性中输入的值。 将Mode切换为Slider,然后将最小值设置为0.05,将最大值设置为6以定义范围。 将默认值设置为5

GlowSize属性拖到工作区中。 将输出端口插入Fresnel Effect Power输入。

最后,还允许用户通过属性设置发光颜色。 无需从Blackboard创建属性,而是可以转换图形中的现有节点。

选择Color节点,然后右键单击并选择“转换为属性”。

Color节点将转换为Blackboard上的color属性,该属性不再可以在图形中直接编辑。 将此属性重命名为GlowColor

单击Save Asset,然后返回到主编辑器窗口。

在“项目”窗口中选择Glow_Mat材料。 您应该在Inspector中看到一个GlowSize滑块和一个GlowColor彩色芯片。

根据您的喜好编辑材料值。 最后,进入Play模式以测试您的工作。

现在,您可以自定义突出显示的内容,您可以调整自己的内心内容!

后记

本篇主要讲述了Shader Graph简介,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容