2010-09-01 53 views

回答

5

OK,這裏去...

你點A,B和C,其中的每一個具有座標x,y和z。正如馬蒂亞斯所說,你需要法線的長度,這樣就可以計算出你的點與法線原點之間的向量與法線本身所成的角度。它可以幫助你認識到你的形象對我們的計算而言是誤導性的;法線(藍線)應該從三角形的一個頂點發出。要將你的點轉化爲矢量,它必須到某個地方,並且你只知道頂點的點(當你可以插入三角形內的任何點時,頂點着色的整個點不必)。

無論如何,第一步是把你的Point3Ds成Vector3Ds。簡單地通過獲取每個起點和終點的座標之間的差異來實現這一點。使用一個點作爲兩個向量的起點,其他兩個點作爲每個點的目的地。因此,如果A是您的原點,則從B中減去A,然後從C中減去A.現在您有一個向量,它描述X,Y和Z軸從A點到B點的運動幅度,同樣從A到C.值得注意的是,一個理論向量沒有自己的起點;要到達B點,您必須從A開始並應用該向量。

的System.Windows.Media.Media3D命名空間有可以使用的Vector3D結構,並輕而易舉地不夠,三維點在同一個命名空間中有一個返回的Vector3D減法()函數:

Vector3D vectorAB = pointB.Subtract(pointA); 
Vector3D vectorAC = pointC.Subtract(pointA); 

現在,法線是兩個向量的叉積。使用下面的公式:

V1 X V2 = [Y1 * Z2 - Y2 * Z1,Z1 * X2 - Z2 * X1,X1 * Y2 - X2 * Y1]

這是基於矩陣數學你不併不一定要知道實施它。矩陣中的三項是法向量的X,Y和Z。幸運的是,如果你使用的Media3D命名空間,則將對Vector3D結構具有雙重交叉()方法會爲你做到這一點:

Vector3D vectorNormal = Vector3D.CrossProduct(vectorAB, vectorAC); 

現在,你需要第三個向量,LightPoint和A之間:

Vector3D vectorLight = PointA.Subtract(LightPoint); 

這是光線從你的光源到達PointA的方向。

現在,找到它們之間的角度,你計算這兩個點積和這兩個長度:

| V | =開方(X^2 + Y^2 + Z^2)

V1 * V2 = X1 * X2 + Y1 * Y2 + Z1 * Z2

或者,如果你使用Media3D,的Vector3D有長度屬性和DotProduct靜態方法:

double lengthLight = vectorLight.Length; 
double lengthNormal = vectorNormal.Length; 
double dotProduct = Vector3D.DotProduct(vectorNormal, vectorLight); 

最後,式Matias的提及:

V1 * V2 = | V1 || V2 | COS(THETA)

重新排列而代變量名:

double theta = arccos(dotProduct/(lengthNormal*lengthLight)) 

或者,如果你足夠聰明才能使用Media3D對象,忘記所有的長度和積東西:

double theta = Vector3D.AngleBetween(vectorNormal, vectorLight); 

西塔現在在度的角度。如果你需要這種方式,乘以數量2(pi)/ 360乘以得到弧度。

故事的寓意是,使用框架給你的東西,除非你有充分的理由不這樣做;使用Media3D命名空間,所有的向量代數消失,你可以找到在5易於讀取線[我編輯的這一點,我將使用的代碼 - 伊恩]答案:

Vector3D vectorAB = Point3D.Subtract(pointB, pointA); 
Vector3D vectorAC = Point3D.Subtract(pointC, pointA); 
Vector3D vectorNormal = Vector3D.CrossProduct(vectorAB, vectorAC); 
Vector3D vectorLight = Point3D.Subtract(pointA, LightPoint); 

double lengthLight = light.Length; 
double lengthNormal = norm.Length; 
double dotProduct = Vector3D.DotProduct(norm, light); 
double theta = Math.Acos(dotProduct/(lengthNormal * lengthLight)); 

// Convert to intensity between 0..255 range for 'Color.FromArgb(... 
//int intensity = (120 + (Math.Cos(theta) * 90)); 
+0

+1謝謝你的一個很好的答案! System.Windows.Media.Media3D是框架4 ...看起來像我升級:) – 2010-09-02 08:38:41

+0

它也在3.5。您可能必須將應用程序設置爲WPF應用程序,我不確定。 – KeithS 2010-09-02 14:50:11

1

要獲得的法線矢量,計算P2之間的叉積 - P1和P3 - P1。

要得到的角度,使用正常和lightPoint之間的點積。記住點(a,b)= | a || b | * cos(theta),所以既然你可以計算兩者的長度,你可以得到theta(他們之間的角度)。

+0

感謝您的回答,我只是有問題把它變成代碼:) – 2010-09-01 21:13:57

0

只是一帶而過相關,但大多數圖形系統也允許表面法線插值,其中每個頂點都有一個相關的法線。在給定的U,V處的有效法線將從頂點法線插值。這樣就可以在光照條件下獲得更平滑的陰影和更好的「曲率」表示,而不必依賴大量的三角形。許多系統通過「凹凸映射」來做類似的技巧來在法線中引入擾動,並獲得紋理感而不用對單個小面進行建模。

現在您可以計算插值法線和光線矢量之間的角度,如其他人已經描述的那樣。

另一個關注點是考慮您是否有環境光源。如果您可以假設點光源無限遠(對於類似地球這樣的小表面上的直射陽光之類的光源實際上是這樣),則可以節省計算矢量差的所有麻煩,並且簡單地假定光的入射角是不變。現在你有一個恆定的光矢量爲你的點積。