日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间

發布時間:2024/10/12 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

在上一個教程中,我們在應用程序窗口的中心成功渲染了一個三角形。 我們沒有太注意我們在頂點緩沖區中拾取的頂點位置。 在本教程中,我們將深入研究3D位置和轉換的細節。

本教程的結果將是渲染到屏幕的3D對象。 雖然之前的教程側重于將2D對象渲染到3D世界,但在這里我們展示了一個3D對象。

?

資源目錄

(SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial04

Github倉庫

?

3D空間

在上一個教程中,三角形的頂點被有策略地放置,以在屏幕上完美地對齊。 但是,情況并非總是如此。 因此,我們需要一個系統來表示3D空間中的對象和一個顯示它們的系統。

在現實世界中,物體存在于3D空間中。 這意味著要將對象放置在世界中的特定位置,我們需要使用坐標系并定義與位置對應的三個坐標。 在計算機圖形學中,3D空間最常用于笛卡爾坐標系。 在該坐標系中,三個軸X,Y和Z彼此垂直,決定了空間中每個點的坐標。 該坐標系進一步分為左手系統和右手系統。 在左手系統中,當X軸指向右側,Y軸指向上方時,Z軸指向前方。 在右手系統中,具有相同的X和Y軸,Z軸指向后方。

圖1.左手坐標系與右手坐標系

現在我們已經討論過坐標系,考慮3D空間。 點在不同的空間中具有不同的坐標。 作為一維中的一個例子,假設我們有一個標尺,我們注意到標尺的5英寸標記處的點P. 現在,如果我們將標尺向右移動1英寸,則相同的點位于4英寸標記處。 通過移動標尺,參考框架已經改變。 因此,當點沒有移動時,它有一個新的坐標。

圖2. 1D中的空間圖示

在3D中,空間通常由原點和來自原點的三個唯一軸定義:X,Y和Z.計算機圖形中通常使用多個空間:對象空間,世界空間,視圖空間,投影空間和屏幕空間。

圖3.在對象空間中定義的立方體

?

對象空間

請注意,多維數據集以原點為中心。?對象空間,也稱為模型空間,是指藝術家在創建3D模型時使用的空間。?通常,藝術家創建以原點為中心的模型,以便更容易執行轉換,例如旋轉模型,我們將在討論轉換時看到。?八個頂點具有以下坐標:? ? (-1, 1, -1)( 1, 1, -1)(-1, -1, -1)( 1, -1, -1)(-1, 1, 1)( 1, 1, 1)(-1, -1, 1)( 1, -1, 1) 因為對象空間是藝術家在設計和創建模型時通常使用的對象空間,所以存儲在磁盤上的模型也在對象空間中。 應用程序可以創建頂點緩沖區來表示此類模型,并使用模型數據初始化緩沖區。 因此,頂點緩沖區中的頂點通常也位于對象空間中。 這也意味著頂點著色器接收對象空間中的輸入頂點數據。

世界空間

世界空間是場景中每個對象共享的空間。 它用于定義我們希望渲染的對象之間的空間關系。 為了想象世界空間,我們可以想象我們正站在朝北的長方形房間的西南角。 我們將我們的腳站立的角落定義為原點,(0,0,0)。 X軸向我們的右邊; Y軸上升; 并且Z軸向前,與我們面對的方向相同。 當我們這樣做時,房間中的每個位置都可以用一組XYZ坐標來識別。 例如,可能有一把椅子在前方5英尺處,在我們右側2英尺處。 在椅子頂部的8英尺高的天花板上可能有一盞燈。 然后我們可以將椅子的位置稱為(2,0,5),將燈的位置稱為(2,8,5)。 正如我們所看到的,世界空間就是所謂的在世界上相互聯系的物體所組成的。

視圖空間

視圖空間(有時稱為相機空間)類似于世界空間,因為它通常用于整個場景。 但是,在視圖空間中,原點位于查看器或攝像機。 視圖方向(觀察者正在看的位置)定義正Z軸。 應用程序定義的“向上”方向變為正Y軸,如下所示。 圖4.世界空間(左)和視圖空間(右)中的相同對象

左圖顯示了一個場景,該場景由類似人的物體和觀察物體的觀察者(相機)組成。 世界空間使用的原點和軸以紅色顯示。 右圖顯示了與世界空間相關的視圖空間。 視圖空間軸顯示為藍色。 為了更清楚地說明,視圖空間與左圖像中的世界空間的方向與讀者不同。 請注意,在視圖空間中,查看器正在Z方向上查看。

?

投影空間

投影空間是指從視圖空間應用投影變換后的空間。 在此空間中,可見內容的X和Y坐標范圍為-1到1,Z坐標范圍為0到1。

?

屏幕空間

屏幕空間通常用于指代幀緩沖區中的位置。 因為幀緩沖區通常是2D紋理,所以屏幕空間是2D空間。 左上角是坐標為(0,0)的原點。 正X向右,正Y向下。 對于w像素寬且h像素高的緩沖區,最右下像素具有坐標(w-1,h-1)。

?

空間對空間的轉換

轉換最常用于將頂點從一個空間轉換為另一個空間。 在3D計算機圖形學中,管道中邏輯上有三種這樣的變換:世界,視圖和投影變換。 下一個教程將介紹單個轉換操作,如轉換,旋轉和縮放。

?

世界轉換

顧名思義,世界轉換將頂點從對象空間轉換為世界空間。 它通常由一個或多個縮放,旋轉和平移組成,基于我們想要給對象的大小,方向和位置。 場景中的每個對象都有自己的世界變換矩陣。 這是因為每個對象都有自己的大小,方向和位置。

?

視圖轉換

頂點轉換為世界空間后,視圖轉換將這些頂點從世界空間轉換為視圖空間。 回想一下之前的討論,觀看空間是世界從觀眾(或相機)的角度出現的。 在視圖空間中,觀察者位于沿正Z軸向外看的原點。

值得注意的是,盡管視圖空間是來自觀察者參照系的世界,但視圖變換矩陣應用于頂點,而不是觀察者。 因此,視圖矩陣必須執行我們應用于我們的查看器或相機的相反轉換。 例如,如果我們想要將攝像機朝向-Z方向移動5個單元,我們需要計算一個視圖矩陣,它可以沿著+ Z方向將頂點平移5個單位。 雖然相機向后移動,但從相機的角度來看,頂點已向前移動。 在XNA Math中,一個方便的API調用XMMatrixLookAtLH()通常用于計算視圖矩陣。 我們只需要告訴它觀察者在哪里,在哪里看,以及表示觀察者頂部的方向,也稱為向上矢量,以獲得相應的視圖矩陣。

?

投影轉換

投影變換將頂點從諸如世界和視圖空間的3D空間轉換為投影空間。 在投影空間中,頂點的X和Y坐標是從3D空間中該頂點的X / Z和Y / Z比獲得的。

圖5.投影

在3D空間中,事物以透視的方式出現。 也就是說,物體越近,它出現的越大。 如圖所示,在遠離觀察者眼睛的d個單位處高h單位的樹的尖端將出現在與另一棵樹的尖端2h單位高和2d單位遠的相同點處。 因此,在2D屏幕上出現頂點的位置與其X / Z和Y / Z比率直接相關。

定義3D空間的參數之一稱為視場(FOV)。 FOV表示在特定方向上查看哪些對象從特定位置可見。 人類有一個前瞻性的FOV(我們無法看到我們背后的東西),我們看不到太近或太遠的物體。 在計算機圖形學中,FOV包含在視錐體中。 視錐體由3D中的6個平面定義。 這些平面中的兩個平行于XY平面。 這些被稱為近Z和遠Z平面。 其他四個平面由觀察者的水平和垂直視野定義。 視場越寬,視錐體體積越寬,觀察者看到的物體越多。

GPU會過濾掉視錐體外的對象,這樣就不必花時間渲染無法顯示的內容。 此過程稱為裁剪。 視錐體是一個四面金字塔,頂部被切掉。 剪切此卷是很復雜的,因為要剪切一個視錐體平面,GPU必須將每個頂點與平面的等式進行比較。 相反,GPU通常首先執行投影變換,然后針對視錐體量進行剪輯。 投影變換對視錐體的影響是金字塔形視錐體成為投影空間中的盒子。 這是因為,如前所述,在投影空間中,X和Y坐標基于3D空間中的X / Z和Y / Z. 因此,點a和點b在投影空間中將具有相同的X和Y坐標,這就是視錐體成為盒子的原因。

圖6.查看平截頭體

假設兩棵樹的尖端恰好位于頂視圖平截頭體邊緣。進一步假設d = 2h。沿投影空間中頂邊的Y坐標將為0.5(因為h / d = 0.5)。因此,任何大于0.5的Y投影后Y值都將被裁剪。這里的問題是0.5由程序選擇的垂直視場確定,并且不同的FOV值導致GPU必須剪切的不同值。為了使這個過程更加方便,3D程序通??s放頂點的投影X和Y值,以便可見的X和Y值的范圍從-1到1.換句話說,任何X或Y坐標都在[-1]之外1]范圍將被刪除。為了使該剪切方案起作用,投影矩陣必須通過h / d或d / h的倒數來縮放投影頂點的X和Y坐標。 d / h也是FOV一半的余切。通過縮放,視錐體的頂部變為h / d * d / h = 1.大于1的任何內容都將被GPU裁剪。這就是我們想要的。

通常也對投影空間中的Z坐標進行類似的調整。 我們希望近和遠Z平面分別在投影空間中為0和1。 當Z = 3D空間中的近Z值時,Z在投影空間中應為0; 當Z = 3D空間中的遠Z時,Z在投影空間中應為1。 完成此操作后,GPU [0 1]以外的任何Z值都將被裁剪掉。

在Direct3D 11中,獲取投影矩陣的最簡單方法是調用XMMatrixPerspectiveFovLH()方法。 我們只提供4個參數-FOVy,Aspect,Zn和Zf-并返回一個矩陣,它可以完成上面提到的所有必要操作。 FOVy是Y方向的視野。 Aspect是寬高比,即視圖寬度與高度的比率。 從FOVy和Aspect,可以計算FOVx。 該縱橫比通常從渲染目標寬度與高度的比率獲得。 Zn和Zf分別是視圖空間中的近和遠Z值。

?

使用轉換

在上一個教程中,我們編寫了一個程序,用于渲染單個三角形。 當我們創建頂點緩沖區時,我們使用的頂點位置直接在投影空間中,這樣我們就不必執行任何變換。 現在我們已經了解了3D空間和變換,我們將修改程序,以便在對象空間中定義頂點緩沖區,就像它應該的那樣。 然后,我們將修改頂點著色器以將頂點從對象空間轉換為投影空間。

?

修改頂點緩沖區

由于我們開始以三維方式表示事物,因此我們將前一個教程中的平面三角形更改為多維數據集。 這將使我們能夠更清楚地展示這些概念。

SimpleVertex vertices[] ={{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) },{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) },{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f ) },{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) },{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 0.0f, 1.0f, 1.0f ) },{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 0.0f, 1.0f ) },{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) },};

  

如果你注意到我們所做的只是指定立方體上的八個點,但我們實際上沒有描述各個三角形。 如果我們按原樣傳遞,輸出將不是我們所期望的。 我們需要通過這八個點指定形成立方體的三角形。

在立方體上,許多三角形將共享相同的頂點,并且一次又一次地重新定義相同的點將浪費空間。 因此,有一種方法只指定八個點,然后讓Direct3D知道要為三角形選擇哪些點。 這是通過索引緩沖區完成的。 索引緩沖區將包含一個列表,該列表將引用緩沖區中的頂點索引,以指定在每個三角形中使用哪些點。 下面的代碼顯示了構成每個三角形的點。

// Create index bufferWORD indices[] ={3,1,0,2,1,3,0,5,4,1,5,0,3,4,7,0,4,3,1,6,5,2,6,1,2,7,6,3,7,2,6,4,5,7,4,6,};

  

如您所見,第一個三角形由點3,1和0定義。這意味著第一個三角形的頂點位于:( - 1.0f,1.0f,1.0f),(1.0f,1.0f,-1.0) f),和(-1.0f,1.0f,-1.0f)。 立方體上有六個面,每個面由兩個三角形組成。 因此,您會看到此處定義的12個三角形。

由于每個頂點都是明確列出的,并且沒有兩個三角形共享邊(至少,它已經被定義),這被認為是一個三角形列表。 總的來說,對于三角形列表中的12個三角形,我們將需要總共36個頂點。

索引緩沖區的創建與頂點緩沖區非常相似,我們在結構中指定了諸如大小和類型之類的參數,并稱為CreateBuffer。 類型是D3D11_BIND_INDEX_BUFFER,因為我們使用DWORD聲明了我們的數組,所以我們將使用sizeof(DWORD)。

D3D11_BUFFER_DESC bd;ZeroMemory( &bd, sizeof(bd) );bd.Usage = D3D11_USAGE_DEFAULT;bd.ByteWidth = sizeof( WORD ) * 36; // 36 vertices needed for 12 triangles in a triangle listbd.BindFlags = D3D11_BIND_INDEX_BUFFER;bd.CPUAccessFlags = 0;bd.MiscFlags = 0;InitData.pSysMem = indices;if( FAILED( g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ) ) )return FALSE;

  

一旦我們創建了這個緩沖區,我們就需要設置它,以便Direct3D知道在生成三角形時引用這個索引緩沖區。 我們指定緩沖區的指針,格式和緩沖區中的偏移量以開始引用。

// Set index bufferg_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );

  

修改頂點著色器

在上一個教程的頂點著色器中,我們采用輸入頂點位置并輸出相同的位置而不進行任何修改。我們可以這樣做,因為輸入頂點位置已經在投影空間中定義?,F在,因為輸入頂點位置是在對象空間中定義的,所以我們必須在從頂點著色器輸出之前對其進行變換。我們通過三個步驟完成此任務:從對象轉換到世界空間,從世界轉換到視圖空間,以及從視圖轉換到投影空間。我們需要做的第一件事是聲明三個常量緩沖區變量。常量緩沖區用于存儲應用程序需要傳遞給著色器的數據。在渲染之前,應用程序通常會將重要數據寫入常量緩沖區,然后在渲染過程中可以從著色器中讀取數據。在FX文件中,常量緩沖區變量在C ++結構中聲明為全局變量。我們將使用的三個變量是HLSL類型“矩陣”的世界,視圖和投影變換矩陣。

一旦我們聲明了我們需要的矩陣,我們就會更新頂點著色器以使用矩陣變換輸入位置。 通過將矢量乘以矩陣來變換矢量。 在HLSL中,這是使用mul()內部函數完成的。 我們的變量聲明和新的頂點著色器如下所示:

cbuffer ConstantBuffer : register( b0 ){matrix World;matrix View;matrix Projection;}//// Vertex Shader//VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR ){VS_OUTPUT output = (VS_OUTPUT)0;output.Pos = mul( Pos, World );output.Pos = mul( output.Pos, View );output.Pos = mul( output.Pos, Projection );output.Color = Color;return output;}

  

在頂點著色器中,每個 mul()將一個變換應用于輸入位置。 世界,視圖和投影變換按順序依次應用。 這是必要的,因為向量和矩陣乘法不是可交換的。

?

設置矩陣

我們更新了頂點著色器以使用矩陣進行變換,但我們還需要在程序中定義三個矩陣。 這三個矩陣將存儲渲染時要使用的變換。 在渲染之前,我們將這些矩陣的值復制到著色器常量緩沖區。 然后,當我們通過調用Draw()啟動渲染時,我們的頂點著色器讀取存儲在常量緩沖區中的矩陣。 除了矩陣之外,我們還需要一個代表常量緩沖區的ID3D11Buffer對象。 因此,我們的全局變量將添加以下內容:

ID3D11Buffer* g_pConstantBuffer = NULL;XMMATRIX g_World;XMMATRIX g_View;XMMATRIX g_Projection;

  

要創建ID3D11Buffer對象,我們使用 ID3D11Device :: CreateBuffer()并指定D3D11_BIND_CONSTANT_BUFFER

D3D11_BUFFER_DESC bd;ZeroMemory( &bd, sizeof(bd) );bd.Usage = D3D11_USAGE_DEFAULT;bd.ByteWidth = sizeof(ConstantBuffer);bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;bd.CPUAccessFlags = 0;if( FAILED(g_pd3dDevice->CreateBuffer( &bd, NULL, &g_pConstantBuffer ) ) )return hr;

  

我們需要做的下一件事是提出三個矩陣,我們將用它來進行轉換。我們希望三角形位于原點上,與XY平面平行。這正是它如何存儲在對象空間中的頂點緩沖區中。因此,世界變換不需要做任何事情,我們將世界矩陣初始化為單位矩陣。我們想要設置我們的相機,使其位于[0 1 -5],查看點[0 1 0]。我們可以使用向上矢量[0 1 0]調用 XMMatrixLookAtLH()來方便地為我們計算視圖矩陣,因為我們希望+ Y方向始終保持在頂部。最后,為了得到投影矩陣,我們稱之為XMMatrixPerspectiveFovLH(),具有90度垂直視場(pi / 2),寬高比為640/480,來自我們的后緩沖區大小,以及近和遠Z分別為0.1和110。這意味著屏幕上將看不到小于0.1或超過110的任何內容。這三個矩陣存儲在全局變量g_World,g_View和g_Projection中。

?

更新常量緩沖區

我們有矩陣,現在我們必須在渲染時將它們寫入常量緩沖區,以便GPU可以讀取它們。 要更新緩沖區,我們可以使用 ID3D11DeviceContext :: UpdateSubresource()API并將指針傳遞給以與著色器常量緩沖區相同的順序存儲的矩陣。 為了做到這一點,我們將創建一個與著色器中的常量緩沖區具有相同布局的結構。 另外,由于矩陣在C ++和HLSL中的內存排列方式不同,我們必須在更新之前轉置矩陣。

//// Update variables//ConstantBuffer cb;cb.mWorld = XMMatrixTranspose( g_World );cb.mView = XMMatrixTranspose( g_View );cb.mProjection = XMMatrixTranspose( g_Projection );g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb, 0, 0 );

  

?

?

轉載于:https://www.cnblogs.com/OctoptusLian/p/9748161.html

總結

以上是生活随笔為你收集整理的Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 苏晴忘穿内裤坐公交车被揉到视频 | 四虎影视www在线播放 | 免费的黄色一级片 | 日操干| 国产精品日韩电影 | 被室友玩屁股(h)男男 | 免费观看久久久 | 日韩一级片免费 | 色噜噜狠狠一区二区三区果冻 | 黄色三级网站 | 日韩香蕉网 | 福利视频免费看 | 天天综合av | 极品美女被c | 一级毛片黄片 | 中文字幕在线观看视频一区二区 | 女生高潮视频在线观看 | 麻豆精品国产传媒mv男同 | 日韩精品高清在线 | 91天天干| 男生吃小头头的视频 | 久久亚洲aⅴ无码精品 | 久久综合亚洲精品 | 影音先锋二区 | 在线观看福利电影 | 亚洲狠狠爱 | 最近免费中文字幕中文高清百度 | 999zyz玖玖资源站永久 | 老外一级黄色片 | 成人精品一区二区 | 玖玖在线播放 | 亚洲久久视频 | 俄罗斯丰满熟妇hd | 操操网站 | jizz中国女人高潮 | 香蕉污视频 | 超碰91在线| 无码人妻丰满熟妇区bbbbxxxx | 进去里在线观看 | 成人国产三级 | 少妇高潮一区二区三区喷水 | 久久精品综合视频 | 欧美一区网站 | 日韩理论片在线观看 | 日韩精品在线观看一区二区三区 | 疯狂伦交 | 日本三级视频在线 | 亚洲综合自拍偷拍 | 日韩人妻无码精品久久久不卡 | 中文字幕最新 | 黄色大片在线免费观看 | 国内成人自拍视频 | 国产熟妇乱xxxxx大屁股网 | 国产黄色免费 | 日韩激情片 | 中文字幕在线观看日韩 | 国产网站黄 | 成人免费一区二区 | 成人美女在线观看 | 久久成人资源 | 中国免费一级片 | 久久99国产精品成人 | 欧美人与性囗牲恔配 | 免费三级大片 | 五月婷婷天堂 | xvideos成人免费视频 | 成人在线观看黄色 | 一区二区三区色 | 日韩精品一二 | 国产18页 | 欧美精品性生活 | 青娱乐在线播放 | 精品不卡视频 | 日韩激情电影在线 | 国产又粗又长又大 | 国产日产欧美一区二区 | 青青青视频在线 | 精品国产a线一区二区三区东京热 | 国产午夜性春猛交ⅹxxx | www黄色网 | 黄色av一级 | 情侣自拍av | 亚洲涩涩图 | 91视频这里只有精品 | 免费黄网在线看 | 亚洲h网站 | 不卡国产在线 | 国产精品国产三级国产专区52 | 久久成人免费视频 | 在线观看羞羞漫画 | www九九九| 亚洲成人观看 | 亚洲精品在线视频 | 日本公妇乱偷中文字幕 | 99自拍偷拍 | 青娱乐国产在线 | 隣の若妻さん波多野结衣 | 四虎影视网 | 黄色一级片在线 |