本篇主要對java處理三維圖形基本的知識做一下復習。有些地方上篇沒仔細討論。
涉及到上一篇的所有類,做一下規整,還有新的類應用描述。
1.Vector3D
這個類描述三維向量。三維向量就是(x,y,z)一個空間點,或從(0,0,0)到(x,y,z)的向量。
提供了向量加 向量減 向量乘 和向量除
還有返回了向量的長度? 空間直線的長度計算公式:根號下(x+-x1)的平方+(y+-y1)+(z+-z1)的平方
區長度方法為
旋轉,比如沿x軸旋轉
因為沿x軸旋轉,x的值忽略,重新對y,z賦值。
這里的形參是預先計算出來的值。
至于這個 float newY = y*cosAngle - z*sinAngle公式做如下解釋
這個圖畫的很不好,
一個點旋轉到另一個點
x=rcosb
y=rsinb
轉過角a后,x1=rcos(a+b) y1=rsin(a+b);
得到 x1=rcosbcosa-rsinbsina? 1=rsinbcosa+rsinacosb
最后
x1=xcosb-ysinb
y1=xsinb+ycosb
沿著其他軸轉一樣。
所以又了以上rotateX的計算方法。
2.ViewWindow
這個類具備了視圖窗口的功能,并且提供投影。
再議3D的數學:
3D圖形的生成就是? 三維圖形到鏡頭的連接線或向量,這些連接線經過視圖窗口,在視圖窗口成像。鏡頭離試圖窗口越近,成像效果越大,這是三角問題。這個角度可以看做鏡頭到試圖窗口的法線向量與連線的夾角。這個成像與屏幕坐標不一致,還要換算為屏幕坐標。
來看一下。
這里形參 v 是具體的三維物體
改變其x和y的值,是通過三角函數等比例關系進行計算
distanceToCamera是視圖窗口到鏡頭的法線長度
經過重新復制的v.x和v.y然后換算為屏幕坐標。
convertFromViewXToScreenX方法見上以篇
z是深度坐標,忽略計算。
多邊形問題
多邊形就是一堆頂點
3.Polygon3D
這個類將多邊形表示成一堆頂點。通過Vector3D[] 存放
看看其中幾個方法
這是計算法線。法線的計算是通過求兩個向量的交積得到。至于向量交積的計算網上有。
法線有方向,方向是通過求點積得到。
為什么需要法線向量?
通過法線向量(帶方向的)與鏡頭與視圖窗口垂直線 的夾角來判斷三維物體是否正對鏡頭
如果是銳角表示正對,否則是背對。
因為初次運行數組初始化長度不夠,會引起數組越界,這個方法保證多邊形的容量可以容納多邊形頂點個數
將多邊形投影到視圖窗口。
4.Transform3D
這個類主要表示旋轉和平移,提供了三角函數算法。通過這個類計算旋轉角度后的三角函數值,并調用Vector3D的旋轉方法。
還有一個成員Vector3D location,代表了它作用于的Vector3D.
5.My3DTest1
這個類的事件監聽就不再做解釋了。
定義了幾個成員
下面會提到。
這里是沿y軸旋轉
treeTransform.rotateAngleY(0.002f*elapsedTime);
經過計算得到了cosAngleY 和 sinAngleY兩個三角函數值
看關鍵的draw方法中的
trandformAndDraw(g, p);
??????? transformedPolygon.setTo(poly);
??????? transformedPolygon.add(myTransform);
??????? transformedPolygon.project(viewWindow);
這三句代碼很重要。
? transformedPolygon.setTo(poly);
將多邊形中的vector全都set到transformedPloygon中
transformedPolygon.add(myTransform);
這里就是進行旋轉的功能,我進入方法內部說明一下。
add方法做了兩件事情:
1.addRotation(myTransform);
這里就是我前面說道的Vector3D里面的旋轉函數方程了。經過旋轉計算后,每一個頂點都會發生坐標的轉移,也就實現了旋轉。
2.add(myTransform.getLocation());
3. transformedPolygon.project(viewWindow);
投影到視圖窗口
最后程序循環連線畫出了三維多邊形,并填充了顏色。
涉及到上一篇的所有類,做一下規整,還有新的類應用描述。
1.Vector3D
這個類描述三維向量。三維向量就是(x,y,z)一個空間點,或從(0,0,0)到(x,y,z)的向量。
提供了向量加 向量減 向量乘 和向量除
還有返回了向量的長度? 空間直線的長度計算公式:根號下(x+-x1)的平方+(y+-y1)+(z+-z1)的平方
區長度方法為
public float length() { return (float)Math.sqrt(x*x + y*y + z*z); }
旋轉,比如沿x軸旋轉
public void rotateX(float cosAngle, float sinAngle) { float newY = y*cosAngle - z*sinAngle; float newZ = y*sinAngle + z*cosAngle; y = newY; z = newZ; }
因為沿x軸旋轉,x的值忽略,重新對y,z賦值。
這里的形參是預先計算出來的值。
至于這個 float newY = y*cosAngle - z*sinAngle公式做如下解釋

這個圖畫的很不好,
一個點旋轉到另一個點
x=rcosb
y=rsinb
轉過角a后,x1=rcos(a+b) y1=rsin(a+b);
得到 x1=rcosbcosa-rsinbsina? 1=rsinbcosa+rsinacosb
最后
x1=xcosb-ysinb
y1=xsinb+ycosb
沿著其他軸轉一樣。
所以又了以上rotateX的計算方法。
2.ViewWindow
這個類具備了視圖窗口的功能,并且提供投影。
再議3D的數學:
3D圖形的生成就是? 三維圖形到鏡頭的連接線或向量,這些連接線經過視圖窗口,在視圖窗口成像。鏡頭離試圖窗口越近,成像效果越大,這是三角問題。這個角度可以看做鏡頭到試圖窗口的法線向量與連線的夾角。這個成像與屏幕坐標不一致,還要換算為屏幕坐標。
來看一下。
public void project(Vector3D v) { //投影到視圖窗口 v.x = distanceToCamera * v.x / -v.z; v.y = distanceToCamera * v.y / -v.z; //轉換為屏幕坐標 v.x = convertFromViewXToScreenX(v.x); v.y = convertFromViewYToScreenY(v.y); }
這里形參 v 是具體的三維物體
改變其x和y的值,是通過三角函數等比例關系進行計算
distanceToCamera是視圖窗口到鏡頭的法線長度
經過重新復制的v.x和v.y然后換算為屏幕坐標。
convertFromViewXToScreenX方法見上以篇
z是深度坐標,忽略計算。
多邊形問題
多邊形就是一堆頂點
3.Polygon3D
這個類將多邊形表示成一堆頂點。通過Vector3D[] 存放
看看其中幾個方法
public Polygon3D(Vector3D[] vertices) { this.v = vertices; numVertices = vertices.length; calcNormal(); } public Vector3D calcNormal() { if (normal == null) { normal = new Vector3D(); } temp1.setTo(v[2]); temp1.subtract(v[1]); temp2.setTo(v[0]); temp2.subtract(v[1]); normal.setToCrossProduct(temp1, temp2); normal.normalize(); return normal; }
這是計算法線。法線的計算是通過求兩個向量的交積得到。至于向量交積的計算網上有。
法線有方向,方向是通過求點積得到。
為什么需要法線向量?
通過法線向量(帶方向的)與鏡頭與視圖窗口垂直線 的夾角來判斷三維物體是否正對鏡頭
如果是銳角表示正對,否則是背對。
public boolean isFacing(Vector3D u) { temp1.setTo(u); temp1.subtract(v[0]); return (normal.getDotProduct(temp1) >= 0); }
public void ensureCapacity(int length) { if (v.length < length) { Vector3D[] newV = new Vector3D[length]; System.arraycopy(v,0,newV,0,v.length); for (int i=v.length; i<newV.length; i++) { newV[i] = new Vector3D(); } v = newV; } }
因為初次運行數組初始化長度不夠,會引起數組越界,這個方法保證多邊形的容量可以容納多邊形頂點個數
public void project(ViewWindow view) { for (int i=0; i<numVertices; i++) { view.project(v[i]); } }
將多邊形投影到視圖窗口。
4.Transform3D
這個類主要表示旋轉和平移,提供了三角函數算法。通過這個類計算旋轉角度后的三角函數值,并調用Vector3D的旋轉方法。
還有一個成員Vector3D location,代表了它作用于的Vector3D.
5.My3DTest1
這個類的事件監聽就不再做解釋了。
定義了幾個成員
private Transform3D myTransform = new Transform3D(0,0,-500); private Polygon3D transformedPolygon = new Polygon3D(); private ViewWindow viewWindow;
下面會提到。
public void update(long elapsedTime) { if (exit.isPressed()) { stop(); return; } elapsedTime = Math.min(elapsedTime, 100); treeTransform.rotateAngleY(0.002f*elapsedTime); if (zoomIn.isPressed()) { treeTransform.getLocation().z += 0.5f*elapsedTime; } if (zoomOut.isPressed()) { treeTransform.getLocation().z -= 0.5f*elapsedTime; } }
這里是沿y軸旋轉
treeTransform.rotateAngleY(0.002f*elapsedTime);
經過計算得到了cosAngleY 和 sinAngleY兩個三角函數值
看關鍵的draw方法中的
trandformAndDraw(g, p);
private void trandformAndDraw(Graphics2D g, Polygon3D poly) { transformedPolygon.setTo(poly); transformedPolygon.add(myTransform); transformedPolygon.project(viewWindow); GeneralPath path = new GeneralPath(); Vector3D v = transformedPolygon.getVertex(0); path.moveTo(v.x, v.y); for (int i=1; i<transformedPolygon.getNumVertices(); i++) { v = transformedPolygon.getVertex(i); path.lineTo(v.x, v.y); } g.setColor(Color.red); g.fill(path); }
??????? transformedPolygon.setTo(poly);
??????? transformedPolygon.add(myTransform);
??????? transformedPolygon.project(viewWindow);
這三句代碼很重要。
? transformedPolygon.setTo(poly);
將多邊形中的vector全都set到transformedPloygon中
transformedPolygon.add(myTransform);
這里就是進行旋轉的功能,我進入方法內部說明一下。
add方法做了兩件事情:
1.addRotation(myTransform);
public void addRotation(Transform3D myTransform) { for (int i=0; i<numVertices; i++) { v[i].addRotation(myTransform); } normal.addRotation(myTransform); } public void addRotation(Transform3D myTransform) { // TODO Auto-generated method stub rotateX(myTransform.getCosAngleX(), myTransform.getSinAngleX()); rotateZ(myTransform.getCosAngleZ(), myTransform.getSinAngleZ()); rotateY(myTransform.getCosAngleY(), myTransform.getSinAngleY()); }
這里就是我前面說道的Vector3D里面的旋轉函數方程了。經過旋轉計算后,每一個頂點都會發生坐標的轉移,也就實現了旋轉。
2.add(myTransform.getLocation());
public void add(Vector3D u) { for (int i=0; i<numVertices; i++) { v[i].add(u); } }
3. transformedPolygon.project(viewWindow);
投影到視圖窗口
最后程序循環連線畫出了三維多邊形,并填充了顏色。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
