WebGL第二十五课:贴图的基础知识| 8月更文挑战

432 阅读5分钟

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

本文标题:WebGL第二十五课:贴图的基础知识| 8月更文挑战

友情提示

这篇文章是WebGL课程专栏的第25篇,强烈建议从前面开始看起。因为花了大量的工夫来讲解向量的概念和矩阵运算。这些基础知识会影响你的思维。

引子

我们知道一张图片,就算很小,像素点也有成千上百个。

但是我们传入WebGL的顶点的个数,一般没这么多。

比如,用我们上次课的办法,画一个正方形的话,也就传入了12个点而已。(如果认为是四个点的,可以回到上次课先看一下,再品尝本次课的内容)

那么,如果我们需要将这个正方形填充一个图片,该怎么办呢。

我们总不能,一个像素点,就准备一个顶点吧,这样还不炸了。

所以说,还是要回顾一下WebGL画三角形的原理:

    1. 将三角形的三个点定好位置
    1. 将三个点根据传入的颜色,或者根据shader中的颜色,将点画出来
    1. 插值(重点就是这一句)

插值深入讲解

两点插值

什么叫两点插值?也就是说,现在有两个点: A(xA,yA)A (x_A, y_A)B(xB,yB)B(x_B, y_B)

点A的颜色用RGB来表示就是(1,1,1), 也就是纯白色。

点B的颜色用RGB来表示就是(0,0,0), 也就是纯黑色。

问题来了,将AB连接起来,问AB线段上任意一点的颜色是什么?

我们用我们朴素的感觉去得出结论:

近朱者赤近墨者黑, 也就是 近A者白 近B者黑

具体的式子就不列出来了,等到用到的时候,再列。

三点插值

这个就要稍微花点时间来说说了。假设有三个点: ABC,颜色分别是:红 绿 蓝。

就像下图这样:

image.png

好了,那么这三个点,组成的三角形内部,任意一点,比如说吧,我们搞一个点D出来,那么这个点D,如果用插值的话,应该是什么颜色呢?

image.png

先给出一个比较有意思的结论:

如果ABC三个点的坐标分别是

(xAyA)(xByB)(xCyC)\left(\begin{array}{cc} x_A\\ y_A\end{array}\right) \left(\begin{array}{cc} x_B\\ y_B\end{array}\right) \left(\begin{array}{cc} x_C\\ y_C\end{array}\right)

如果 D 点的坐标

(xDyD)=a(xAyA)+b(xByB)+c(xCyC)\left(\begin{array}{cc} x_D\\ y_D\end{array}\right) = a * \left(\begin{array}{cc} x_A\\ y_A\end{array}\right) + b * \left(\begin{array}{cc} x_B\\ y_B\end{array}\right)+ c * \left(\begin{array}{cc} x_C\\ y_C\end{array}\right) (式1)

那么 D 点的颜色

D=aA+bB+cCD_颜 = a * A_颜 + b * B_颜 + c * C_颜 (式2)

也就是说:我们找到 三个数 a b c。如果这三个数能够将ABC的坐标组合成D点的坐标,那么D点的颜色,也就是这三个数将ABC的颜色进行组合。

用矩阵来表达一下 式1, 也就是D点坐标的得出:

(xDyD)=(xAxBxCyAyByC)(abc)\left(\begin{array}{cc} x_D\\ y_D\end{array}\right) = \left(\begin{array}{ccc} x_A&x_B&x_C\\ y_A&y_B&y_C\end{array}\right) * \left(\begin{array}{cc} a\\ b \\c \end{array}\right)

用矩阵来表达一下 式2,也就是D点颜色的得出:

(RDGDBD)=(RARBRCGAGBGCBABBBC)(abc)\left(\begin{array}{cc} R_D\\ G_D\\ B_D\end{array}\right) = \left(\begin{array}{ccc} R_A&R_B&R_C\\ G_A&G_B&G_C\\ B_A&B_B&B_C\end{array}\right) * \left(\begin{array}{cc} a\\ b \\c \end{array}\right)

从形式上来讲,但凡是ABC三个点拥有的东西,不管你是坐标,还是颜色,还是别的什么东西,全部都可以用abc这三个数进行组合。

    1. 举一个例子, 温度

ABC三个点的温度分别是 1℃, 30℃, 50 ℃。已知D点坐标:

(xDyD)=(xAxBxCyAyByC)(abc)\left(\begin{array}{cc} x_D\\ y_D\end{array}\right) = \left(\begin{array}{ccc} x_A&x_B&x_C\\ y_A&y_B&y_C\end{array}\right) * \left(\begin{array}{cc} a\\ b \\c \end{array}\right)

问:如果用插值算法的话,那么D点的温度应该是多少?

答:我们用abc三个数进行组合。

(D)=(ABC)(abc)=a1+b30+c50\left(\begin{array}{cc} 温度_D\end{array}\right) = \left(\begin{array}{ccc} 温度_A&温度_B&温度_C\end{array}\right) * \left(\begin{array}{cc} a\\ b \\c \end{array}\right) = a * 1 + b * 30 + c * 50

采样信息:UV

要知道,我们本次课的目的,并不是简单的合成一个颜色。

而是要在中间填充一个图片。

这势必要增加一个步骤,就是我们传入WebGL的点,到底跟图片本身是怎么对应的。

我们知道一个图片,就是一个 width * height 的矩形区域。

我们把这个矩形区域的

  • 左下角看做原点(0,0)

  • 右上角看做(1,1)的话

那么中间任意一个地方,都有一个坐标,我们把这个坐标写成(u, v)。

例如,

  • 图片中心的 (u, v) = (0.5, 0.5)
  • 左上角的 (u, v) = (0, 1)
  • 右下角的 (u, v) = (1, 0)

也就是说,任意一个(u,v)都能够在一个图片上,找到一个位置,而这个位置肯定有图片本身的RGB颜色信息。

我们就是这样来指定一个坐标点的图片信息的,这个信息就是UV信息。

例如,A 点的(u,v) = (0,0), 那么,A点采样的时候,就是在图片的左下角进行采样。

例如,B 点的(u,v) = (0,1), 那么,B点采样的时候,就是在图片的左上角进行采样。

例如,C 点的(u,v) = (1,1), 那么,C点采样的时候,就是在图片的右上角进行采样。

那么假如 有一点D,D点的坐标:

(xDyD)=(xAxBxCyAyByC)(abc)\left(\begin{array}{cc} x_D\\ y_D\end{array}\right) = \left(\begin{array}{ccc} x_A&x_B&x_C\\ y_A&y_B&y_C\end{array}\right) * \left(\begin{array}{cc} a\\ b \\c \end{array}\right)

那么D点的(u,v)是多少呢?根据上面一小节,三个数插值的算法得出:

(UDVD)=(UAUBUCVAVBVC)(abc)\left(\begin{array}{cc} U_D\\ V_D\end{array}\right) = \left(\begin{array}{ccc} U_A&U_B&U_C\\ V_A&V_B&V_C\end{array}\right) * \left(\begin{array}{cc} a\\ b \\c \end{array}\right)

好了,现在D点的(u,v)出来了,那么相应的,D点也可以在图片上,找到一个点,进而进行采样了。

结论

WebGL画三角形的时候,如果我们同时提供了图片和坐标点的UV信息,那么一个三角形中其他的点的UV信息,就是可以插值出来,有了UV信息之后,就可以在图片上进行采样了,然后,三角形内部就可以被图片上采样到的颜色进行填充了。




  正文结束,下面是答疑

小能能说:还行,比较好理解,下次课是不是要搞实践,也就是搞一搞代码?

  • 答:对, 这一次课就是来讲原理,下一次课会放出代码。