本篇主要對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元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

