本篇主要对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公式做如下解释
[img]http://luanshiqunying-sina-com.iteye.com/upload/attachment/116838/8ed19025-918c-31d2-a906-1a3bfc757ed7.jpg[/img]
这个图画的很不好,
一个点旋转到另一个点
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公式做如下解释
[img]http://luanshiqunying-sina-com.iteye.com/upload/attachment/116838/8ed19025-918c-31d2-a906-1a3bfc757ed7.jpg[/img]
这个图画的很不好,
一个点旋转到另一个点
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);
投影到视图窗口
最后程序循环连线画出了三维多边形,并填充了颜色。