浏览 3673 次
锁定老帖子 主题:java 游戏编程 (九)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-06-19
最后修改:2009-06-19
涉及到上一篇的所有类,做一下规整,还有新的类应用描述。 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); 投影到视图窗口 最后程序循环连线画出了三维多边形,并填充了颜色。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-11-10
楼主,这些应该是你看David Brackeen 的 Developing Games in Java 所做的笔记吧.
我也在折腾这本书 |
|
返回顶楼 | |