前言

鉴于许多同学对计算机图形学设计作品无法下手,特此推出Java3D设计作品入门级教程,可以给予毫无头绪的你一点思路。本文仅起到抛砖引玉的作用,并不提供现成的作品。

坐标对应关系

首先我们要理解java3d中的坐标轴,这个坐标轴与我们平常摆的位置的不太一样,所以要做下区分

在这里插入图片描述

然后我们把这个坐标轴代入到我们真实的环境中,代码及运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package com.test.demo01;

import java.applet.Applet;
import java.awt.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;
public class BezierSurfaceMerging extends Applet
{public BranchGroup createBranchGroupSceneGraph()
{BranchGroup BranchGroupRoot =new BranchGroup();
BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);
Color3f bgColor=new Color3f(0f,1.0f,1.0f);
Background bg=new Background(bgColor);
bg.setApplicationBounds(bounds);
BranchGroupRoot.addChild(bg);
Color3f directionalColor=new Color3f(1.f,0.f,0.f);
Vector3f vec=new Vector3f(0.f,0.f,-1.0f);
DirectionalLight directionalLight=new DirectionalLight(directionalColor,vec);
directionalLight.setInfluencingBounds(bounds);
BranchGroupRoot.addChild(directionalLight);
Transform3D tr=new Transform3D();
tr.setScale(0.85);
TransformGroup transformgroup=new TransformGroup(tr);
transformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
transformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
BranchGroupRoot.addChild(transformgroup);
MouseRotate mouserotate = new MouseRotate();
mouserotate.setTransformGroup(transformgroup);
BranchGroupRoot.addChild(mouserotate);
mouserotate.setSchedulingBounds(bounds);
MouseZoom mousezoom = new MouseZoom();
mousezoom.setTransformGroup(transformgroup);
BranchGroupRoot.addChild(mousezoom);
mousezoom.setSchedulingBounds(bounds);
MouseTranslate mousetranslate = new MouseTranslate();
mousetranslate.setTransformGroup(transformgroup);
BranchGroupRoot.addChild(mousetranslate);
mousetranslate.setSchedulingBounds(bounds);
//定义第一个Bezier曲面的16个控制顶点
float[][][] P1={{{-0.8f,0.9f,-0.4f,1.f},
{-0.2f,0.8f,-0.5f,1.f},
{0.2f,0.9f,-0.4f,1.f},
{0.8f,0.8f,-0.5f,1.f} },
{ {-0.8f,0.7f,-0.4f,1.f},
{-0.2f,0.6f,0.9f,1.f},
{0.2f,0.7f,0.8f,1.f},
{0.8f,0.6f,-0.4f,1.f} },
{{-0.8f,0.4f,-0.4f,1.f},
{-0.2f,0.5f,0.8f,1.f},
{0.2f,0.3f,0.7f,1.f},
{0.8f,0.4f,-0.5f,1.f} },
{ {-0.8f,0.f,-0.8f,1.f},
{-0.2f,0.1f,0.9f,1.f},
{0.2f,0.f,-0.8f,1.f},
{0.8f,0.1f,0.9f,1.f} } };
//定义第一个Bezier曲面外观属性
Appearance app1 = new Appearance();
PolygonAttributes polygona1=new PolygonAttributes();
polygona1.setBackFaceNormalFlip(true);
polygona1.setCullFace(PolygonAttributes.CULL_NONE);
// polygona1.setPolygonMode(PolygonAttributes.POLYGON_LINE);
app1.setPolygonAttributes(polygona1);
ColoringAttributes color1=new ColoringAttributes();
color1.setColor(1.f,0.f,0.f);
app1.setColoringAttributes(color1);


Shape3D BezierSurfaceface1=new BezierThreeOrderSurfaceface(P1,app1);
transformgroup.addChild(BezierSurfaceface1);
BranchGroupRoot.compile();
return BranchGroupRoot;
}
public BezierSurfaceMerging()
{setLayout(new BorderLayout());
GraphicsConfiguration gc = SimpleUniverse.getPreferredConfiguration();
Canvas3D c=new Canvas3D(gc);
add("Center",c);
BranchGroup BranchGroupScene=createBranchGroupSceneGraph();
SimpleUniverse u=new SimpleUniverse(c);
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(BranchGroupScene);
}
public static void main(String[] args)
{new MainFrame(new BezierSurfaceMerging(),400,400); }
}
class BezierThreeOrderSurfaceface extends Shape3D
{public BezierThreeOrderSurfaceface(float[][][] P,Appearance app)
{int i,j,k;
int n0;//定义对参数u、v在[0,1]区间的等分点数
float division;//参数u在[0,1]区间的等分线段长度
n0=50;division=1.f/n0;
//分别定义存放控制顶点x、y、z坐标与第四维坐标的数组
float[][] PX=new float[4][4];
float[][] PY=new float[4][4];
float[][] PZ=new float[4][4];
float[][] P4=new float[4][4];
//定义系数矩阵及其转置矩阵
float[][] M1={{1.f,0.f,0.f,0.f},
{-3.f,3.f,0.f,0.f},
{3.f,-6.f,3.f,0.f},
{-1.f,3.f,-3.f,1.f}};
float[][] M2={{1.f,-3.f,3.f,-1.f},
{0.f,3.f,-6.f,3.f},
{0.f,0.f,3.f,-3.f},
{0.f,0.f,0.f,1.f}};
//定义Bezier曲面的u、v参数分割点坐标数组
float[][][] UV=new float[n0+1][n0+1][2];
//定义U、V矩阵数组
float[][] UU=new float[1][4];
float[][] VV=new float[4][1];
//定义存放曲面上点的坐标的数组
float[][][] SurfaceXYZ=new float[n0+1][n0+1][4];
for(i=0;i<n0+1;i++)
for(j=0;j<n0+1;j++)
{ UV[i][j][0]=i*division;
UV[i][j][1]=j*division; }
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{ PX[i][j]=P[i][j][0];
PY[i][j]=P[i][j][1];
PZ[i][j]=P[i][j][2];
P4[i][j]=P[i][j][3]; }
//计算曲面上点的坐标值
for(i=0;i<n0+1;i++)
for(j=0;j<n0+1;j++)
{ UU[0][0]=1.f;
UU[0][1]=UV[i][j][0];
UU[0][2]=UV[i][j][0]*UV[i][j][0];
UU[0][3]=UV[i][j][0]*UV[i][j][0]*UV[i][j][0];
VV[0][0]=1.f;
VV[1][0]=UV[i][j][1];
VV[2][0]=UV[i][j][1]*UV[i][j][1];
VV[3][0]=UV[i][j][1]*UV[i][j][1]*UV[i][j][1];
//计算一点的x坐标
matrixm g0=new matrixm(1,4,4,UU,M1);
matrixm g1=new matrixm(1,4,4,g0.CC,PX);
matrixm g2=new matrixm(1,4,4,g1.CC,M2);
matrixm g3=new matrixm(1,4,1,g2.CC,VV);
SurfaceXYZ[i][j][0]=g3.CC[0][0];
//计算一点的y坐标
matrixm g4=new matrixm(1,4,4,UU,M1);
matrixm g5=new matrixm(1,4,4,g4.CC,PY);
matrixm g6=new matrixm(1,4,4,g5.CC,M2);
matrixm g7=new matrixm(1,4,1,g6.CC,VV);
SurfaceXYZ[i][j][1]=g7.CC[0][0];
//计算一点的z坐标
matrixm g8=new matrixm(1,4,4,UU,M1);
matrixm g9=new matrixm(1,4,4,g8.CC,PZ);
matrixm g10=new matrixm(1,4,4,g9.CC,M2);
matrixm g11=new matrixm(1,4,1,g10.CC,VV);
SurfaceXYZ[i][j][2]=g11.CC[0][0];
//计算一点的第4维坐标
matrixm g12=new matrixm(1,4,4,UU,M1);
matrixm g13=new matrixm(1,4,4,g12.CC,P4);
matrixm g14=new matrixm(1,4,4,g13.CC,M2);
matrixm g15=new matrixm(1,4,1,g14.CC,VV);
SurfaceXYZ[i][j][3]=g15.CC[0][0];
//将齐次坐标转换为三维坐标系坐标,如果第4维为1,则不用除第4维
SurfaceXYZ[i][j][0]=SurfaceXYZ[i][j][0]/SurfaceXYZ[i][j][3];
SurfaceXYZ[i][j][1]=SurfaceXYZ[i][j][1]/SurfaceXYZ[i][j][3];
SurfaceXYZ[i][j][2]=SurfaceXYZ[i][j][2]/SurfaceXYZ[i][j][3];
}
QuadArray BezierQuadsurfaceface = new QuadArray(n0*n0*4,
GeometryArray.COORDINATES|GeometryArray.NORMALS);
int c=0;//以顶点数累加的方式设置顶点的序号
for(i=0;i<n0;i++)
{for(j=0;j<n0;j++)
{//设置一个平面上的4个点
Point3f A=new Point3f(SurfaceXYZ[i][j][0],SurfaceXYZ[i][j][1],
SurfaceXYZ[i][j][2]);
Point3f B=new Point3f(SurfaceXYZ[i][j+1][0],SurfaceXYZ[i][j+1][1],
SurfaceXYZ[i][j+1][2]);
Point3f C=new Point3f(SurfaceXYZ[i+1][j+1][0],SurfaceXYZ[i+1][j+1][1],
SurfaceXYZ[i+1][j+1][2]);
Point3f D=new Point3f(SurfaceXYZ[i+1][j][0],SurfaceXYZ[i+1][j][1],
SurfaceXYZ[i+1][j][2]);
//计算由四个点形成的平面的法向量
Vector3f a = new Vector3f(A.x - B.x, A.y - B.y, A.z - B.z);
Vector3f b = new Vector3f(C.x - B.x, C.y - B.y, C.z - B.z);
Vector3f n = new Vector3f();
n.cross(b, a);
n.normalize();
//设置点的序号
BezierQuadsurfaceface.setCoordinate(c, A);
BezierQuadsurfaceface.setCoordinate(c+1, B);
BezierQuadsurfaceface.setCoordinate(c+2, C);
BezierQuadsurfaceface.setCoordinate(c+3, D);
//设置点的法向量
BezierQuadsurfaceface.setNormal(c, n);
BezierQuadsurfaceface.setNormal(c+1, n);
BezierQuadsurfaceface.setNormal(c+2, n);
BezierQuadsurfaceface.setNormal(c+3, n);
c=c+4;
}}
this.addGeometry(BezierQuadsurfaceface);
this.setAppearance(app);
}}
class BezierSurfaceControlPoints extends Shape3D
{public BezierSurfaceControlPoints(float[][][] P,Appearance app)
{int i,j,k;
QuadArray BeziersurfacecontrolPointsNet =new QuadArray(3*3*4,
GeometryArray.COORDINATES|GeometryArray.NORMALS);
int c=0;
for(i=0;i<3;i++)
{for(j=0;j<3;j++)
{Point3f A=new Point3f(P[i][j][0],P[i][j][1],P[i][j][2]);
Point3f B=new Point3f(P[i][j+1][0],P[i][j+1][1],P[i][j+1][2]);
Point3f C=new Point3f(P[i+1][j+1][0],P[i+1][j+1][1],P[i+1][j+1][2]);
Point3f D=new Point3f(P[i+1][j][0],P[i+1][j][1],P[i+1][j][2]);
Vector3f a = new Vector3f(A.x - B.x, A.y - B.y, A.z - B.z);
Vector3f b = new Vector3f(C.x - B.x, C.y - B.y, C.z - B.z);
Vector3f n = new Vector3f();
n.cross(b, a);
n.normalize();
BeziersurfacecontrolPointsNet.setCoordinate(c, A);
BeziersurfacecontrolPointsNet.setCoordinate(c+1, B);
BeziersurfacecontrolPointsNet.setCoordinate(c+2, C);
BeziersurfacecontrolPointsNet.setCoordinate(c+3, D);
BeziersurfacecontrolPointsNet.setNormal(c, n);
BeziersurfacecontrolPointsNet.setNormal(c+1, n);
BeziersurfacecontrolPointsNet.setNormal(c+2, n);
BeziersurfacecontrolPointsNet.setNormal(c+3, n);
c=c+4;
}}
this.addGeometry(BeziersurfacecontrolPointsNet);
this.setAppearance(app);
}}
class matrixm
{public float CC[][]= new float[4][4];
int ll,mm,kk;
public matrixm(int mmm, int kkk, int nnn,float a[][],float b[][])
{for(ll=0;ll<mmm;ll++)
for(mm=0;mm<nnn;mm++){CC[ll][mm]=0.f;}
for(ll=0;ll<mmm;ll++)
for(mm=0;mm<nnn;mm++)
{for(kk=0;kk<kkk;kk++) CC[ll][mm]=CC[ll][mm]+a[ll][kk]*b[kk][mm];}
}}


在这里插入图片描述
在这一长段代码中,只有P1的这16个点是我们要改动的地方,这16个的点共同组成了一个曲面。每个点包含了4个坐标,但其中的1.f我们是不需要去动的,因此真正有用的是前三个
{X, Y, Z, 1.f}
这里的XYZ就分别对应到上述提到的坐标轴中,那么理解了坐标是怎么使用后,还要将坐标对应到曲面中。

为了方便演示,我们将P1中的坐标改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
float[][][] P1={
{{-0.8f, -1.2f, -0.8f, 1.f}, {-0.2f, 0.2f, -0.5f, 1.f},
{0.2f, 0.3f, -0.5f, 1.f}, {0.8f, -1.2f, -0.8f, 1.f}},

{{-0.8f, -0.1f, -0.2f, 1.f}, {-0.2f, 0.9f, -0.2f, 1.f},
{0.2f, 0.9f, -0.2f, 1.f}, {0.8f, -0.1f, -0.2f, 1.f}},

{{-0.8f, -0.1f, 0.2f, 1.f}, {-0.2f, 0.9f, 0.2f, 1.f},
{0.2f, 0.9f, 0.2f, 1.f}, {0.8f, -0.1f, 0.2f, 1.f}},

{{-0.6f, -0.6f, 0.9f, 1.f}, {-0.2f, 0.2f, 0.5f, 1.f},
{0.2f, 0.3f, 0.5f, 1.f}, {0.6f, -0.65f, 0.8f, 1.f}}};

运行我们的代码,得到如下结果:
在这里插入图片描述
到这步后,我们要把最前面提到的坐标轴,与这张图相结合。这里注意一下,为了避免把自己搞混乱,运行出结果后就不要随便去转动它!!!第一印象很重要。
在这里插入图片描述
这就是在这张图中代表的坐标系(上下位置不一定准确)
我们的重头戏要来了,这16个点分别代表图中的哪个位置,因为这个图像凹凸有致,我们很容易想到去调整它的Y坐标,来得到最佳的观察效果。
我们将这里的坐标分别4组,从上至下,从左至右,依次记为1,2,3……16
在这里插入图片描述
首先我们将第一个点的Y坐标改为0,观察效果
在这里插入图片描述
可以看到已经有了一定的变化,随后我们转动图像,以俯视的视角,也就是想象自己飞到了图像的上方。
在这里插入图片描述
可以看到图形的这一角比较特别,相比较原先有点翘起,归根结底就是我们把第一个点的纵坐标由-1.2f变为了0f,产生了这个效果。有兴趣的同学可以再把它改成-1.2f,就会得到如下 结果:
在这里插入图片描述
我们依葫芦画瓢,把这16个点都改一遍,也就是只把它们的Y坐标改为0,分别会得到以下结果(均采用了俯视的视角):

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
到这里,我们第一组的坐标全部测试完毕了,相信大家一定对坐标和曲面之间的对应关系有了一定的了解。现在我们再测一下每组的第一个点,同样修改其Y坐标
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
自己都试一遍印象才能深刻噢!

接着我们看看把全部的Y坐标归0的结果
在这里插入图片描述
可以看到打开的时候已经变成了一个平面了,不再是曲面,这也给了 我们一个构造平面的思路,也就是把16个的坐标的XYZ任意一个全部设置为0,就可以得到平面。

当然学到这里,你已经掌握了一个曲面是如何运转的,然而我们的作品肯定不是只由一个曲面就能完成,除非你看开了。

加一个面

接下来我们将详细分析一下,自己如何再加一个曲面

添加如下代码, 这里的P2是由P1的Y坐标修改为0.5f得来,也就是把整个面往上抬了0.5f的距离,可以先在脑海中想想会是什么样子再往下滑,建立空间感

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
float[][][] P2={
{{-0.8f, 0.5f, -0.8f, 1.f}, {-0.2f, 0.5f, -0.5f, 1.f},
{0.2f, 0.5f, -0.5f, 1.f}, {0.8f, 0.5f, -0.8f, 1.f}},

{{-0.8f, 0.5f, -0.2f, 1.f}, {-0.2f, 0.5f, -0.2f, 1.f},
{0.2f, 0.5f, -0.2f, 1.f}, {0.8f, 0.5f, -0.2f, 1.f}},

{{-0.8f, 0.5f, 0.2f, 1.f}, {-0.2f, 0.5f, 0.2f, 1.f},
{0.2f, 0.5f, 0.2f, 1.f}, {0.8f, 0.5f, 0.2f, 1.f}},

{{-0.6f, 0.5f, 0.9f, 1.f}, {-0.2f, 0.5f, 0.5f, 1.f},
{0.2f, 0.5f, 0.5f, 1.f}, {0.6f, 0.5f, 0.8f, 1.f}}};
//定义第一个Bezier曲面外观属性
Appearance app2 = new Appearance();
PolygonAttributes polygona2=new PolygonAttributes();
polygona2.setBackFaceNormalFlip(true);
polygona2.setCullFace(PolygonAttributes.CULL_NONE);
polygona2.setPolygonMode(PolygonAttributes.POLYGON_LINE);
app2.setPolygonAttributes(polygona2);
ColoringAttributes color2=new ColoringAttributes();
color2.setColor(0.8f,0.f,0.f);
app2.setColoringAttributes(color2);
Shape3D BezierSurfaceface2=new BezierThreeOrderSurfaceface(P2,app2);
transformgroup.addChild(BezierSurfaceface2);

说说要改的地方,P2 app2 polygona2 color2 BezierSurfaceface2
这里都由原先的1改为了2,要是想添加3个,4个,10个,100个,也是以此类推。
效果如下:
在这里插入图片描述
看到这里,相信你一定已经会意了
小练习:可以先动手试试如何用6个曲面拼成一个方块
本次教程就到这里了,快去完成自己的设计作品吧!
4班冲!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package com.test.demo01;

import java.applet.Applet;
import java.awt.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;
public class BezierSurfaceMerging extends Applet
{public BranchGroup createBranchGroupSceneGraph()
{BranchGroup BranchGroupRoot =new BranchGroup();
BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);
Color3f bgColor=new Color3f(0f,1.0f,1.0f);
Background bg=new Background(bgColor);
bg.setApplicationBounds(bounds);
BranchGroupRoot.addChild(bg);
Color3f directionalColor=new Color3f(1.f,0.f,0.f);
Vector3f vec=new Vector3f(0.f,0.f,-1.0f);
DirectionalLight directionalLight=new DirectionalLight(directionalColor,vec);
directionalLight.setInfluencingBounds(bounds);
BranchGroupRoot.addChild(directionalLight);
Transform3D tr=new Transform3D();
tr.setScale(0.85);
TransformGroup transformgroup=new TransformGroup(tr);
transformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
transformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
BranchGroupRoot.addChild(transformgroup);
MouseRotate mouserotate = new MouseRotate();
mouserotate.setTransformGroup(transformgroup);
BranchGroupRoot.addChild(mouserotate);
mouserotate.setSchedulingBounds(bounds);
MouseZoom mousezoom = new MouseZoom();
mousezoom.setTransformGroup(transformgroup);
BranchGroupRoot.addChild(mousezoom);
mousezoom.setSchedulingBounds(bounds);
MouseTranslate mousetranslate = new MouseTranslate();
mousetranslate.setTransformGroup(transformgroup);
BranchGroupRoot.addChild(mousetranslate);
mousetranslate.setSchedulingBounds(bounds);
//定义第一个Bezier曲面的16个控制顶点
float[][][] P1={
{{-0.8f, 0f, -0.8f, 1.f}, {-0.2f, 0f, -0.5f, 1.f},
{0.2f, 0f, -0.5f, 1.f}, {0.8f, 0f, -0.8f, 1.f}},

{{-0.8f, 0f, -0.2f, 1.f}, {-0.2f, 0f, -0.2f, 1.f},
{0.2f, 0f, -0.2f, 1.f}, {0.8f, 0f, -0.2f, 1.f}},

{{-0.8f, 0f, 0.2f, 1.f}, {-0.2f, 0f, 0.2f, 1.f},
{0.2f, 0f, 0.2f, 1.f}, {0.8f, 0f, 0.2f, 1.f}},

{{-0.6f, 0f, 0.9f, 1.f}, {-0.2f, 0f, 0.5f, 1.f},
{0.2f, 0f, 0.5f, 1.f}, {0.6f, 0f, 0.8f, 1.f}}};
//定义第一个Bezier曲面外观属性
Appearance app1 = new Appearance();
PolygonAttributes polygona1=new PolygonAttributes();
polygona1.setBackFaceNormalFlip(true);
polygona1.setCullFace(PolygonAttributes.CULL_NONE);
polygona1.setPolygonMode(PolygonAttributes.POLYGON_LINE);
app1.setPolygonAttributes(polygona1);
ColoringAttributes color1=new ColoringAttributes();
color1.setColor(0.8f,0.f,0.f);
app1.setColoringAttributes(color1);


float[][][] P2={
{{-0.8f, 0.5f, -0.8f, 1.f}, {-0.2f, 0.5f, -0.5f, 1.f},
{0.2f, 0.5f, -0.5f, 1.f}, {0.8f, 0.5f, -0.8f, 1.f}},

{{-0.8f, 0.5f, -0.2f, 1.f}, {-0.2f, 0.5f, -0.2f, 1.f},
{0.2f, 0.5f, -0.2f, 1.f}, {0.8f, 0.5f, -0.2f, 1.f}},

{{-0.8f, 0.5f, 0.2f, 1.f}, {-0.2f, 0.5f, 0.2f, 1.f},
{0.2f, 0.5f, 0.2f, 1.f}, {0.8f, 0.5f, 0.2f, 1.f}},

{{-0.6f, 0.5f, 0.9f, 1.f}, {-0.2f, 0.5f, 0.5f, 1.f},
{0.2f, 0.5f, 0.5f, 1.f}, {0.6f, 0.5f, 0.8f, 1.f}}};
//定义第一个Bezier曲面外观属性
Appearance app2 = new Appearance();
PolygonAttributes polygona2=new PolygonAttributes();
polygona2.setBackFaceNormalFlip(true);
polygona2.setCullFace(PolygonAttributes.CULL_NONE);
polygona2.setPolygonMode(PolygonAttributes.POLYGON_LINE);
app2.setPolygonAttributes(polygona2);
ColoringAttributes color2=new ColoringAttributes();
color2.setColor(0.8f,0.f,0.f);
app2.setColoringAttributes(color2);
Shape3D BezierSurfaceface2=new BezierThreeOrderSurfaceface(P2,app2);
transformgroup.addChild(BezierSurfaceface2);

Shape3D BezierSurfaceface1=new BezierThreeOrderSurfaceface(P1,app1);
transformgroup.addChild(BezierSurfaceface1);
BranchGroupRoot.compile();
return BranchGroupRoot;
}
public BezierSurfaceMerging()
{setLayout(new BorderLayout());
GraphicsConfiguration gc = SimpleUniverse.getPreferredConfiguration();
Canvas3D c=new Canvas3D(gc);
add("Center",c);
BranchGroup BranchGroupScene=createBranchGroupSceneGraph();
SimpleUniverse u=new SimpleUniverse(c);
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(BranchGroupScene);
}
public static void main(String[] args)
{new MainFrame(new BezierSurfaceMerging(),400,400); }
}
class BezierThreeOrderSurfaceface extends Shape3D
{public BezierThreeOrderSurfaceface(float[][][] P,Appearance app)
{int i,j,k;
int n0;//定义对参数u、v在[0,1]区间的等分点数
float division;//参数u在[0,1]区间的等分线段长度
n0=50;division=1.f/n0;
//分别定义存放控制顶点x、y、z坐标与第四维坐标的数组
float[][] PX=new float[4][4];
float[][] PY=new float[4][4];
float[][] PZ=new float[4][4];
float[][] P4=new float[4][4];
//定义系数矩阵及其转置矩阵
float[][] M1={{1.f,0.f,0.f,0.f},
{-3.f,3.f,0.f,0.f},
{3.f,-6.f,3.f,0.f},
{-1.f,3.f,-3.f,1.f}};
float[][] M2={{1.f,-3.f,3.f,-1.f},
{0.f,3.f,-6.f,3.f},
{0.f,0.f,3.f,-3.f},
{0.f,0.f,0.f,1.f}};
//定义Bezier曲面的u、v参数分割点坐标数组
float[][][] UV=new float[n0+1][n0+1][2];
//定义U、V矩阵数组
float[][] UU=new float[1][4];
float[][] VV=new float[4][1];
//定义存放曲面上点的坐标的数组
float[][][] SurfaceXYZ=new float[n0+1][n0+1][4];
for(i=0;i<n0+1;i++)
for(j=0;j<n0+1;j++)
{ UV[i][j][0]=i*division;
UV[i][j][1]=j*division; }
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{ PX[i][j]=P[i][j][0];
PY[i][j]=P[i][j][1];
PZ[i][j]=P[i][j][2];
P4[i][j]=P[i][j][3]; }
//计算曲面上点的坐标值
for(i=0;i<n0+1;i++)
for(j=0;j<n0+1;j++)
{ UU[0][0]=1.f;
UU[0][1]=UV[i][j][0];
UU[0][2]=UV[i][j][0]*UV[i][j][0];
UU[0][3]=UV[i][j][0]*UV[i][j][0]*UV[i][j][0];
VV[0][0]=1.f;
VV[1][0]=UV[i][j][1];
VV[2][0]=UV[i][j][1]*UV[i][j][1];
VV[3][0]=UV[i][j][1]*UV[i][j][1]*UV[i][j][1];
//计算一点的x坐标
matrixm g0=new matrixm(1,4,4,UU,M1);
matrixm g1=new matrixm(1,4,4,g0.CC,PX);
matrixm g2=new matrixm(1,4,4,g1.CC,M2);
matrixm g3=new matrixm(1,4,1,g2.CC,VV);
SurfaceXYZ[i][j][0]=g3.CC[0][0];
//计算一点的y坐标
matrixm g4=new matrixm(1,4,4,UU,M1);
matrixm g5=new matrixm(1,4,4,g4.CC,PY);
matrixm g6=new matrixm(1,4,4,g5.CC,M2);
matrixm g7=new matrixm(1,4,1,g6.CC,VV);
SurfaceXYZ[i][j][1]=g7.CC[0][0];
//计算一点的z坐标
matrixm g8=new matrixm(1,4,4,UU,M1);
matrixm g9=new matrixm(1,4,4,g8.CC,PZ);
matrixm g10=new matrixm(1,4,4,g9.CC,M2);
matrixm g11=new matrixm(1,4,1,g10.CC,VV);
SurfaceXYZ[i][j][2]=g11.CC[0][0];
//计算一点的第4维坐标
matrixm g12=new matrixm(1,4,4,UU,M1);
matrixm g13=new matrixm(1,4,4,g12.CC,P4);
matrixm g14=new matrixm(1,4,4,g13.CC,M2);
matrixm g15=new matrixm(1,4,1,g14.CC,VV);
SurfaceXYZ[i][j][3]=g15.CC[0][0];
//将齐次坐标转换为三维坐标系坐标,如果第4维为1,则不用除第4维
SurfaceXYZ[i][j][0]=SurfaceXYZ[i][j][0]/SurfaceXYZ[i][j][3];
SurfaceXYZ[i][j][1]=SurfaceXYZ[i][j][1]/SurfaceXYZ[i][j][3];
SurfaceXYZ[i][j][2]=SurfaceXYZ[i][j][2]/SurfaceXYZ[i][j][3];
}
QuadArray BezierQuadsurfaceface = new QuadArray(n0*n0*4,
GeometryArray.COORDINATES|GeometryArray.NORMALS);
int c=0;//以顶点数累加的方式设置顶点的序号
for(i=0;i<n0;i++)
{for(j=0;j<n0;j++)
{//设置一个平面上的4个点
Point3f A=new Point3f(SurfaceXYZ[i][j][0],SurfaceXYZ[i][j][1],
SurfaceXYZ[i][j][2]);
Point3f B=new Point3f(SurfaceXYZ[i][j+1][0],SurfaceXYZ[i][j+1][1],
SurfaceXYZ[i][j+1][2]);
Point3f C=new Point3f(SurfaceXYZ[i+1][j+1][0],SurfaceXYZ[i+1][j+1][1],
SurfaceXYZ[i+1][j+1][2]);
Point3f D=new Point3f(SurfaceXYZ[i+1][j][0],SurfaceXYZ[i+1][j][1],
SurfaceXYZ[i+1][j][2]);
//计算由四个点形成的平面的法向量
Vector3f a = new Vector3f(A.x - B.x, A.y - B.y, A.z - B.z);
Vector3f b = new Vector3f(C.x - B.x, C.y - B.y, C.z - B.z);
Vector3f n = new Vector3f();
n.cross(b, a);
n.normalize();
//设置点的序号
BezierQuadsurfaceface.setCoordinate(c, A);
BezierQuadsurfaceface.setCoordinate(c+1, B);
BezierQuadsurfaceface.setCoordinate(c+2, C);
BezierQuadsurfaceface.setCoordinate(c+3, D);
//设置点的法向量
BezierQuadsurfaceface.setNormal(c, n);
BezierQuadsurfaceface.setNormal(c+1, n);
BezierQuadsurfaceface.setNormal(c+2, n);
BezierQuadsurfaceface.setNormal(c+3, n);
c=c+4;
}}
this.addGeometry(BezierQuadsurfaceface);
this.setAppearance(app);
}}
class BezierSurfaceControlPoints extends Shape3D
{public BezierSurfaceControlPoints(float[][][] P,Appearance app)
{int i,j,k;
QuadArray BeziersurfacecontrolPointsNet =new QuadArray(3*3*4,
GeometryArray.COORDINATES|GeometryArray.NORMALS);
int c=0;
for(i=0;i<3;i++)
{for(j=0;j<3;j++)
{Point3f A=new Point3f(P[i][j][0],P[i][j][1],P[i][j][2]);
Point3f B=new Point3f(P[i][j+1][0],P[i][j+1][1],P[i][j+1][2]);
Point3f C=new Point3f(P[i+1][j+1][0],P[i+1][j+1][1],P[i+1][j+1][2]);
Point3f D=new Point3f(P[i+1][j][0],P[i+1][j][1],P[i+1][j][2]);
Vector3f a = new Vector3f(A.x - B.x, A.y - B.y, A.z - B.z);
Vector3f b = new Vector3f(C.x - B.x, C.y - B.y, C.z - B.z);
Vector3f n = new Vector3f();
n.cross(b, a);
n.normalize();
BeziersurfacecontrolPointsNet.setCoordinate(c, A);
BeziersurfacecontrolPointsNet.setCoordinate(c+1, B);
BeziersurfacecontrolPointsNet.setCoordinate(c+2, C);
BeziersurfacecontrolPointsNet.setCoordinate(c+3, D);
BeziersurfacecontrolPointsNet.setNormal(c, n);
BeziersurfacecontrolPointsNet.setNormal(c+1, n);
BeziersurfacecontrolPointsNet.setNormal(c+2, n);
BeziersurfacecontrolPointsNet.setNormal(c+3, n);
c=c+4;
}}
this.addGeometry(BeziersurfacecontrolPointsNet);
this.setAppearance(app);
}}
class matrixm
{public float CC[][]= new float[4][4];
int ll,mm,kk;
public matrixm(int mmm, int kkk, int nnn,float a[][],float b[][])
{for(ll=0;ll<mmm;ll++)
for(mm=0;mm<nnn;mm++){CC[ll][mm]=0.f;}
for(ll=0;ll<mmm;ll++)
for(mm=0;mm<nnn;mm++)
{for(kk=0;kk<kkk;kk++) CC[ll][mm]=CC[ll][mm]+a[ll][kk]*b[kk][mm];}
}}