Ambient Occlusion

在以往的光照模型中,我们没有考虑间接光
以往的环境光照模型为: A=Lama
La 表示物体接受到的间接光的总量
ma 表示物体的材质,指定了射入环境光的反射和吸收的数量
并且认为光线从各个方向均匀的入射到物体表面
但这种计算模型完全不真实

环境光遮蔽的思想是:物体表面某点 p 的间接光数目是与以 p 为球心的半球对入射光线的遮蔽程度成比例的
这里写图片描述
(图片来源:Introduction to 3D Game Programming With DirectX 11)
左边的图表示入射光线全部通过半球射入到 p 点上
右边的图表明一部分光线被遮挡未能入射到 p 点上,即 p 点被遮蔽了

在现实中我们知道这样一个现象,墙角处看起来总是比旁边要暗一下,那是因为墙角收到墙面的遮蔽,因此为了模拟这样一个情况,我们需要计算出物体顶点的遮蔽程度,或者说遮蔽值

那么我们怎样去计算每个顶点的遮蔽程度呢?

假设 p 为物体表面上一点,以 p 点为球心构造一个半球,半球的方向为该点法线的方向,无需考虑负半球,其无法对 p 点造成遮蔽。

构造随机的入射光线是比较困难的,我们可以逆向处理,如:由 p 点发出N条光线,若由H条方向被遮蔽了,则我们认为该点的遮蔽程度为 HN ,我们也将接受到的光线比例称为ambient access.因此ambient access = 1.0 - HN

AO计算公式:
A(p,n)=1πΩV(w,p)max(wn,0)dw

p 表示表面上一点
Ω 表示以 p 点为球心的正半球,即法线指向的方向
n 表示 p 点的法线
w 表示半球体 Ω p 点发出光线的方向向量
V 表示可视函数

因此Ambient Occlusion的计算是通过对围绕着以 p 点为球心的半球 Ω 上的局部AO值进行积分得到,由此可见, V(w,p) 是一个二值函数,因为对于任意一条光线,要么对点 p 产生遮蔽要么不产生,因此取值只有0 , 1 。但实现起来这显然是不可能也不必要的。我们只需进行一部分采样来进行模拟得到

假设通过点 p 沿着半球 Ω 发出的一条光线,与物体相交于点 q ,但是假如点 q p 点太远时,我们可以认为点 q p 点并没有产生遮蔽,因此我们可以设置一个阀值(threshold value),当距离大于阀值时,认为不产生遮蔽作用

我们可以在进入着色器之前为每个顶点预先计算出其遮蔽值~~

伪代码如下:

        std::vector<UINT> VertexSharedCount(VertexCount); // 用于保存顶点被共享的次数,最终用于计算顶点的平均Ambient Access
        for(int i = 0; i < TriangleCount; i++)
        {
            int i0 = indices[3 * i + 0];
            int i1 = indices[3 * i + 1];
            int i2 = indices[3 * i + 2];

            Vertex v0 = vertices[i0];
            Vertex v1 = vertices[i1];
            Vertex i2 = vertices[i2];

            Edge e1 = v1 - v0;
            Edge e2 = v2 - v0;

            normal = e1 * e2;

            center = (v0 + v1 + v2) / 3;

            for(int j = 0; j < SampleLightCount; j++)
            {
                RayDirection = GenerateRandomVector();

                if(!octree.RayIntersect(center , normal))
                {
                    UnOcclusionNum++;
                }
            }

            float access = 1.0f - (UnOcclusionNum / SampleLightCount);

            vertices[i0].access += access;
            vertices[i1].access += access;
            vertices[i2].access += access;

            VertexSharedCount[i0]++;
            VertexSharedCount[i1]++;
            VertexSharedCount[i2]++;
        }

        for(int i = 0; i < VertexCount; i++)
        {
            vertices[i].access /= VertexSharedCount[i];
        }

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值