学习教程来自:【技术美术百人计划】图形 3.3 曲面细分与几何着色器 大规模草渲染

Unity版本:Unity 2019.3.15f1


感谢老师的传道授业解惑,本篇用于总结复习和实践

1. 知识基础

TESS能做什么?

  1. 将曲面细分:直线逼近曲线、正方体细分成球体

  2. 增加凹凸感,与置换贴图结合使用


对比图

  1. 优化:根据既定规则(如,距离)控制细分面数

GS能做什么?

  1. 几何动画:爆炸破碎效果

  2. 草地生成


OpenGL中的着色顺序

图片来源


2. TESS

pragma hull hullProgram


pragma domain ds

输入输出

输入Patch,将图元细分,输出细分后的顶点

流程

  1. HULL Shader:设定参数;对输入进行变化(若需要)

  2. Tessellation Primitive Generation:细分操作

  3. Domain Shader:空间转换

    vert函数(不是顶点着色器 )对顶点进行了变化
  4. 顶点替换的vert函数

    使用切线空间矩阵将法线转换回世界空间

3. GS

pragma geometry geo

输入输出

均为图元,输出的图元需要按顺序逐顶点构建

几何着色器函数

在切线空间中生成并转换到对象空间

4. TESS和GS结合使用

生成一个更加接近实际的模拟草地

几何着色器部分

  1. 生成一棵草

    顶点从下往上添加,一共 SEGMENT * 2 + 1 个点
  2. 草的弯曲(bend)和朝向(wind+facing)

    最下边的2个点只考虑朝向
  3. 草的密度调整

    在HullShader部分基于距离调整参数
  4. 效果

5. 课后作业

基于草的效果,尝试实现物体在草地上运动时产生的交互。

思路

这里使用了一个圆形小球作为运动的物体,小球下方的草地会被压平(height降低),未被压平但在小球周围的物体,会收到挤压向周围弯曲(facing和bend),并且这些与小球产生接触的草,收到风的影响会降低(wind)。


因此需要在几何着色器中重新计算以上的变化矩阵,基于当前小球在世界空间下的位置。

height

disFactor 为世界空间下的顶点与小球的距离

underFactor 为判断是否草在正下方

disFactor = compileFactor(_TestLocation,vWorldPos);
underFactor = disFactor < 0.6 ? 0.2 * disFactor : 1;

height = height * disFactor * underFactor;

facing

计算一个朝向,使周围的小草都朝向小球(只考虑XZ平面,从-Z方向开始超箭头方向一周,return的值从0变化到2PI,用arccos可求得)

float compileFacingFactor(float3 xPos, float3 yPos){
        float x = yPos.x-xPos.x;
        float z = yPos.z-xPos.z;
        float t = 0;
        if(x < 0){
            x = -x;
            z = -z;
            t = UNITY_PI;
        }
        return acos(dot(float3(0, 0, -1),normalize(float3(x, 0, z)))) + t;
}

facingFactor = compileFacingFactor(_TestLocation,vWorldPos);
facingRotationMatrixCus = AngleAxis3x3(facingFactor, float3(0, 0, 1));

bend

按距离增加了弯曲程度(不太严谨,应该离得越近越弯曲)

forwardFactor = 2;
bendRotationMatrixCus = AngleAxis3x3(forwardFactor * disFactor * _BendRotationRandom * UNITY_PI * 0.5, float3(-1, 0, 0));

wind

越近受到风的影响越小

windFactor = 0.5;
windRotationCus = AngleAxis3x3(UNITY_PI * windSample * windFactor * disFactor, wind);

效果图