Metal與圖形渲染八:透視糾正與坐標(biāo)系

零. 前言

之前一段時(shí)間一直和團(tuán)隊(duì)的其他小伙伴研究很炫酷的特效荐吵,遇到了很多掉頭發(fā)的問題,幸好大家都很給力秉宿,一一給解決了。今天抽空來(lái)復(fù)盤和總結(jié)一下當(dāng)時(shí)遇到的一些難點(diǎn)吧屯碴,就是標(biāo)題所說(shuō)的描睦,透視糾正和坐標(biāo)系這兩個(gè)大難題~

一. 透視糾正

我們的特效需求支持了不規(guī)則的圖形遮罩,也就意味著我們不能直接簡(jiǎn)單粗暴地取一個(gè)圖形的最大最小四個(gè)頂點(diǎn)坐標(biāo)导而。

于是我們想到初步的方案是用OpenCV識(shí)別出四邊形的四個(gè)頂點(diǎn)位置忱叭,直接傳給業(yè)務(wù)端進(jìn)行渲染,想法很不錯(cuò)今艺,確實(shí)識(shí)別出來(lái)了韵丑,但是卻發(fā)現(xiàn)渲染出來(lái)的圖像完全扭曲了

有種百思不得其解的感覺,后面查到文章才知道是透視糾正的原因虚缎。撵彻。

在我們執(zhí)行渲染操作的時(shí)候,頂點(diǎn)著色器會(huì)要求我們返回一個(gè)含(x, y, z, w)的四維坐標(biāo),w稱為比例因子陌僵,當(dāng)w不為0時(shí)(一般設(shè)1)轴合,表示一個(gè)坐標(biāo),一個(gè)三維坐標(biāo)的三個(gè)分量x碗短,y受葛,z用齊次坐標(biāo)表示為變?yōu)閤,y豪椿,z奔坟,w的四維空間,變換成三維坐標(biāo)是方式是(x/w, y/w, z/w)搭盾。

w的作用可不僅僅是使一個(gè)頂點(diǎn)等比例壓縮咳秉,他還有透視糾正的功能,如下面公式所示鸯隅,當(dāng)渲染操作進(jìn)行紋理渲染的時(shí)候澜建,他會(huì)根據(jù)當(dāng)前渲染點(diǎn)到兩個(gè)頂點(diǎn)的距離、以及兩個(gè)頂點(diǎn)的w值進(jìn)行透視糾正蝌以,可以看到炕舵,某個(gè)點(diǎn)w值越大,就離a點(diǎn)越遠(yuǎn)跟畅。w的設(shè)置符合近大遠(yuǎn)小的透視變換咽筋。

如果我們直接傳入頂點(diǎn)坐標(biāo),使w=1徊件,則原透視糾正公式就會(huì)變?yōu)榫€性插值奸攻,最終導(dǎo)致了紋理變形:

因此,為了使得紋理不變形虱痕,我們需要獲取兩個(gè)參數(shù)睹耐,一個(gè)是圖像的外接矩形坐標(biāo),一個(gè)是將外接矩形變換為真實(shí)頂點(diǎn)坐標(biāo)的透視變換矩陣部翘。當(dāng)透視變換矩陣(4*4)乘以外接矩形坐標(biāo)(4*1)時(shí)硝训,即可得到真實(shí)的頂點(diǎn)坐標(biāo),紋理插值也不會(huì)變形了新思。

至于怎么得到透視變換矩陣嘛窖梁,那是工具的事兒啦,大概原理就是根據(jù)外接矩形坐標(biāo)表牢、真實(shí)頂點(diǎn)坐標(biāo)窄绒,調(diào)用OpenCV的透視變換函數(shù)求出來(lái)的。

二. 坐標(biāo)系

通過上一章崔兴,我們可以知道彰导,需要用工具產(chǎn)生的頂點(diǎn)坐標(biāo)蛔翅、透視矩陣確定最終的頂點(diǎn)坐標(biāo)坐標(biāo)。

但由于這個(gè)特效是Web位谋、Android山析、iOS三端的,而且iOS端渲染還包含Metal渲染和OpenGL渲染掏父,各種渲染機(jī)制的坐標(biāo)系不完全相同笋轨,可以簡(jiǎn)單地區(qū)分為左手坐標(biāo)系和右手坐標(biāo)系,我們需要根據(jù)這些坐標(biāo)系來(lái)為工具定制出具體的透視變換矩陣求解方案赊淑。

什么是左手坐標(biāo)系和右手坐標(biāo)系呢爵政?顧名思義,需要伸出你的左手和右手陶缺,并作出兩兩垂直的手勢(shì)钾挟,如下圖所示,可以發(fā)現(xiàn)饱岸,當(dāng)x軸和y軸方向一致的時(shí)候掺出,z軸會(huì)朝向兩個(gè)相反的地方。

OpenGL和OpenCV同屬右手坐標(biāo)系苫费,工具正常求透視矩陣即可汤锨,但對(duì)于Metal的透視矩陣,我們?cè)谟?jì)算的過程中需要將y坐標(biāo)置反百框,這樣就相當(dāng)于z軸翻轉(zhuǎn)了闲礼,才可以適配左手坐標(biāo)系。

再來(lái)看看他們x铐维、y軸的方向位仁,可以發(fā)現(xiàn)OpenGL和Metal是以中間點(diǎn)為原點(diǎn),往右方椎、往上遞增,而OpenCV是以左上角為原點(diǎn)钧嘶,往右棠众、往下遞增。所以工具求出頂點(diǎn)位置后還需要一發(fā)x有决、y坐標(biāo)轉(zhuǎn)換操作闸拿。

這里的originX和originY就是將OpenCV的坐標(biāo)系y坐標(biāo)取反后,歸一化得到的真實(shí)坐標(biāo)书幕。

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;

在解決完頂點(diǎn)坐標(biāo)翻轉(zhuǎn)后新荤,我們還需要留意OpenGL和Metal之間的紋理坐標(biāo)系的差異,OpenGL紋理坐標(biāo)系以左下角為原點(diǎn)台汇,而Metal以左上角為原點(diǎn)苛骨。

OpenGL渲染——GPUImage提供的默認(rèn)紋理坐標(biāo)如下:

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

由此可見篱瞎,對(duì)于OpenGL渲染,頂點(diǎn)的構(gòu)建四個(gè)點(diǎn)分別是左下痒芝、右下俐筋、左上、右上严衬。

而自研Metal鏈?zhǔn)戒秩疽膊捎昧讼嗤募y理坐標(biāo)數(shù)值:

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

但由于紋理坐標(biāo)系與OpenGL不一致澄者,因此對(duì)于Metal渲染,頂點(diǎn)的構(gòu)建四個(gè)點(diǎn)分別是左上请琳、右上粱挡、左下、右下俄精。

因此询筏,對(duì)于同一個(gè)點(diǎn)來(lái)說(shuō),OpenGL的頂點(diǎn)y坐標(biāo)還需要再翻轉(zhuǎn)一次嘀倒。得到以下代碼:

OpenGL的四個(gè)頂點(diǎn):

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

Metal的四個(gè)頂點(diǎn):

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

三. 總結(jié)

w坐標(biāo)是透視變換的重要因子屈留,以近大遠(yuǎn)小的方式?jīng)Q定了渲染圖形的坐標(biāo)和紋理糾正。

OpenGL测蘑、Metal的頂點(diǎn)坐標(biāo)系灌危、紋理坐標(biāo)系各不相同,需要根據(jù)具體坐標(biāo)系去決定頂點(diǎn)坐標(biāo)和紋理坐標(biāo)碳胳。

四. 參考文章

WebGL 紋理映射的透視糾正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勇蝙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挨约,更是在濱河造成了極大的恐慌味混,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诫惭,死亡現(xiàn)場(chǎng)離奇詭異翁锡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)夕土,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門馆衔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人怨绣,你說(shuō)我怎么就攤上這事角溃。” “怎么了篮撑?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵减细,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我赢笨,道長(zhǎng)未蝌,這世上最難降的妖魔是什么驮吱? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮树埠,結(jié)果婚禮上糠馆,老公的妹妹穿的比我還像新娘。我一直安慰自己怎憋,他們只是感情好又碌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绊袋,像睡著了一般毕匀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上癌别,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天皂岔,我揣著相機(jī)與錄音,去河邊找鬼展姐。 笑死躁垛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的圾笨。 我是一名探鬼主播教馆,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼擂达!你這毒婦竟也來(lái)了土铺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤板鬓,失蹤者是張志新(化名)和其女友劉穎悲敷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俭令,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡后德,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抄腔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片探遵。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妓柜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涯穷,我是刑警寧澤棍掐,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站拷况,受9級(jí)特大地震影響作煌,放射性物質(zhì)發(fā)生泄漏掘殴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一粟誓、第九天 我趴在偏房一處隱蔽的房頂上張望奏寨。 院中可真熱鬧,春花似錦鹰服、人聲如沸病瞳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)套菜。三九已至,卻和暖如春设易,著一層夾襖步出監(jiān)牢的瞬間逗柴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工顿肺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戏溺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓屠尊,卻偏偏與公主長(zhǎng)得像旷祸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子知染,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容