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

這個(gè)圖畫(huà)的很不好,
一個(gè)點(diǎn)旋轉(zhuǎn)到另一個(gè)點(diǎn)
x=rcosb
y=rsinb
轉(zhuǎn)過(guò)角a后,x1=rcos(a+b) y1=rsin(a+b);
得到 x1=rcosbcosa-rsinbsina? 1=rsinbcosa+rsinacosb
最后
x1=xcosb-ysinb
y1=xsinb+ycosb
沿著其他軸轉(zhuǎn)一樣。
所以又了以上rotateX的計(jì)算方法。
2.ViewWindow
這個(gè)類具備了視圖窗口的功能,并且提供投影。
再議3D的數(shù)學(xué):
3D圖形的生成就是? 三維圖形到鏡頭的連接線或向量,這些連接線經(jīng)過(guò)視圖窗口,在視圖窗口成像。鏡頭離試圖窗口越近,成像效果越大,這是三角問(wèn)題。這個(gè)角度可以看做鏡頭到試圖窗口的法線向量與連線的夾角。這個(gè)成像與屏幕坐標(biāo)不一致,還要換算為屏幕坐標(biāo)。
來(lái)看一下。
public void project(Vector3D v) { //投影到視圖窗口 v.x = distanceToCamera * v.x / -v.z; v.y = distanceToCamera * v.y / -v.z; //轉(zhuǎn)換為屏幕坐標(biāo) v.x = convertFromViewXToScreenX(v.x); v.y = convertFromViewYToScreenY(v.y); }
這里形參 v 是具體的三維物體
改變其x和y的值,是通過(guò)三角函數(shù)等比例關(guān)系進(jìn)行計(jì)算
distanceToCamera是視圖窗口到鏡頭的法線長(zhǎng)度
經(jīng)過(guò)重新復(fù)制的v.x和v.y然后換算為屏幕坐標(biāo)。
convertFromViewXToScreenX方法見(jiàn)上以篇
z是深度坐標(biāo),忽略計(jì)算。
多邊形問(wèn)題
多邊形就是一堆頂點(diǎn)
3.Polygon3D
這個(gè)類將多邊形表示成一堆頂點(diǎn)。通過(guò)Vector3D[] 存放
看看其中幾個(gè)方法
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; }
這是計(jì)算法線。法線的計(jì)算是通過(guò)求兩個(gè)向量的交積得到。至于向量交積的計(jì)算網(wǎng)上有。
法線有方向,方向是通過(guò)求點(diǎn)積得到。
為什么需要法線向量?
通過(guò)法線向量(帶方向的)與鏡頭與視圖窗口垂直線 的夾角來(lái)判斷三維物體是否正對(duì)鏡頭
如果是銳角表示正對(duì),否則是背對(duì)。
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; } }
因?yàn)槌醮芜\(yùn)行數(shù)組初始化長(zhǎng)度不夠,會(huì)引起數(shù)組越界,這個(gè)方法保證多邊形的容量可以容納多邊形頂點(diǎn)個(gè)數(shù)
public void project(ViewWindow view) { for (int i=0; i<numVertices; i++) { view.project(v[i]); } }
將多邊形投影到視圖窗口。
4.Transform3D
這個(gè)類主要表示旋轉(zhuǎn)和平移,提供了三角函數(shù)算法。通過(guò)這個(gè)類計(jì)算旋轉(zhuǎn)角度后的三角函數(shù)值,并調(diào)用Vector3D的旋轉(zhuǎn)方法。
還有一個(gè)成員Vector3D location,代表了它作用于的Vector3D.
5.My3DTest1
這個(gè)類的事件監(jiān)聽(tīng)就不再做解釋了。
定義了幾個(gè)成員
private Transform3D myTransform = new Transform3D(0,0,-500); private Polygon3D transformedPolygon = new Polygon3D(); private ViewWindow viewWindow;
下面會(huì)提到。
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軸旋轉(zhuǎn)
treeTransform.rotateAngleY(0.002f*elapsedTime);
經(jīng)過(guò)計(jì)算得到了cosAngleY 和 sinAngleY兩個(gè)三角函數(shù)值
看關(guān)鍵的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);
這里就是進(jìn)行旋轉(zhuǎn)的功能,我進(jìn)入方法內(nèi)部說(shuō)明一下。
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()); }
這里就是我前面說(shuō)道的Vector3D里面的旋轉(zhuǎn)函數(shù)方程了。經(jīng)過(guò)旋轉(zhuǎn)計(jì)算后,每一個(gè)頂點(diǎn)都會(huì)發(fā)生坐標(biāo)的轉(zhuǎn)移,也就實(shí)現(xiàn)了旋轉(zhuǎn)。
2.add(myTransform.getLocation());
public void add(Vector3D u) { for (int i=0; i<numVertices; i++) { v[i].add(u); } }
3. transformedPolygon.project(viewWindow);
投影到視圖窗口
最后程序循環(huán)連線畫(huà)出了三維多邊形,并填充了顏色。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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