浏览 4913 次
锁定老帖子 主题:java 游戏编程 (八)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-06-18
最后修改:2009-06-19
多边形造型(polygon modeling):将虚拟三维时间看做平面多边形。 光束跟踪(ray tracing):建立光束模型,简历眼到光源的模型。 java中常见的利用三维加速卡方法:Java3D和OpenGL关联。 Java3D核心是用OpenGL或DirectX绘制 现在我们用轻量级三维多边形绘制器,暂不用Java3D api 需要数学方面知识,但都很浅。 先考虑一个案例:我们构造一个四边形,然后它可以任意围绕x轴或y轴旋转,并且可以放大缩小。当然也可以围绕Z轴,只不过这样感觉不到3D效果。 解释一下这里的x,y,z。 在二维图形中,如果和屏幕相同的二维坐标,原点在屏幕左上方,x从左往右,y从上往下. 在三维图形中,x向右,y向上,z向里(感觉就是往屏幕里,远离人的方向) 我们从最终测试类出发,先构思出这个类应有的方法,然后回推该写的具体类和方法。 伪代码 package com.jsheng.game.test2; import java.awt.Color; import java.awt.Graphics2D; import java.awt.event.KeyEvent; import com.jsheng.game.util.GameAction; import com.jsheng.game.util.GameCore; import com.jsheng.game.util.InputManager; /** function: * company: jsheng * @author wanghn wanghaining9999@sina.com */ public class My3DTest1 extends GameCore { public static void main(String[] args) { new My3DTest1().run(); } private 多边形 a = new 多边形(); private GameAction exit = new GameAction("exit"); private GameAction zoomIn = new GameAction("zoomIn"); private GameAction zoomOut = new GameAction("zoomOut"); public void init() { super.init(); InputManager inputManager = new InputManager( screen.getFullScreenWindow()); inputManager.setCursor(InputManager.INVISIBLE_CURSOR); inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE); inputManager.mapToKey(zoomIn, KeyEvent.VK_UP); inputManager.mapToKey(zoomOut, KeyEvent.VK_DOWN); } public void do设置多边形(){ } public void do设置多边形旋转角度(){ } public void update(long elapsedTime) { if (exit.isPressed()) { stop(); return; } elapsedTime = Math.min(elapsedTime, 100); } public void draw(Graphics2D g) { //处理 this.draw多边形(g, a); } /** 在屏幕绘制多边形 */ private void draw多边形(Graphics2D g,多边形 a) { } } 向量,三角函数等数学知识就不介绍了,这里的程序模拟了这些算法。 说个概念:视图窗口和镜头 视图窗口是三维空间中语屏幕窗口大小相同的窗口。镜头就好像眼睛,去观察视图窗口,然后去将三维物体投影到视图窗口。(这里可以参考相关资料,或我以后整理上图更好说明这个问题) 3D中的数学 将三维物体投影到视图窗口中可以简化为直角三角形问题。 假设三维物体坐标二维点是(x,y),投影到视图窗口的二维点是(x1,y1) 从镜头到视图窗口距离是d 三维点到原点距离是z,得到: x1=dx/-z;y1=dy/-z d的值是我们来设置的 另外还能用夹角 从镜头出发到视图窗口两遍发射直线,两直线得到一个夹角,我们就可以通过三角函数来计算一些问题。 给出类代码,具备视图窗口和投影功能。 package com.jsheng.game.util.java3d; import java.awt.Rectangle; public class ViewWindow { private Rectangle bounds; //视图窗口的边界 private float angle; //水平视角 private float distance; //视图窗口到镜头的距离 public ViewWindow(int left, int top, int width, int height, float angle) { bounds = new Rectangle(); this.angle = angle; setBounds(left, top, width, height); } public void setBounds(int left, int top, int width, int height) { bounds.x = left; bounds.y = top; bounds.width = width; bounds.height = height; distance = (bounds.width/2) / (float)Math.tan(angle/2); } public void setAngle(float angle) { this.angle = angle; distance = (bounds.width/2) / (float)Math.tan(angle/2); } public float getAngle() { return angle; } public int getWidth() { return bounds.width; } public int getHeight() { return bounds.height; } public int getTopOffset() { return bounds.y; } public int getLeftOffset() { return bounds.x; } public float getDistance() { return distance; } public float convertFromViewXToScreenX(float x) { return x + bounds.x + bounds.width/2; } public float convertFromViewYToScreenY(float y) { return -y + bounds.y + bounds.height/2; } public float convertFromScreenXToViewX(float x) { return x - bounds.x - bounds.width/2; } public float convertFromScreenYToViewY(float y) { return -y + bounds.y + bounds.height/2; } //将指定的向量投影到屏幕 public void project(Vector3D v) { v.x = distance * v.x / -v.z; v.y = distance * v.y / -v.z; // convert to screen coordinates v.x = convertFromViewXToScreenX(v.x); v.y = convertFromViewYToScreenY(v.y); } }] 处理多边形: package com.jsheng.game.util.java3d; public class Polygon3D { private static Vector3D temp1 = new Vector3D(); private static Vector3D temp2 = new Vector3D(); private Vector3D[] v; private int numVertices; private Vector3D normal; public Polygon3D() { numVertices = 0; v = new Vector3D[0]; normal = new Vector3D(); } public Polygon3D(Vector3D[] v) { this.v = v; numVertices = v.length; calcNormal(); } public void setTo(Polygon3D polygon) { numVertices = polygon.numVertices; normal.setTo(polygon.normal); ensureCapacity(numVertices); for (int i=0; i<numVertices; i++) { v[i].setTo(polygon.v[i]); } } public void ensureCapacity(int length) { if (v.length < length) { Vector3D[] newV = new Vector3D[length]; for (int i=v.length; i<newV.length; i++) { newV[i] = new Vector3D(); } v = newV; } } public int getNumVertices() { return numVertices; } public Vector3D getVertex(int index) { return v[index]; } public void project(ViewWindow view) { for (int i=0; i<numVertices; i++) { view.project(v[i]); } } public void add(Vector3D u) { for (int i=0; i<numVertices; i++) { v[i].add(u); } } public void subtract(Vector3D u) { for (int i=0; i<numVertices; i++) { v[i].subtract(u); } } public void add(Transform3D xform) { addRotation(xform); add(xform.getLocation()); } public void subtract(Transform3D xform) { subtract(xform.getLocation()); subtractRotation(xform); } public void addRotation(Transform3D xform) { for (int i=0; i<numVertices; i++) { v[i].addRotation(xform); } normal.addRotation(xform); } public void subtractRotation(Transform3D xform) { for (int i=0; i<numVertices; i++) { v[i].subtractRotation(xform); } normal.subtractRotation(xform); } 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 Vector3D getNormal() { return normal; } public void setNormal(Vector3D n) { if (normal == null) { normal = new Vector3D(n); } else { normal.setTo(n); } } public boolean isFacing(Vector3D u) { temp1.setTo(u); temp1.subtract(v[0]); return (normal.getDotProduct(temp1) >= 0); } } 三维变换之旋转: 譬如沿z轴旋转,则z值不变。 r是旋转半径 则x = rcos(a) y=rcos(a) a是原始角度 x1=rcos(a+b) y1=rsin(a+b) b是旋转角度 x1=rcosacosb-rsinasinb y1=rsinacosb+rsinbcosa 最后得到 x1=xcosb-ysinb y1=xsinb+ycosb 开发包装旋转功能的类 package com.jsheng.game.util.java3d; public class Transform3D { protected Vector3D location; private float cosAngleX; private float sinAngleX; private float cosAngleY; private float sinAngleY; private float cosAngleZ; private float sinAngleZ; public Transform3D() { this(0,0,0); } public Transform3D(float x, float y, float z) { location = new Vector3D(x, y, z); setAngle(0,0,0); } public Transform3D(Transform3D v) { location = new Vector3D(); setTo(v); } public Object clone() { return new Transform3D(this); } public void setTo(Transform3D v) { location.setTo(v.location); this.cosAngleX = v.cosAngleX; this.sinAngleX = v.sinAngleX; this.cosAngleY = v.cosAngleY; this.sinAngleY = v.sinAngleY; this.cosAngleZ = v.cosAngleZ; this.sinAngleZ = v.sinAngleZ; } public Vector3D getLocation() { return location; } public float getCosAngleX() { return cosAngleX; } public float getSinAngleX() { return sinAngleX; } public float getCosAngleY() { return cosAngleY; } public float getSinAngleY() { return sinAngleY; } public float getCosAngleZ() { return cosAngleZ; } public float getSinAngleZ() { return sinAngleZ; } public float getAngleX() { return (float)Math.atan2(sinAngleX, cosAngleX); } public float getAngleY() { return (float)Math.atan2(sinAngleY, cosAngleY); } public float getAngleZ() { return (float)Math.atan2(sinAngleZ, cosAngleZ); } public void setAngleX(float angleX) { cosAngleX = (float)Math.cos(angleX); sinAngleX = (float)Math.sin(angleX); } public void setAngleY(float angleY) { cosAngleY = (float)Math.cos(angleY); sinAngleY = (float)Math.sin(angleY); } public void setAngleZ(float angleZ) { cosAngleZ = (float)Math.cos(angleZ); sinAngleZ = (float)Math.sin(angleZ); } public void setAngle(float angleX, float angleY, float angleZ) { setAngleX(angleX); setAngleY(angleY); setAngleZ(angleZ); } public void rotateAngleX(float angle) { if (angle != 0) { setAngleX(getAngleX() + angle); } } public void rotateAngleY(float angle) { if (angle != 0) { setAngleY(getAngleY() + angle); } } public void rotateAngleZ(float angle) { if (angle != 0) { setAngleZ(getAngleZ() + angle); } } public void rotateAngle(float angleX, float angleY, float angleZ) { rotateAngleX(angleX); rotateAngleY(angleY); rotateAngleZ(angleZ); } } 最后完成最初设想的类 package com.jsheng.game.test2; import java.awt.Color; import java.awt.Graphics2D; import java.awt.event.KeyEvent; import java.awt.geom.GeneralPath; import com.jsheng.game.util.GameAction; import com.jsheng.game.util.GameCore; import com.jsheng.game.util.InputManager; import com.jsheng.game.util.java3d.Polygon3D; import com.jsheng.game.util.java3d.Transform3D; import com.jsheng.game.util.java3d.Vector3D; import com.jsheng.game.util.java3d.ViewWindow; /** function: * company: jsheng * @author wanghn wanghaining9999@sina.com */ public class My3DTest1 extends GameCore { public static void main(String[] args) { new My3DTest1().run(); } Vector3D v1 = new Vector3D(-50, 0, 0); Vector3D v2 = new Vector3D(50, 0, 0); Vector3D v3 = new Vector3D(-50, 100, 0); Vector3D v4 = new Vector3D(50, 100, 0); Vector3D[] vs = new Vector3D[]{v1,v2,v3,v4}; private Polygon3D p = new Polygon3D(vs); private Transform3D myTransform = new Transform3D(0,0,-500); private Polygon3D transformedPolygon = new Polygon3D(); private ViewWindow viewWindow; private GameAction exit = new GameAction("exit"); private GameAction zoomIn = new GameAction("zoomIn"); private GameAction zoomOut = new GameAction("zoomOut"); public void init() { super.init(); InputManager inputManager = new InputManager( screen.getFullScreenWindow()); inputManager.setCursor(InputManager.INVISIBLE_CURSOR); inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE); inputManager.mapToKey(zoomIn, KeyEvent.VK_UP); inputManager.mapToKey(zoomOut, KeyEvent.VK_DOWN); viewWindow = new ViewWindow(0, 0, screen.getWidth(), screen.getHeight(), (float)Math.toRadians(75)); } public void update(long elapsedTime) { if (exit.isPressed()) { stop(); return; } elapsedTime = Math.min(elapsedTime, 100); myTransform.rotateAngleY(0.002f*elapsedTime); if (zoomIn.isPressed()) { myTransform.getLocation().z += 0.5f*elapsedTime; } if (zoomOut.isPressed()) { myTransform.getLocation().z -= 0.5f*elapsedTime; } } public void draw(Graphics2D g) { g.setColor(Color.black); g.fillRect(0, 0, screen.getWidth(), screen.getHeight()); g.setColor(Color.white); g.drawString("按下ESC退出", 5, fontSize); 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); } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-06-24
java不适合游戏编程,你就别折腾了
|
|
返回顶楼 | |
发表时间:2009-06-25
solonote 写道 java不适合游戏编程,你就别折腾了
是的,java做游戏不太舒服,不如Cpp来的痛快。 研究研究而已,在很多地方还是可以触类旁通的,您说对吗? |
|
返回顶楼 | |
发表时间:2009-06-25
恩 我对我的话抱歉~
|
|
返回顶楼 | |
发表时间:2009-07-03
能否把你 这些游戏编程的代码上传,方便下载本机学习
|
|
返回顶楼 | |