Metal与图形渲染八:透视纠正与坐标系

零. 前言

之前一段时间一直和团队的其他小伙伴研究很炫酷的特效,遇到了很多掉头发的问题,幸好大家都很给力,一一给解决了。今天抽空来复盘和总结一下当时遇到的一些难点吧,就是标题所说的,透视纠正和坐标系这两个大难题~

一. 透视纠正

我们的特效需求支持了不规则的图形遮罩,也就意味着我们不能直接简单粗暴地取一个图形的最大最小四个顶点坐标。

于是我们想到初步的方案是用OpenCV识别出四边形的四个顶点位置,直接传给业务端进行渲染,想法很不错,确实识别出来了,但是却发现渲染出来的图像完全扭曲了

有种百思不得其解的感觉,后面查到文章才知道是透视纠正的原因。。

在我们执行渲染操作的时候,顶点着色器会要求我们返回一个含(x, y, z, w)的四维坐标,w称为比例因子,当w不为0时(一般设1),表示一个坐标,一个三维坐标的三个分量x,y,z用齐次坐标表示为变为x,y,z,w的四维空间,变换成三维坐标是方式是(x/w, y/w, z/w)。

w的作用可不仅仅是使一个顶点等比例压缩,他还有透视纠正的功能,如下面公式所示,当渲染操作进行纹理渲染的时候,他会根据当前渲染点到两个顶点的距离、以及两个顶点的w值进行透视纠正,可以看到,某个点w值越大,就离a点越远。w的设置符合近大远小的透视变换。

如果我们直接传入顶点坐标,使w=1,则原透视纠正公式就会变为线性插值,最终导致了纹理变形:

因此,为了使得纹理不变形,我们需要获取两个参数,一个是图像的外接矩形坐标,一个是将外接矩形变换为真实顶点坐标的透视变换矩阵。当透视变换矩阵(4*4)乘以外接矩形坐标(4*1)时,即可得到真实的顶点坐标,纹理插值也不会变形了。

至于怎么得到透视变换矩阵嘛,那是工具的事儿啦,大概原理就是根据外接矩形坐标、真实顶点坐标,调用OpenCV的透视变换函数求出来的。

二. 坐标系

通过上一章,我们可以知道,需要用工具产生的顶点坐标、透视矩阵确定最终的顶点坐标坐标。

但由于这个特效是Web、Android、iOS三端的,而且iOS端渲染还包含Metal渲染和OpenGL渲染,各种渲染机制的坐标系不完全相同,可以简单地区分为左手坐标系和右手坐标系,我们需要根据这些坐标系来为工具定制出具体的透视变换矩阵求解方案。

什么是左手坐标系和右手坐标系呢?顾名思义,需要伸出你的左手和右手,并作出两两垂直的手势,如下图所示,可以发现,当x轴和y轴方向一致的时候,z轴会朝向两个相反的地方。

OpenGL和OpenCV同属右手坐标系,工具正常求透视矩阵即可,但对于Metal的透视矩阵,我们在计算的过程中需要将y坐标置反,这样就相当于z轴翻转了,才可以适配左手坐标系。

再来看看他们x、y轴的方向,可以发现OpenGL和Metal是以中间点为原点,往右、往上递增,而OpenCV是以左上角为原点,往右、往下递增。所以工具求出顶点位置后还需要一发x、y坐标转换操作。

这里的originX和originY就是将OpenCV的坐标系y坐标取反后,归一化得到的真实坐标。

GLfloat originX, originY, width, height;
originX = -1 + 2 * rect.origin.x / videoSize.width;
originY = 1 - 2 * rect.origin.y / videoSize.height;
width = 2 * rect.size.width / videoSize.width;
height = 2 * rect.size.height / videoSize.height;

在解决完顶点坐标翻转后,我们还需要留意OpenGL和Metal之间的纹理坐标系的差异,OpenGL纹理坐标系以左下角为原点,而Metal以左上角为原点。

OpenGL渲染——GPUImage提供的默认纹理坐标如下:

static const GLfloat noRotationTextureCoordinates[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
    };

由此可见,对于OpenGL渲染,顶点的构建四个点分别是左下、右下、左上、右上。

而自研Metal链式渲染也采用了相同的纹理坐标数值:

- (NSArray *)defaultTextureCoordinates {
    return @[
        @0.0f, @0.0f,
        @1.0f, @0.0f,
        @0.0f, @1.0f,
        @1.0f, @1.0f,
    ];
}

但由于纹理坐标系与OpenGL不一致,因此对于Metal渲染,顶点的构建四个点分别是左上、右上、左下、右下。

因此,对于同一个点来说,OpenGL的顶点y坐标还需要再翻转一次。得到以下代码:

OpenGL的四个顶点:

float oriVertices[] = {
    originX,            -originY,
    originX + width,    -originY,
    originX,            height - originY,
    originX + width,    height - originY,
};

Metal的四个顶点:

NSArray *result = @[
    @(originX), @(originY),
    @(originX+width), @(originY),
    @(originX), @(originY-height),
    @(originX+width), @(originY-height),
];

三. 总结

w坐标是透视变换的重要因子,以近大远小的方式决定了渲染图形的坐标和纹理纠正。

OpenGL、Metal的顶点坐标系、纹理坐标系各不相同,需要根据具体坐标系去决定顶点坐标和纹理坐标。

四. 参考文章

WebGL 纹理映射的透视纠正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容