OpenGLES入门笔记 :OpenGLES光照基础总结2 获取法向量

背景

上一篇我们谈了光照的基本知识,其中漫反射和镜面反射都涉及到了光照面的法线。如果对于天空盒等简单的物体,我们手工指定了法向量,但是如果对于一个复杂的物体,我们没办法为每个面指定法向量了。下面我们就来总结如何找到每个面的法向量。

原理

这里写图片描述
如图,此时我们把ABCD当做一个平面,此时向量AC和向量BD可以确定一个平面。蓝色箭头就代表ABCD平面的法线,也就是我们要求的法向量。
通过点ABCD的坐标,我们可以求得向量AC,BD。有了向量ACBD,我们如何确定它们的法线呢?这就用到一些线性代数的知识了,下面的知识就靠百度百科了….

这里写图片描述

上图截取自百度百科,注意最后一句话,叉积得到的是一个向量,并且与当前这两个向量垂直。这不就是我们要的法向量吗!
此时还有个问题,我们的法向量也是有方向的,是垂直与表面向上的。那么叉积的方向是如何判断的呢?百度百科是这样解释的:

方向:a向量与b向量的向量积的方向与这两个向量所在平面垂直,且遵守右手定则。(一个简单的确定满足“右手定则”的结果向量的方向的方法是这样的:若坐标系是满足右手定则的,当右手的四指从a以不超过180度的转角转向b时,竖起的大拇指指向是c的方向。

下面附图一张,表示向量a X向量 b,以及对应的右手手势(这只手似乎握着什么东西…….)。
这里写图片描述
这样我们就得到了平面的法向量。

叉积的具体计算方式如下
a=(a1,b1,c1),b=(a2,b2,c2)
两向量的叉积可以用如下行列式来计算i,j,k分别代表x,y,z轴的单位向量。
  | i j k|
  |x1 y1 z1|
  |x2 y2 z2|

i(y1z2 - z1y2) + j(z1x2 - z2x1) + k(x1y2 - y1x2)

代码

下面我们开始拷贝代码….
先来建立一个向量类,用来保存我们的向量并提供相关计算方法。
Vector.class

    public static class Vector  {
        public final float x, y, z;

        public Vector(float x, float y, float z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public float length() {
            return FloatMath.sqrt(
                x * x 
              + y * y 
              + z * z);
        }

        // http://en.wikipedia.org/wiki/Cross_product        
        public Vector crossProduct(Vector other) {
            return new Vector(
                (y * other.z) - (z * other.y), 
                (z * other.x) - (x * other.z), 
                (x * other.y) - (y * other.x));
        }

        // http://en.wikipedia.org/wiki/Dot_product
        public float dotProduct(Vector other) {
            return x * other.x 
                 + y * other.y 
                 + z * other.z;
        }

        public Vector scale(float f) {
            return new Vector(
                x * f, 
                y * f, 
                z * f);
        }

        public Vector normalize() {
            return scale(1f / length());
        }
    }

我们可以使用crossProduct方法来得到当前向量与其他向量之间的叉积,有了上述的理论知识,我们很容易明白这个方法的实现。

同样这里也提供了点积的求法dotProduct,点积得到是一个值,也就是每个对应的向量相乘后再相加。

还提供了一个向量归一化方法normalize,即把当前向量的模长变为1,方向不变。

使用vectorBetween方法来得到向量。

public static Vector vectorBetween(Point from, Point to) {
        return new Vector(
            to.x - from.x, 
            to.y - from.y, 
            to.z - from.z);
    }

这样,我们只要能够找到确定一个平面的点的坐标,通过点坐标得到能够确定平面的向量的坐标,然后就可以通过这两个向量来得到平面的法线了。将得到的法线传入着色器的参数,着色器就能得到平面的法线了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值