从零开始实现3D软光栅渲染器 (1) 简介
如何在2D屏幕上表示3D物體?這是學(xué)習(xí)3D編程必須要搞明白的事情。大家都知道,調(diào)用OpenGL的函數(shù),給定三角形的3個(gè)頂點(diǎn)位置,顏色,就能在屏幕上畫一個(gè)三角形,再加載一幅圖片,就可以給這個(gè)三角形附上紋理,還能讓這個(gè)三角形繞某個(gè)坐標(biāo)軸發(fā)生旋轉(zhuǎn)… 這些看似簡(jiǎn)單的問(wèn)題的背后,實(shí)則是3D編程的內(nèi)功。大家都知道,學(xué)武之人,拼的是內(nèi)力,花里胡哨的招式的確很博人眼球,但是從長(zhǎng)遠(yuǎn)來(lái)看,收益遠(yuǎn)沒有修煉內(nèi)力高。
而一個(gè)軟光柵渲染器幾乎涵蓋了所有的3D渲染知識(shí),從本篇開始,我們將從零開始實(shí)現(xiàn)一個(gè)3D軟光柵渲染器,學(xué)習(xí)3D渲染背后的數(shù)學(xué)原理。
光柵化
所謂光柵化就是將你想畫的東西轉(zhuǎn)換到2D屏幕上的像素的過(guò)程。這個(gè)過(guò)程涉及到很多光柵化算法,比如說(shuō),畫一條直線,大家都知道直線的方程:y = k * x + b (斜截式) 這里的 x , y 的取值范圍是全體實(shí)數(shù),但是屏幕是像素組成的,你要想在屏幕上顯示,你就得使用一些算法將這些實(shí)數(shù)集映射到相應(yīng)的像素集(離散化)。
3D流水線
光柵化是OpenGL渲染流水線的一個(gè)階段,而這個(gè)階段是由GPU完成的。一方面,由于現(xiàn)在很多成熟的光柵化算法已經(jīng)被集成到GPU中,基本不用開發(fā)人員手動(dòng)實(shí)現(xiàn)了。另一方面,由于GPU具有很強(qiáng)的并行計(jì)算能力,相比在CPU中實(shí)現(xiàn)這些算法,圖形的渲染會(huì)大大提升。
那么什么是渲染管線呢?你可以想象一下iphone的生成車間,先制作地板,然后焊接電路,再安裝電池…這就是一條流水線。3D編程中,將物體最終顯示到屏幕上也要經(jīng)歷類似的過(guò)程。
我們以游戲開發(fā)為例,簡(jiǎn)單介紹一下這個(gè)流程:
首先,我們需要一個(gè)坐標(biāo)系來(lái)描述場(chǎng)景中各物體的位置,否則你根本無(wú)法確定游戲角色、道具等的位置,這個(gè)坐標(biāo)就叫世界坐標(biāo)。就像它的名字那樣,我們可以把它理解成描述我們構(gòu)建的3D世界的坐標(biāo)系,它是唯一的,它是固定不變的。
而我們的游戲模型一般都是在3D軟件中創(chuàng)建的,一般建模的時(shí)候,也需要一個(gè)坐標(biāo)系用來(lái)描述各個(gè)頂點(diǎn)的位置,這就是局部坐標(biāo)系。如下圖就是blender中的局部坐標(biāo)系,順便說(shuō)一下,它是右手坐標(biāo)系,紅綠藍(lán)三個(gè)箭頭分別對(duì)應(yīng)x,y,z三個(gè)坐標(biāo)軸。局部坐標(biāo)系的原點(diǎn)一般是由建模者設(shè)置的,比如建一個(gè)游戲人物的模型,有的人喜歡把局部坐標(biāo)系的原點(diǎn)放到模型雙腳中心,而有的人喜歡把它放在角色的腰部位置,這都是可以的。
一個(gè)游戲場(chǎng)景一般包含很多模型(房屋,角色,道具,樹木 etc.),而要將這些分別來(lái)自不同建模者的模型繪制到同一個(gè)場(chǎng)景(同一個(gè)世界坐標(biāo)系)中來(lái),就需要進(jìn)行坐標(biāo)變換。沒有找到合適的模型,就拿我珍藏的一張合影來(lái)舉個(gè)例子吧。一圖勝前言,不需要解釋。
好了,現(xiàn)在模型們已經(jīng)變換到世界坐標(biāo)系了。你玩游戲的時(shí)候,是不是可以控制人物走動(dòng),走到不同的位置,會(huì)看到不同的景象?此時(shí),你看到視圖,是有一個(gè)叫攝像機(jī)的東東控制的,又叫虛擬相機(jī)。這其實(shí)是一個(gè)概念,就是為了方便觀察世界坐標(biāo)系中而抽象出來(lái)的一個(gè)模型(這里的模型是一種概念上的模型)。即使不同攝像機(jī),我們照樣也可以觀察世界坐標(biāo)系中各個(gè)物體,這個(gè)我們?cè)诤竺娼榻B。現(xiàn)在你只要知道,有一個(gè)叫攝像機(jī)東西,我們可以很方便的通過(guò)控制它來(lái)觀察世界坐標(biāo)系中的物體。此時(shí),我們看到的物體是相對(duì)攝像機(jī)的位置而言的。比如,你拿手機(jī)拍照的時(shí)候,雖然你拍的是上海的東方明珠,等你拍下來(lái)了,就是你手機(jī)上的東方明珠,同一個(gè)物體,只是描述的方式不同,這個(gè)好好品一下。為什么這么干,我們以后再說(shuō)。
現(xiàn)實(shí)世界是3D的,而計(jì)算機(jī)屏幕是2D的。我們?cè)趺磳?D的世界繪制到2D的屏幕上呢?此時(shí),我們就需要選擇一種投影算法,將3D世界中的坐標(biāo)點(diǎn)投影到2D屏幕上。
3D渲染最注重的就是效率。我們其實(shí)只要繪制我們?nèi)搜勰芸匆姷臇|西就好了。一個(gè)三角形,其實(shí)是有2個(gè)面的,一般在某一時(shí)刻,我們只能看到一個(gè)面,所以,另一個(gè)面就不需要繪制了。比如,一個(gè)精細(xì)的人物模型,可能有幾千萬(wàn)個(gè)三角形構(gòu)成的,而我們只能看到游戲人物的外表,其內(nèi)部的三角形面片其實(shí)就不用繪制了,因?yàn)闆]人看。
到這里,我們就已經(jīng)拿到了要進(jìn)行繪制的頂點(diǎn)數(shù)據(jù)了。接下來(lái),就是前面說(shuō)的進(jìn)行光柵化操作了。也就是說(shuō),我給你一堆頂點(diǎn)以及頂點(diǎn)之間的連接關(guān)系,你要能夠在屏幕上正確顯示出來(lái)(決定到底屏幕上哪些像素被著色,哪些不被著色)。假設(shè)我就繪制一個(gè)三角形,給3個(gè)頂點(diǎn),光柵化的過(guò)程,就是將這三個(gè)頂點(diǎn)之間的連線映射到屏幕上相應(yīng)的像素,如果給了顏色信息,還要給三角形區(qū)域著色。到這里,就能夠在屏幕上現(xiàn)實(shí)3D圖形了。
接下來(lái),就是一些優(yōu)化操作了,比如各種測(cè)試(像素包含測(cè)試、裁剪測(cè)試、alpha測(cè)試、模板測(cè)試、深度測(cè)試 etc.)、混合操作等,反正目的就是提升性能、優(yōu)化渲染效果。
這就是大概的3D渲染流水線。我們的軟光柵渲染器就是要自己編碼實(shí)現(xiàn)這一套流程,這樣在調(diào)用OpenGL函數(shù)的時(shí)候,你才知道它背后到底發(fā)生了什么,當(dāng)你遇到問(wèn)題的時(shí)候,你才有能力嘗試猜測(cè)可能什么地方出了問(wèn)題。
開發(fā)環(huán)境
最后,說(shuō)一下開發(fā)環(huán)境。因?yàn)槲覀兪菍W(xué)習(xí)3D渲染流水線,這個(gè)本身已經(jīng)夠復(fù)雜了。為了能把注意力放到軟光柵的實(shí)現(xiàn)上,我們的開發(fā)環(huán)境越簡(jiǎn)單越好,所以,我們選擇JavaScript開發(fā)一個(gè)Web-based軟光柵渲染器,開發(fā)環(huán)境VS code,記事本也可以。
其實(shí),只要你掌握了這一套流程,隨便什么語(yǔ)言,只是顯示環(huán)境不同,核心原理都是相同的。對(duì)著我們的教程,你完全可以實(shí)現(xiàn)其他語(yǔ)言的軟光柵渲染器。
歡迎大家關(guān)注我的公眾號(hào)【OpenGL編程】,定期分享OpenGL相關(guān)的3D編程教程、算法、小項(xiàng)目。歡迎大家一起交流。
總結(jié)
以上是生活随笔為你收集整理的从零开始实现3D软光栅渲染器 (1) 简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 计算机硬件与软件教学反思,计算机硬件教学
- 下一篇: JSP危险化学品管理系统myeclips