zoukankan      html  css  js  c++  java
  • 一个小demo的开发日记(一)

    啊~Re: 0怎么这么赞啊~

    啊~

    =====================================================

    好吧我知道我很久没更新了。

    这不重要!EMT!

    =====================================================

    嘛,进入正题嗯ww

     

    一、3D几何体的组成

    在进入正题之前,请允许我先说些关于…嗯…怎么说呢,基础的东西。

     

    说到底啊,游戏里用到的这些场景。

    它们都是什么?

    它们怎么组成的?

    它们又是怎么被画到屏幕上的?

    为什么我在场景中安放了几个光源,它们就能反光,有阴影,各种各样的效果?

     

    我们都知道计算机程序是通过一行一行的指令执行的。那么上述这些过程又是怎么完成的呢?如果不清楚这个过程的话,是没办法对其进行"深入的改造"的 ——

     

    个人认为,这个demo中如果不了解这些内容的话,是没有办法做出来的。

    在这个demo里 ——

    • 为了让树有平滑的生长过程,还要美观,我需要完全用程序生成这棵树的模型。

      而且说到底我也做不出一个像样的树。大概…能做出一个正在长大的史莱姆

    • 为了让树叶能够好看一点,我希望我能够自己控制光照的计算。

      而且Unity的PBR / GI我没自信在surface上不卡啊。还丑。

    • 为了有一个赞的天空和日夜交替,我希望我能够自己计算整个天空是什么样子的。

      而且Asset store里的东西太贵了。买得起的话谁自己写啊(误

    • ……

    (PBR:基于物理模型的渲染技术;GI:全局光照)

     

    …所以,我需要自己搞。所以,我需要了解这个过程(上面提到的)到底是怎么进行的。

    当然,忽略了诸多细节。

     

    那么首先,我们需要表示出整个场景。这大概算是一个切入点吧。

    不过在这个demo中我们不需要考虑场景的问题。Unity已经为我们做好了;我们只需要考虑场景中的某个物体的"形状""贴图"等等要素。

     

    我们知道,在现今的渲染体系中,物体都是由一堆小面拼起来的。就像下面这个茶壶:

     

    这一个个四边形面组成了茶壶。不过实际上我们关注的并非是面,而是面的顶点。如果我们调整顶点的位置,它会牵动一些面的变化,最终反应到茶壶形状的变化。

     

    除了位置之外,顶点还有许多别的属性。比如给顶点设置一个"颜色"属性,那我们就可以给这个茶壶上色。而且随着顶点颜色的变化,茶壶表面的颜色也会相应的做出改变。

    (下图是一个简化的例子,有三个分别为红色绿色蓝色顶点。)

     

    现在我们有顶点了。为了表示它们,让所有顶点的各项属性分别表示成成一个数组:

    [ A的位置,B的位置,… ]

    [ A的颜色,B的颜色,… ]

     

    好了。但是现在,我们还只有一堆顶点,我们需要把它们组成一个面。为此,我们需要告诉计算机:那些点该组成一个面呢?

    假设这里,面都是三角面。我们把它也表示成一个数组:

    [ 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, … ]

    这表示:0-1-2是一个面,0-2-3是一个面,0-3-4是一个面,…

    这里数字是顶点的序号,这个例子中A是顶点0,B是顶点1。

     

    好,现在我们有整个模型了。该怎么画它呢?

    这部分是显卡(图形处理器,GPU)的工作。首先,我们把这几个数组丢给显卡,随后——

     

    显卡会把这几个数组里的数据转化为空间中的点,这些点具有它们的属性。

    这个过程可以人为设定转换的过程,以及最后它们应该具有怎样的属性。这也是通过写一段小程序实现的,这个程序必须包含一个函数,这个函数接收传进来的一堆数组中的某一列,输出空间中这个点的位置,以及它的各种属性值。这段程序称为顶点着色器(Vertex Shader)。

     

    随后,再经过几个可编程和不可编程的过程,这些点最终组成了面。

    然后经过了一个叫做栅格化的过程,它们被映射到了一些像素上。有点像画图程序里拉出一个圆,随后它"落入"像素点中,变成一幅图的过程。

     

    注意,到现在为止,这些像素还没有颜色。

    不过这些像素各自拥有属性值,这些属性值是从上一步设置好的属性值中计算得出的:就像颜色的渐变一样,每个属性值都会经过"渐变"的过程,然后称为某个像素的属性值

    "渐变"的过程被称为插值。这是一个线性插值。

     

    然后,我们得到某个像素的属性值,需要计算出这个像素该有的颜色。

    这一步也是可以编程的。这个函数要实现的目的就是输入属性值,输出一个颜色值(RGBA),这被称为片段 / 像素着色器(Fragment Shader 或 Pixel Shader)

     

    最后再经过一些乱七八糟的过程(比如扔掉被挡住的顶点之类),最终成为图像呈现给我们。

     

    在上面那个渐变三角形的例子中,颜色值随着顶点位置被传入,在顶点着色器中颜色值原封不动的传出,作为像素着色器的输入值(这时已经拥有渐变了);像素着色器再原封不动的把它输出,就成了那样一副图像。

    上面是一个被简化过的渲染流程。

    (想看真货吗www?)

    不过其实我们大多数情况下,并不关心中间那一坨。所以也不要方w

     

    那么,每个物体都是由什么组成的?

    之前说过,物体由顶点组成,而每个顶点有着许多种属性。实际上,上文中用作例子的"颜色"并不是一个什么常用的属性,比较常用的属性大概有这么几种:

    位置。这是必须的。

    法线。这代表了顶点的朝向,可以用来判断是否朝向光源等。法线是个单位矢量(长度为1)。

    纹理坐标。这代表了作为贴图的图片该如何"贴"到模型上。

    切线。用来建立切线空间。比较高级的技术会用到,可以先不用在意。

    乱七八糟的一些自定义的参数。当然了 —— 你想传一些自有用途的东西到着色器里,不会有人拦着你的。

     

    法线的话大概是这个样子:

     

    纹理坐标(为和坐标加以区别,常用(u, v)的方式表示):

    可以这么来理解:贴图上有几个被顶点标记好的点,把图上被标记的点钉在对应的顶点上。大概是这个感觉。

     

    切线

    其实这个东西可以先不在意,不过还是蛮重要的。

    有的时候在计算中,我们需要用到切线空间:这个空间的正交基(xyz轴)是以顶点的法线(N)和两个与法线垂直的单位矢量(B & T)组成的。不过事实上,和法线垂直的矢量有无穷多个(一个平面),所以我们需要人为指定一个和它垂直的单位矢量便于计算。这个人为指定的矢量就是切线(T),然后我们可以简单的将N和T叉乘来得到B,这就建立起了切线空间。

    N:Normal(法矢(向)量)

    T:Tangent(切矢(向)量)

    B:Bi-Normal(副法矢(向)量)

     

    一言不合就这么多字了…好吧,那下回见w

     

     

     

     

    E M T!

    K M T!

     

    (pixivid = 56926503)

  • 相关阅读:
    获得随机数
    Android Studio中的神操作
    Android Studio中的神操作
    我的github首页
    我的github首页
    初步尝试kotlin
    初步尝试kotlin
    创建自己的github博客
    js方法重载
    【HPU】[1014]【C语言训练】亲密数
  • 原文地址:https://www.cnblogs.com/betairy-linkzeldagg/p/5538793.html
Copyright © 2011-2022 走看看