投影紋理對映(Projective Texture Mapping)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
http://blog.csdn.net/xiajun07061225/article/details/7672635
一、紋理投影對映簡介
投影紋理對映用於對映一個紋理到物體上,好比將幻燈片投影到牆上一樣。
投影紋理對映經常在一些陰影演算法以及體繪製(Volume Rendering)演算法中用到。嚴格的說,只要涉及到“紋理實時和空間頂點對應”,通常都要用到投影紋理對映技術。
下面是一個紋理投影對映的例項效果圖:
圖一 紋理投影對映效果圖
二、紋理投影對映優點
1、將紋理與空間頂點實時對應,不需要預先在建模軟體中生成紋理座標。
2、使用投影對映時,可以有效避免紋理扭曲現象。
下面圖顯示了投影紋理對映和普通紋理貼圖的效果對比:
圖二 投影空間插值和真實空間插值對比
三、原理以及實現步驟
為了把紋理投影到一個表面上,我們所要做的是根據表面點的位置和投影源來確定紋理座標。我們可以把投影源攝像成一個攝像機,位於場景的某處。就像OpenGL中定義一個攝像機一樣,我們這樣的一個座標系統(不放稱之為投影座標系統):中心點位於投影源所在的位置,檢視矩陣V將座標轉化到投影座標系統,透視投影矩陣P將視景體轉換為一個大小為2的立方體,其中心點位於投影座標系統的原點。將這兩個矩陣疊加在一起,再加上縮放和平移的變換矩陣(用於把剛才得到的大小為2的立方體變為大小為1,而且中心點位於(0.5,0.5,0.5))。我們就得到了下面的變換矩陣:
圖三 投影紋理對映座標變換矩陣
需要注意的是:這樣得到的座標是沒有被歸一化的,在訪問紋理之前需要將各分量除以其w分量。
上述的矩陣P、V均可以通過攝像機的位置、攝影角度求得。
投影紋理對映通常包含了兩個內容:紋理座標被分配到頂點上的方式以及圖元光柵化階段它們的計算方式。我們經常把紋理對映看成將紋理影象應用到圖元上--事實確實是這樣,但是其中包含著很多數學計算。
光柵化的一些細節
當進行投影紋理對映時,我們使用齊次(homogeneous)紋理座標,或者叫位於投影空間的座標。當進行非投影紋理對映時,我們使用real紋理座標,或者叫位於real space的座標。對於2D紋理投影對映,3分量的齊次座標(s,t,q)被在圖元以及每個片斷上插值,插值後的齊次座標被投影到real 2D紋理座標(s/q,t/q),然後訪問紋理。而對於非投影的2D紋理對映,2分量的real座標(s,t)被在圖元上插值,然後直接用於訪問紋理影象。
這樣也就導致了前面圖二中的插值效果上的差別。
分配齊次紋理座標
上述關於光柵化的討論基於的一個假設是每個頂點已經被分配了齊次紋理座標。作為應用程式編寫者,這是我們所要做的工作。下面討論如何在OpenGL中實現它。
設想紋理是從一個投影儀投影到一個場景上的。這個投影儀和攝像機有很多共同屬性:它有檢視變換(將world space 座標變換到projector space或者叫eye space),有投影變換(將projector space視體對映到剪下座標)。最後,我們實施縮放和偏移操作來進行範圍對映。對於攝像機,x和y是依據當前的視口設定進行對映,z是依據當前的深度範圍進行對映。對於投影紋理對映,而範圍對映一般是把每個座標對映到區間[0,1]內。
下圖對比了兩種變換:應用到頂點座標用於計算window space位置座標的變換和計算投影紋理座標的變換。
圖四 應用到world space頂點座標上的用於計算window space座標的攝像機變換和應用到world space頂點座標上用於計算投影紋理座標的投影變換很相似
分配紋理座標很重要的一方面是利用OpenGL的紋理座標生成的功能。它是根據頂點的其他屬性來產生紋理座標。比如GL_OBJECT_LINEAR和GL_EYE_LINEAR,在object space和eyes pace內的頂點座標分別被用來產生紋理座標。另外一些方式使用了其他補貼的屬性。GL_SPEREMAP和GL_REFLECTION_MAP使用了eye space頂點座標和法線。GL_NORMAL_MAP則是根據法線向量產生紋理座標。
OpenGL對於每個座標方向可以使用不同的產生紋理座標的方法。比如你可以在S方向採用GL_SPHERE_MAP,在T上採用GL_REFLECTION_MAP,在R上採用GL_OBJECT_LINEAR,Q上採用GL_EYE_LINEAR。不過這種特性並不是很有用,我們通常採用相同的方式。
下面以一個實際的例子來說明如何實現投影紋理對映(OpenGL+GLSL),其效果及開頭所給出的圖一。圖中繪製了一個茶壺,然後從一個方向將一幅紋理影象投影到茶壺上面。
頂點著色器projtex.vs:
#version 400
[cpp] view plain copy print ?- layout (location = 0) in vec3 VertexPosition;
- layout (location = 1) in vec3 VertexNormal;
- out vec3 EyeNormal; // Normal in eye coordinates
- out vec4 EyePosition; // Position in eye coordinates
- out vec4 ProjTexCoord;
- uniform mat4 ProjectorMatrix;//用於計算投影紋理對映的矩陣
- uniform vec3 WorldCameraPosition;
- uniform mat4 ModelViewMatrix;//模型檢視矩陣
- uniform mat4 ModelMatrix;//模型變換矩陣
- uniform mat3 NormalMatrix;//法線變換矩陣
- uniform mat4 ProjectionMatrix;//投影變換矩陣
- uniform mat4 MVP;//模型檢視變換矩陣
- void main()
- {
- vec4 pos4 = vec4(VertexPosition,1.0);
- EyeNormal = normalize(NormalMatrix * VertexNormal);
- EyePosition = ModelViewMatrix * pos4;
- ProjTexCoord = ProjectorMatrix * (ModelMatrix * pos4);
- gl_Position = MVP * pos4;
- }
layout (location = 0) in vec3 VertexPosition;layout (location = 1) in vec3 VertexNormal;out vec3 EyeNormal; // Normal in eye coordinatesout vec4 EyePosition; // Position in eye coordinatesout vec4 ProjTexCoord;uniform mat4 ProjectorMatrix;//用於計算投影紋理對映的矩陣uniform vec3 WorldCameraPosition;uniform mat4 ModelViewMatrix;//模型檢視矩陣uniform mat4 ModelMatrix;//模型變換矩陣uniform mat3 NormalMatrix;//法線變換矩陣uniform mat4 ProjectionMatrix;//投影變換矩陣uniform mat4 MVP;//模型檢視變換矩陣void main(){ vec4 pos4 = vec4(VertexPosition,1.0); EyeNormal = normalize(NormalMatrix * VertexNormal); EyePosition = ModelViewMatrix * pos4; ProjTexCoord = ProjectorMatrix * (ModelMatrix * pos4); gl_Position = MVP * pos4;}
上面的程式碼前兩行是將法線和頂點座標變換到eye space。
然後是計算投影紋理座標:先將位於object space的座標變換到world space,然後通過左乘紋理投影矩陣變換計算出紋理投影座標。
最後計算內建的gl_Position即剪切平面座標。
片斷著色器projtex.fs(下面只列出一部分):
[cpp] view plain copy print ?- #version 400
- in vec3 EyeNormal; // Normal in eye coordinates
- in vec4 EyePosition; // Position in eye coordinates
- in vec4 ProjTexCoord;
- uniform sampler2D ProjectorTex;
- layout( location = 0 ) out vec4 FragColor;
- void main() {
- vec3 color = phongModel(vec3(EyePosition), EyeNormal);
- vec4 projTexColor = vec4(0.0);
- if( ProjTexCoord.z > 0.0 )
- //textureProj:紋理座標各分量會除以最後一個分量
- projTexColor = textureProj( ProjectorTex, ProjTexCoord );
- FragColor = vec4(color,1.0) + projTexColor * 0.5;
- }
#version 400in vec3 EyeNormal; // Normal in eye coordinatesin vec4 EyePosition; // Position in eye coordinatesin vec4 ProjTexCoord;uniform sampler2D ProjectorTex;layout( location = 0 ) out vec4 FragColor;void main() { vec3 color = phongModel(vec3(EyePosition), EyeNormal); vec4 projTexColor = vec4(0.0); if( ProjTexCoord.z > 0.0 ) //textureProj:紋理座標各分量會除以最後一個分量 projTexColor = textureProj( ProjectorTex, ProjTexCoord ); FragColor = vec4(color,1.0) + projTexColor * 0.5;}
函式phongModel是計算phong光照模型的。
注意其中的textureProj函式,它專門用於投影紋理訪問的。它的紋理座標的各分量會除以最後一個分量,然後才訪問紋理。
在這個例子中,我們假設投影儀位於(2.0,5.0,5.0),朝向是(-2.0,-4.0,0.0),方向(0.0,1.0,0.0)是向上的。我們採用了一個外部庫GLM庫來根據投影儀的這些資訊計算出各個變換矩陣,程式碼如下:
[cpp] view plain copy print ?- vec3 projPos = vec3(2.0f,5.0f,5.0f);
- vec3 projAt = vec3(-2.0f,-4.0f,0.0f);
- vec3 projUp = vec3(0.0f,1.0f,0.0f);
- mat4 projView = glm::lookAt(projPos, projAt, projUp);
- mat4 projProj = glm::perspective(30.0f, 1.0f, 0.2f, 1000.0f);
- mat4 projScaleTrans = glm::translate(vec3(0.5f)) * glm::scale(vec3(0.5f));
- prog.setUniform("ProjectorMatrix", projScaleTrans * projProj * projView);
vec3 projPos = vec3(2.0f,5.0f,5.0f); vec3 projAt = vec3(-2.0f,-4.0f,0.0f); vec3 projUp = vec3(0.0f,1.0f,0.0f); mat4 projView = glm::lookAt(projPos, projAt, projUp); mat4 projProj = glm::perspective(30.0f, 1.0f, 0.2f, 1000.0f); mat4 projScaleTrans = glm::translate(vec3(0.5f)) * glm::scale(vec3(0.5f)); prog.setUniform("ProjectorMatrix", projScaleTrans * projProj * projView);
給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow
你好! 這是你第一次使用 **Markdown編輯器** 所展示的歡迎頁。如果你想學習如何使用Markdown編輯器, 可以仔細閱讀這篇文章,瞭解一下Markdown的基本語法知識。新的改變
我們對Markdown編輯器進行了一些功能拓展與語法支援,除了標準的Markdown編輯器功能,我們增加了如下幾點新功能,幫助你用它寫部落格:
- 全新的介面設計 ,將會帶來全新的寫作體驗;
- 在創作中心設定你喜愛的程式碼高亮樣式,Markdown 將程式碼片顯示選擇的高亮樣式 進行展示;
- 增加了 圖片拖拽 功能,你可以將本地的圖片直接拖拽到編輯區域直接展示;
- 全新的 KaTeX數學公式 語法;
- 增加了支援甘特圖的mermaid語法1 功能;
- 增加了 多螢幕編輯 Markdown文章功能;
- 增加了 焦點寫作模式、預覽模式、簡潔寫作模式、左右區域同步滾輪設定 等功能,功能按鈕位於編輯區域與預覽區域中間;
- 增加了 檢查列表 功能。
功能快捷鍵
撤銷:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜體:Ctrl/Command + I
標題:Ctrl/Command + Shift + H
無序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
檢查列表:Ctrl/Command + Shift + C
插入程式碼:Ctrl/Command + Shift + K
插入連結:Ctrl/Command + Shift + L
插入圖片:Ctrl/Command + Shift + G
合理的建立標題,有助於目錄的生成
直接輸入1次#,並按下space後,將生成1級標題。
輸入2次#,並按下space後,將生成2級標題。
以此類推,我們支援6級標題。有助於使用TOC
語法後生成一個完美的目錄。
如何改變文字的樣式
強調文字 強調文字
加粗文字 加粗文字
標記文字
刪除文字
引用文字
H2O is是液體。
210 運算結果是 1024.
插入連結與圖片
連結: link.
圖片:
帶尺寸的圖片:
當然,我們為了讓使用者更加便捷,我們增加了圖片拖拽功能。
如何插入一段漂亮的程式碼片
去部落格設定頁面,選擇一款你喜歡的程式碼片高亮樣式,下面展示同樣高亮的 程式碼片
.
// An highlighted block var foo = 'bar';
生成一個適合你的列表
- 專案
- 專案
- 專案
- 專案
- 專案1
- 專案2
- 專案3
- 計劃任務
- 完成任務
建立一個表格
一個簡單的表格是這麼建立的:
專案 | Value |
---|---|
電腦 | $1600 |
手機 | $12 |
導管 | $1 |
設定內容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文字居中 | 第二列文字居右 | 第三列文字居左 |
SmartyPants
SmartyPants將ASCII標點字元轉換為“智慧”印刷標點HTML實體。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' |
‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" |
“Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash |
– is en-dash, — is em-dash |
建立一個自定義列表
- Markdown
- Text-to- HTML conversion tool
- Authors
- John
- Luke
如何建立一個註腳
一個具有註腳的文字。2
註釋也是必不可少的
Markdown將文字轉換為 HTML。
KaTeX數學公式
您可以使用渲染LaTeX數學表示式 KaTeX:
Gamma公式展示 是通過尤拉積分
你可以找到更多關於的資訊 LaTeX 數學表示式here.
新的甘特圖功能,豐富你的文章
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section 現有任務
已完成 :done, des1, 2014-01-06,2014-01-08
進行中 :active, des2, 2014-01-09, 3d
計劃一 : des3, after des2, 5d
計劃二 : des4, after des3, 5d
- 關於 甘特圖 語法,參考 這兒,
UML 圖表
可以使用UML圖表進行渲染。 Mermaid. 例如下面產生的一個序列圖::
這將產生一個流程圖。:
- 關於 Mermaid 語法,參考 這兒,
FLowchart流程圖
我們依舊會支援flowchart的流程圖:
- 關於 Flowchart流程圖 語法,參考 這兒.
匯出與匯入
匯出
如果你想嘗試使用此編輯器, 你可以在此篇文章任意編輯。當你完成了一篇文章的寫作, 在上方工具欄找到 文章匯出 ,生成一個.md檔案或者.html檔案進行本地儲存。
匯入
如果你想載入一篇你寫過的.md檔案或者.html檔案,在上方工具欄可以選擇匯入功能進行對應副檔名的檔案匯入,
繼續你的創作。
註腳的解釋 ↩︎