java3D 第三章 java3D基本图形类详解

java 3D基本图形功能

java 3D场景式管理

用一个球体与一个长方体生成的组合体程序实例来说明

类图

image-20211018074623214

代码

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.GraphicsConfiguration;
import java.awt.event.MouseAdapter;

import java.util.Vector;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Material;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import javax.xml.crypto.dsig.Transform;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.SimpleUniverse;
//由于Applet是在用户计算机上执行的,因此它的执行速度是不受网络宽带或者MODEM存取速度的限制,
//用户可以更好的欣赏网页上Applet产生的多媒体效果。
public class TwoPrimitiveDisplay extends Applet {
	public BranchGroup creatBranchGroup() {
		// 定义BranchGroup
		BranchGroup branchGroup = new BranchGroup();
		// 创建球心在坐标系原点球形范围,指定圆心和半径
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		
		// 定义背景颜色
		Color3f bjcolor3f = new Color3f(1.0f,1.0f,1.0f);//参数是rgb
		Background background=new Background(bjcolor3f);
		//利用背景对象设置背景范围(上面创建了还没设置)
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);
		
		//定义平行光颜色
		Color3f directioncolor3f =new Color3f(1.f,1.f,1.f);
		//设置光线方向
		//Vector3f 是包javax.vecmath中的数学类,用于用浮点数来设定一个矢量。Vector对象常常用于设置图形形变。
		Vector3f vector3f=new Vector3f(-1.f,-1.f,-1.0f);
		//利用上面颜色和方向对象指定光线的方向和颜色
		DirectionalLight directionalLight=new DirectionalLight(directioncolor3f, vector3f);
		//设置光线范围与上面背景范围相同
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);
		
		//定义两个三维体外观,在之后使用
		Appearance appearance1=new Appearance();
		Material material1=new Material();
		material1.setDiffuseColor(new Color3f(1.f,.0f,0.0f));
		appearance1.setMaterial(material1);//外观利用材料类设定
		Appearance appearance2=new Appearance();
		Material material2=new Material();
		material2.setDiffuseColor(new Color3f(.0f,1.f,0.f));
		appearance2.setMaterial(material2);
		
		//定义总的TransformGroup:transformgroup
		TransformGroup transformGroup=new TransformGroup();
		//设置对该TransformGroup的读写能力
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(transformGroup);
		
		//定义鼠标对场景的旋转,平移,放大功能
		//旋转
		MouseRotate mouseRotate=new MouseRotate();
		mouseRotate.setTransformGroup(transformGroup);
		transformGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);
		//放大
		MouseZoom mouseZoom =new MouseZoom();
		mouseZoom.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);
		//平移
		MouseTranslate mouseTranslate=new MouseTranslate();
		mouseTranslate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);
		/*定义一个球体与一个长方体的大小、外观属性与坐标变换,并定义相应的TransformGroup:tg1、tg2*/
		//球体
		TransformGroup transformGroup1=new TransformGroup();
		transformGroup1.addChild(new Sphere(0.4f,appearance1));
		//Transform3D 对象用于进行3D几何形变比如平移和旋转
		Transform3D transform3d=new Transform3D();
		//利用传入的 Vector3f型的参数设置图形的平移值
		//Transform3D对象所定义的变换是用于创建场景图中的 TransformGroup 对象的。
		transform3d.setTranslation(new Vector3f(0.f,-0.425f,0.f));
		//长方体
		//使用transform3d设置长方体的位置
        //TransformGroup(Transform3D t1)通过传入Transform3D对象参数来构造并且初始化一个TransformGroup 对象。
		TransformGroup transformGroup2=new TransformGroup(transform3d);
		transformGroup2.addChild(new Box(0.5f,0.05f,0.5f,appearance2));
		//将定义好的两个TransformGroup(tg1、tg2)加入到总的transformgroup
		transformGroup.addChild(transformGroup1);
		transformGroup.addChild(transformGroup2);
		//在将一个子图加入到一个VirtualUniverse或者SimpleUniverse类的虚拟空间之前,该整个子图可被预编译优化。
		//对BranchGroupRoot预编译
		branchGroup.compile();
		
		return branchGroup;				
	}
	
	public TwoPrimitiveDisplay() {
		//设置布局管理器
		setLayout(new BorderLayout());
		//图形化配置
		GraphicsConfiguration gc=SimpleUniverse.getPreferredConfiguration();
		//Canvas3D是AWT (Abstract Windowing Toolkit)的Canvas对象的3D版。它提供了一个窗口用来显示Java 3D的图象。
		Canvas3D canvas3D=new Canvas3D(gc);
		//将投影平面上的图象显示在显示平面的中间
		add("Center",canvas3D);
		
		//调用createBranchGroup();方法
		BranchGroup branchGroup=creatBranchGroup();
		//设置SimpleUniverse,由系统选择视点在z轴的正向,观察方向沿z轴反向
		SimpleUniverse simpleUniverse=new SimpleUniverse();
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		//将branchGroup加入到simpleUniverse中
		simpleUniverse.addBranchGraph(branchGroup);
		
	}
	public static void main(String[] args) {
		//通过MainFrame显示图象 参数MainFrame(Applet applet1, int i, int j) i,j为宽高
		new MainFrame(new TwoPrimitiveDisplay(), 300, 300);
	}

}

运行结果:

image-20211018075015276

SimpleUniverse类及其方法

SimpleUniverse类介绍
类SimpleUniverse属于com.sun.j3d.utils.universe包,其结构如上。该类可快速地设置一个最小的用户环境,并且很容易使一个Java 3D应用程序运行起来。该实用程序类创建了场景图中与观察相关的所有必须对象。该类创建了一个Locale、一个单独的ViewingPlatform和一个Viewer观察者对象,其中,该ViewingPlatform和Viewer观察者都是用其所有默认参数创建的。对于很多Java 3D应用程序来说,SimpleUniverse类提供了应用程序所需的全部功能。但是,对于需要向程序增加更多控制以获得更多功能的复杂应用程序来说,SimpleUniverse类并不适合

SimpleUniverse类的方法

  • SimpleUniverse( ) 构造函数:
    创建一个Locale,并用其默认参数创建一个一个单独的ViewingPlatform对象和一个Viewer观察者对象。

  • getPreferredConfiguration()方法:
    其返回值类型为static java.awt.GraphicsConfiguration类型。该方法对当前使用的计算机系统,找到一个最优的GraphicsConfiguration对象,其值存在static java.awt.GraphicsConfiguration的一个对象中。该对象然后用来创建针对该系统的Canvas3D对象。

  • SimpleUniverse类的方法getViewingPlatform()方法:

    ​ 返回与当前场景图相关的ViewingPlatform对象。该方法的类型是public ViewingPlatform getViewingPlatform()。

ViewingPlatform类及方法

Java 3D虚拟世界坐标系统
虚拟世界坐标系统是一种在虚拟环境中统一的坐标系统,该坐标系统对所有场景图对象都适用。对于一个给定的View观察,虚拟世界坐标系通过包含一个已附加该View的ViewPlatform对象的Local对象来定义。它是一个右手坐标系,默认情况下和Java 3D的显示器坐标系相同。

Java 3D的透视投影(perspective projection)与平行投影(parallel projection)

  • 透视投影模拟人眼睛看东西与相机照相的原理,以这种投影方式显示的图象与人眼睛看到的,或者与相机照相照到的图象相近。这种透视投影的特点是离视点近的形体显得大,离视点远的显得小。
  • 平行投影就是将空间的三维型体分别向三个坐标平面进行平行投影(也可称为向三个坐标平面做垂直投影),分别形成各种视图,其中最常用的就是工程制图中的主视图、俯视图与侧视图

透视投影观察四棱台

  • 观察四棱台决定了一个透视投影的观察范围。该透视投影的观察点或者相机位置在z轴上,也就是锥顶在z轴上,四棱台的中心轴线与z轴重合。四棱台的六个面称为剪裁平面,在该四棱台平面之内的内容将显示在投影平面上,位于四棱台剪裁平面之外的内容将被剪裁掉,不会显示在投影平面上。

    image-20211018080811695

  • image-20211018081033700

    • 观察四棱台的定义有两种方式,如上图所示。

      第一种方式用参数(left,bottom,near)和(right,top,near)定义四棱台范围。

      第二种方式,用near和far参数确定近端和远端的剪裁平面;fovx参数确定在X轴方向的观察角度范围(the field of view in the X dimension),用弧度表示(radian);aspect参数确定窗口的aspect比率。

    • near和far参数允许应用程序决定哪些Java 3D对象没有必要画出来。位于far参数面之外的对象由于距离视点太远通常无法产生图象,而位于near参数面之外的对象由于距离视点太近而模糊,也不能产生图象

View类的View()构造函数的部分默认参数

field of view : PI/4;
left manual eye in coexistence :   
(-0.033,0.0,0.4572);
right manual eye in coexistence : (0.033,0.0,0.4572);
front clip distance : 0.1;
back clip distance : 10.0

平行投影直角长方体(rectangular box)定义
相关参数定义了一个用于投影的直角长方体:(left,bottom,near)和(right,top,near)参数确定近端剪裁平面的左下与右上角点,分别与窗口的左下与右上角点相对应。far参数确定远端剪裁平面,如下图。

image-20211018081635320

setNominalViewingTransform()方法

  • public void setNominalViewingTransform()方法,在当前三维观察范围基础上,设置ViewPlatform变换中名义上的观察距离。如果ViewAttachPolicy不是默认的View.NOMINAL_HEAD,则该方法无效。
  • 默认的ViewPlatform对象的原点在(0.0,0.0,0.0)处。应用该方法将使ViewPlatform原点沿着z轴往后移动,以便使处于坐标原点的跨越标准化x轴范围-1与+1的对象能够在全窗口宽度内显示。这可以通过在ViewPlatform的坐标变换中设置一个1/(tan(fieldofView/2))平移变换实现。
    public void setNominalViewingTransform()
    {
        if(viewPlatform.getViewAttachPolicy() == 0)
        {
            double d;
            if(viewerList.size() == 0)
            {
                d = 0.78539816339744828D;
            } else
            {
                if(viewerList.size() > 1)
                    throw new RuntimeException(J3dUtilsI18N.getString("ViewingPlatform0"));
                Viewer viewer = (Viewer)viewerList.keys().nextElement();
                View view = viewer.getView();
                d = view.getFieldOfView();
            }
            Transform3D transform3d = new Transform3D();
            //这里是上文的1/(tan(fieldofView/2))!!!!!!!!
            double d1 = 1.0D / Math.tan(d / 2D);
            
            transform3d.set(new Vector3d(0.0D, 0.0D, d1));
            getViewPlatformTransform().setTransform(transform3d);
        }
    }
  • 如果没有Viewer的对象与该ViewingPlatform对象相关联,则默认的fieldofView值为PI/4.0,PI为180度的弧度值。计算下来,1/(tan(fieldofView/2))的值约为3.414米,也就是视点位于z轴上的3.414米处,观察角度范围为PI/4.0。

包的关系

image-20211018083346651

image-20211018083325718

Shape3D类及方法

image-20211018083930745

  • Shape3D类定义所有的几何体。它包含了几何体与该几何体的外观属性。几何体组件部分定义三维空间体的几何形状外观属性部分定义颜色、材质等属性
  • Shape3D类叶子节点定义所有的几何对象。一个Shape 3D类的对象包含一个Geometry几何组件对象的列表和唯一的一个Appearance外观组件对象。几何对象定义三维形体的几何数据。外观对象定义该三维形体的外观属性,包括颜色、材质、纹理等。

Shape3D类中等价类的概念

  • 在一个Shape3D的几何对象列表中的所有元素必须属于同一个等价类,也就是属于同一种基本的几何类型。对GeometryArray类的所有子类,所有的点对象是等价的,所有线对象是等价的,所有多边形对象是等价的。属于同一个等价类的几何对象可以加入同一个Shape 3D类的对象中。

  • 以下都是Geometry的子类,是等价的

GeometryArray(point): [Indexed]PointArrayGeometryArray(line):  [Indexed]{LineArray, LineStripArray}GeometryArray(polygon):[Indexed{TriangleArray,TriangleStripArray,TriangleFanArray, QuadArray}CompressedGeometryText3D

Shape3D类的构造函数

(1)Shape3D():用默认参数创建一个Shape3D节点。
(2)Shape3D(Geometry geometry):用给定的几何组件geometry和一个空的appearance组件创建一个Shape3D节点。
(3)Shape3D(Geometry geometry, Appearance appearance):用给定的geometry几何组件和appearance组件创建一个Shape3D节点。

Shape3D类的方法

(1)setGeometry(Geometry geometry)方法:将几何组件geometry设置在几何组件列表的序号Index=0处。如果Index=0处原来有几何组件,则用新的覆盖原来的。
(2)insertGeometry(Geometry geometry,int index)方法:将geometry几何组件插入到Shape3D节点的几何组件列表的index处
(3)addGeometry(Geometry geometry)方法:将geometry几何组件附加到Shape3D节点的几何组件列表的最后,如果是空表,则附加到Index=0处。
(4)setAppearance(Appearance appearance)方法:设置Shape3D节点的appearance外观组件。如果没有设置该项,则用默认值。

image-20211018085223512

Appearance类及方法

​ Appearance类对象定义所有与显示相关的外观状态,这些状态可设置为一个Shape3D节点的组件对象(Component Object)。

属性设置

  • 颜色属性:通过ColoringAttributes类颜色

  • 点的属性:通过PointAttributes 类定义与点相关的属性,包括点的大小、是否使用反走样等。

  • 线属性:通过LineAttributes类定义与线相关的属性,这些属性包括线型、线宽、是否使用反走样等。

  • 多边形属性:通过 PolygonAttributes 类定义与多边形相关的属性,包括面侧的选择、显示模式(点显示模式、线显示模式、填充面显示模式)等。

  • 可视化模式(Rendering Attributes):通过RenderingAttributes类的对象定义与可视化相关的参数,包括alpha测试函数,光栅化操作,是否不考虑顶点的颜色,是否显示不可见物体,是否使用深度缓存等

  • 透明度属性(Transparency attributes):通过TransparencyAttributes类定义三维型体透明度属性

  • 材质(Material):通过Material类定义三维型体在光照条件下外观,包括环境光颜色(ambient color)、散射光颜色(diffuse color)、反射光颜色(specular color)、发射光颜色(emissive color)、光亮度(shininess)。这些属性都定义在Material类对象中

  • 纹理(Texture):在Texture类的对象中定义在纹理匹配时的纹理图像与过滤参数 。

  • 纹理属性(Texture attributes): 在TextureAttributes类的对象中定义与纹理匹配相关的属性,如纹理模式(texture mode)、纹理转换(texture transform)、 混合颜色(blend color)、透视矫正模式(perspective correction mode)。

  • 纹理坐标产生(Texture coordinate generation):在 TexCoordGeneration 类的对象中定义与纹理坐标产生相关的属性,如纹理坐标产生功能是否已设置,坐标格式(2D或3D),纹理坐标的产生模式(对象线性(object linear)、视点线性(eye linear)、球面反射匹配(spherical reflection mapping)),RST坐标平面方程(the R, S, and T coordinate plane equations)。

Appearance类的构造函数与方法

1.Appearance类的构造函数public Appearance(),应用默认参数创建一个Appearance类的对象。

2.Appearance类的方法如下

  • setColoringAttributes(ColoringAttributes coloringAttributes):向Appearance类的对象设置与颜色属性有关的ColoringAttributes类的对象。
  • setPointAttributes(PointAttributes pointAttributes):向Appearance类的对象设置与点属性有关的PointAttributes类的对象。
  • setLineAttributes(LineAttributes lineAttributes):向Appearance类的对象设置与线属性有关的LineAttributes类的对象。
  • setPolygonAttributes(PolygonAttributes polygonAttributes):向Appearance类的对象设置与多边形属性有关的PolygonAttributes类的对象。
  • setTransparencyAttributes(TransparencyAttributes transparencyAttributes):向Appearance类的对象设置与透明属性有关的TransparencyAttributes类的对象。
  • setMaterial(Material material):向Appearance类的对象设置与材质有关的Material类的对象。
  • setRenderingAttributes(RenderingAttributes renderingAttributes):向Appearance类的对象设置与显示模式有关的RenderingAttributes类的对象。
  • setTexCoordGeneration(TexCoordGeneration texCoordGeneration):设置生成纹理坐标的TexCoordGeneration类的对象。
  • setTexture(Texture texture):设置纹理Texture类的对象。
  • setTextureAttributes(TextureAttributes textureAttributes):设置有关纹理属性的TextureAttributes类的对象。

BranchGroup类

  • 一个BranchGroup作为一个场景图分支的根。
  • BranchGroup对象是唯一能插入到一个Locale对象中的对象。以BranchGroup节点为根的场景图子图是一个编辑单元。针对一个BranchGroup,有下列操作。
  • 一个BranchGroup可以通过调用其compile()方法对其进行编译,这种编译是针对整个子图的。并且,对包含在子图中的任一个BranchGroup节点也都要进行编译
  • 一个BranchGroup节点可通过一个Locale节点将其加入到一个虚拟空间中(VirtualUniverse),此时,该子图处于激活状态。

TransformGroup类

TransformGroup节点通过Transform3D对象定义了一个唯一的3D空间坐标变换,该变换可对其子节点进行位置、方向及比例变换。

image-20211018090950910

TransformGroup类的构造函数

(1)TransformGroup()构造函数:用一个单位矩阵变换创建一个TransformGroup 对象。
(2)TransformGroup(Transform3D t1)构造函数:用一个变换矩阵t1创建一个TransformGroup对象。
(3)setTransform(Transform3D t1)方法:设置该TransformGroup的坐标变换矩阵为t1。
(4)getTransform(Transform3D t1)方法:获取该TransformGroup中的坐标变换矩阵,并将该矩阵值复制到矩阵t1中。

GeometryArray类

  • GeometryArray类是PointArray类、LineArray类、TriangleArray类、QuadArray类、
  • GeometryStripArray类与IndexedGeometryArray类的直接父类,
  • GeometryArray类中定义的构造函数和方法可被其子类继承。
  • public abstract class GeometryArray extends Geometry
    GeometryArray类的对象中包含有独立的位置坐标数组、颜色数组、法向量数组、纹理坐标数组和顶点属性。
  • 在数组中的所有颜色值必须在[0.0,1.0]范围内。所有的法向量必须是模长为1的单位向量。

GeometryArray类的构造函数

  • GeometryArray(int vertexCount,int vertexFormat)构造函数:用给定数量的顶点与顶点格式创建一个空的GeometryArray对象。

    • vertexCount:表示在GeometryArray中几何体所包含的顶点数

    • vertexFormat:表示这些顶点的格式,是一个多选项
      1)COORDINATES:表示在该GeometryArray数组中包含顶点的坐标,并且该项是一个必选项;
      2)NORMALS:表示包含每个顶点的法向量;

      3)COLOR_3或COLOR_4:表示每个顶点颜色
      COLOR_3表示没有alpha信息,也就是指顶点数组包括没有透明度的颜色;
      COLOR_4表示有alpha信息,也就是指顶点数组包括含有透明度的颜色;

      不指定COLOR_3或COLOR_4顶点格式颜色:GeometryArray对象中的每个顶点的默认颜色是白色。
      指定了COLOR_3或COLOR_4顶点格式颜色,则GeometryArray对象中的每个顶点的默认颜色是黑色
      4)TEXTURE_COORDINATE_2、TEXTURE_COORDINATE_3、TEXTURE_COORDINATE_4:分别表示每个顶点的2D、3D或4D纹理坐标;
      5)VERTEX_ATTRIBUTES:表示包含一个或多个顶点属性数组

  • GeometryArray(int vertexCount,int vertexFormat,int texCoordSetCount,int[] texCoordSetMap)构造函数 用给定的顶点数、顶点格式、纹理坐标集数、纹理坐标匹配数组创建一个空的GeometryArray对象。其它所有参数将采用默认值。

    • texCoordSetCount:表示在该GeometryArray对象中纹理坐标集的数量。如果vertexFormat不包含TEXTURE_COORDINATE_2或者TEXTURE_COORDINATE_3参数,则不用texCoordSetCount参数。
    • texCoordSetMap:表示一个将纹理坐标集匹配到纹理单元的数组。对于在相关Appearance对象中的每一个纹理单元,该数组都通过纹理单元数检索。

GeometryArray类的方法

setCoordinate方法相关

  • setCoordinate方法

    这四个方法从index序号处开始设置GeometryArray对象中顶点数组的坐标值。整个源数组中的坐标值全部复制到GeometryArray对象的顶点数组中。

    public void setCoordinates(int index,float[] coordinates)public void setCoordinates(int index,double[] coordinates)public void setCoordinates(int index,Point3f[] coordinates)public void setCoordinates(int index,Point3d[] coordinates)

    这四个方法对GeometryArray对象中的顶点数组从index序号处开始设置值,对float[] coordinates一维数组中的值从start序号处开始取length个顶点的坐标值给GeometryArray对象中的顶点数组复制值。
    Index:是该GeometryArray对象中的目的顶点数组中的起始序号;
    Start:是源数组float[] coordinates一维数组中的起始序号;
    Length:是源数组float[] coordinates一维数组中从Start起始序号开始由Length值确定的顶点区间;

  • Point3f类、Point3d类

    ​ Point3f类、Point3d类分别包含浮点型与双精度型的x、y、z值。Point3f是javax.vecmath.Tuple3f包中定义的一个类,用该类的构造函数Point3f(float x,float y,float z)设置一个Point3f对象的x、y、z坐标分量值如果创建一个Point3f 类的对象point,Point3f point=new Point3f(x,y,z);则point.x、Point.y、Point.z分别表示该点的x、y、z坐标值。对该点的引用与赋值方式相同。Point3f()方法将创建一个三个坐标值都为0.f的点如果处理的是双精度数,则有Point3d类及其Point3d(double x,double y,double z)构造函数,用法相同.

  • *setCoordinate(int index,float[] coordinate)*方法

    ​ setCoordinate(int index,float[] coordinate),设置一个点的三个坐标值,*index为点的编号。float[] coordinate是一个一维数组,分别表示一个点的x、y、z坐标,也就是coordinate[0]、coordinate[1]、coordinate[2]*分别表示该点的x、y、z坐标值。

    setCoordinate(int index,double[] coordinate)setCoordinate(int index, Point3f coordinate)setCoordinate(int index, Point3d coordinate)

    这三个方法分别设置index序号处顶点坐标的x、y、z

setcolor方法相关

  • setColor方法

    设置单个点颜色

    public void setColor(int index, float[] color)public void setColor(int index, Color3f color)public void setColor(int index, Color4f color)

    设置多个点颜色

    setColors(int index,float[] colors)setColors(int index,Color3f[] colors)setColors(int index,Color4f[] colors)setColors(int index,float[] colors,int start,int length)setColors(int index,Color3f[] colors,int start,int length)setColors(int index,Color4f[] colors,int start,int length)
  • Color3f类,Color4f 类

    • Color3f(float x,float y,float z)方法是Color3f类的一个构造函数,该构造函数通过设置红、绿、蓝(R、G、B)三个分量的值来表示一种颜色。三个分量的值都必须在0.0到1.0之间。Color3f类对象的创建:Color3f color=new Color3f(0.2f,0.5f,1.f),则color.x=0.2f,color.y=0.5f,color.z=1.f。color.x表示红颜色值,color.y表示绿颜色值,color.z表示蓝颜色值。Color3f()将创建一个三个分量为0的颜色。
      setColor(int index, Color3f color)方法:设置在index处的点的颜色值,Color3f与Point3f类似,用三个浮点数表示一种颜色组合,每个浮点数的值都在0.0到1.0之间

    • Color4f类的一个构造函数为Color4f(float x,float y,float z,float w),由单精度的4个元素值x、y、z和w表示一种4元素颜色值。x、y、z和w值分别表示红、绿、兰和alpha值。颜色和alpha值取值范围应该在[0.0, 1.0]。

      alpha值

      • COLOR_3表示没有alpha信息,也就是指顶点数组包括没有透明度的颜色
      • COLOR_4表示有alpha信息,也就是指顶点数组包括含有透明度的颜色
      • 当不指定COLOR_3或COLOR_4顶点格式颜色时,则GeometryArray对象中的每个顶点的默认颜色是白色
      • 当指定了COLOR_3或COLOR_4顶点格式颜色,则GeometryArray对象中的每个顶点的默认颜色是黑色

setNormal方法

setNormals(int index,float[] normals)setNormals(int index,Vector3f[] normals)setNormals(int index,float[] normals,int start,int length)setNormals(int index,Vector3f[] normals,int start,int length)

方法参数解释:

  • 对index序号处的点设置单位法向量。
  • 法向量的三个分量分别为:normal[0]、normal[1]、normal[2]。该法向量与index处的顶点相对应,是index处的顶点的法向量。
  • Vector3f类表示由三个浮点数形成的一个向量,和Point3f类类似。

点PointArray类

  • PointArray类是组织与定义点的数组类。

  • PointArray类是GeometryArray类的子类,因此,它继承了GeometryArray类中定义的方法与变量。vertexCount(定点数)与vertexFormat(定点格式)参数含义与GeometryArray类中含义相同。

  • PointArray类构造函数如下:
    PointArray(int vertexCount,int vertexFormat);

PointAttributes类

  • PointAttributes类的对象用来定义点的各种属性
  • 点的属性包括:
    • Size:定义点的大小,以Pixel象素为单位。缺省时点的大小是一个象素单位。
    • Antialiasing:英文含义是反走样,当一个点的大小大于一个象素单位时,为了使点在显示时外形接近于一个圆形,则需要设置该参数。如果没有设置该参数,也就是缺省,则该点显示为一个由多个象素围成的正方形。

PointAttributes类的构造函数

  • PointAttributes():用默认参数创建一个PointAttributes对象。
  • PointAttributes(float pointSize,Boolean pointAntialiasing):用给定的参数创建一个PointAttributes对象。

PointAttributes类的方法

  • setPointSize(float pointSize):以象素为单位设置点的大小
  • setPointAntialiasingEnable(boolean state)方法:打开或关闭反走样开关。当state值为true时,表示打开反走样功能;当state值为false时,表示关闭点的反走样功能。

运用上文类进行代码实战——DisplayPoints

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.PointArray;
import javax.media.j3d.PointAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class DisplayPoints extends Applet{
	
	public BranchGroup CreateBranchGroup() {
		BranchGroup branchGroup=new BranchGroup();
		// 创建球心在坐标系原点球形范围,指定圆心(三维)和半径
		BoundingSphere boundingSphere=new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
		Color3f Bgcolor=new Color3f(1.0f,1.0f,1.0f);
		Background background=new Background(Bgcolor);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);
		
		//TransformGroup对象存储了几何形变比如平移和旋转,此处设置读写即是否允许旋转等操作
		//作为Group类的子类,TransformGroup类的实例用于创建场景图并且都其子结点的集合
		TransformGroup group=new TransformGroup();
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(group);
		
		//定义鼠标对场景的旋转,平移,放大功能 以下几个对象都加入TransformGroup的实例
		//旋转
		MouseRotate mouseRotate=new MouseRotate();
		mouseRotate.setTransformGroup(group);
		mouseRotate.setSchedulingBounds(boundingSphere);
		//加到BranchGroup中
		branchGroup.addChild(mouseRotate);
		//放大
		MouseZoom mouseZoom=new MouseZoom();
		mouseZoom.setTransformGroup(group);
		mouseZoom.setSchedulingBounds(boundingSphere);
		branchGroup.addChild(mouseZoom);
		//平移
		MouseTranslate mouseTranslate=new MouseTranslate();
		mouseRotate.setTransformGroup(group);
		mouseRotate.setSchedulingBounds(boundingSphere);
		branchGroup.addChild(mouseTranslate);
		
		//Shape3D类定义所有的几何体。它包含了几何体与该几何体的外观属性
		//Shape3D类叶子节点定义所有的几何对象。一个Shape 3D类的对象包含一个Geometry几何组件对象的列表和唯一的一个Appearance外观组件对象。
		//Geometry对象(这里是他的子类PointArray),Appearance对象都需加入Shape3D
		Shape3D shape3d=new Shape3D();
		//定义顶点坐标
		float vertexes[] = { .5f, 0.6f, 0.0f, -0.5f, 0.6f, 0.0f, 0.5f, 0.05f, 0.0f, -0.5f, 0.05f, 0.f, -0.5f, -0.7f,
				0.0f, 0.5f, -0.7f, 0.1f };
		//定义定点颜色
		float pointColors[] = 
			{ 1.0f, 0.f, 0.0f, 
				0.0f, 1.f, 0.f, 
				0.0f, 0.f, 1.0f, 
				1.0f, 1.0f, 0.f, 
				0.0f, 1.0f, 1.f, 
				1.f,0.f, 1.0f };

		 // 定点数
		int vCount=6;
		//PointArray类是组织与定义点的数组类
		//COORDINATES:表示在该GeometryArray数组中包含顶点的坐标,并且该项是一个必选项
		//COLOR_3表示没有alpha信息,也就是指顶点数组包括没有透明度的颜色
		PointArray array=new PointArray(vCount, PointArray.COORDINATES | PointArray.COLOR_3);
		//从0序号处开始设置GeometryArray对象中顶点数组的坐标值
		array.setCoordinate(0, vertexes);
		//从0序号处开始设置GeometryArray对象中顶点数组的颜色值
		array.setColor(0, pointColors);
		//PointAttributes类的对象用来定义点的各种属性
		PointAttributes attributes=new PointAttributes();
		attributes.setPointSize(70.0f);
		//打开或关闭反走样开关 打开为圆形关闭为正方形
		attributes.setPointAntialiasingEnable(true);
		
		//以上设置均为加入transformgroup
		Appearance appearance=new Appearance();
		appearance.setPointAttributes(attributes);
		shape3d.setGeometry(array);
		shape3d.setAppearance(appearance);
		group.addChild(shape3d);
		branchGroup.compile();
		return branchGroup;
	}
	
	public DisplayPoints() {
		setLayout(new BorderLayout());
		GraphicsConfiguration gc=SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d=new Canvas3D(gc);
		add("Center",canvas3d);
		//获取返回值
		BranchGroup branchGroup=CreateBranchGroup();
		//设置SimpleUniverse,由系统选择视点在z轴的正向,观察方向沿z轴反向,参数为canvas3D对象
		SimpleUniverse simpleUniverse=new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
	}
	public static void main(String[] args) {
		//通过MainFrame显示图象 参数MainFrame(Applet applet1, int i, int j) i,j为宽高
		new MainFrame(new DisplayPoints(), 300, 300);
	}

}

IndexedPointArray类

IndexedPointArray类的构造函数
从定义好的所有点的坐标与颜色数组中选择出一部分点进行显示。

  • IndexedPointArray(int vertexCount,int vertexFormat,int indexCount):用给定的参数创建一个空的IndexedPointArray类的对象
  • 各参数含义如下:
    • vertexCount:表示顶点的总数
    • vertexFormat:表示顶点的格式
    • indexCount:表示在已经定义的顶点中所选择的索引点的总数。

方法:

//设置指定索引点处的坐标。
SetCoordinateint index,Point3f coordinate)
//设置index与新的坐标索引相对应。
SetCoordinateIndexint index,int coordinateindex)
//设置从index开始与新的坐标索引数组中的索引相对应。
setCoordinateIndices(int index,int[] coordinateIndices)
//设置在index处点的颜色值
setColor(int index, Color3f color)
//设置新的颜色索引
setColorIndex(int index,int colorIndex)
//设置从index开始与新的点颜色索引数组中的索引相对应。
setColorIndices(int index,int[] colorIndices)
//用来设置法向量索引。
setNormalIndex(int index,int normalIndex)
setNormalIndices(int index,int[] normalIndices)

参数:

  • Index是起始索引;coordinateindex、coordinateIndices是新坐标索引。

  • Color3f与Point3f类似,用三个浮点数表示一种颜色组合,每个浮点数的值都在0.0到1.0之间。

  • Index是顶点索引,colorindex是新颜色索引。

  • 在使用setCoordinateIndices、setColorIndices时,首先要创建包括具体索引的整形数组coordinateIndices、colorIndices.

运用进上文实战代码DisplayPoints

		 // 定点数
		int vCount=6;
		//索引个数
		int indexCount=3;
		//数组中存的是索引 第0个第3个第5个
		int index[]={0,3,5};
		//PointArray类是组织与定义点的数组类
		//COORDINATES:表示在该GeometryArray数组中包含顶点的坐标,并且该项是一个必选项
		//COLOR_3表示没有alpha信息,也就是指顶点数组包括没有透明度的颜色
		IndexedPointArray array=new IndexedPointArray(vCount, PointArray.COORDINATES|PointArray.COLOR_3,indexCount);
		//从0序号处开始设置GeometryArray对象中顶点数组的坐标值
		array.setCoordinates(0, vertexes);
		array.setCoordinateIndices(0, index);
		//从0序号处开始设置GeometryArray对象中顶点数组的颜色值
		array.setColors(0, pointColors);
		array.setColorIndices(0, index);

image-20211022194837927

线LineArray类

LineArray构造函数

  • LineArray(int vertexCount,int vertexFormat)应用相关参数创建一个空的LineArray类的对象。该类生成的线段是不连续的,线段的连接方式:0-1,2-3,4-5等,其中,1、2之间与3、4之间不连接。
  • vertexCount:表示生成多段线的总顶点数。
  • vertexFormat:表示这些点坐标的格式与GeometryArray类中的参数相同。

LineAttributes类

该类定义所有与线的显示相关的属性与状态

LineAttributes类的构造函数

  • LineAttributes():用默认参数创建一个LineAttributes类的对象。
    ​ 各默认参数如下:

    • line width:1;
    • line pattern:PATTERN_SOLID;
    • pattern mask: 0xffff;pattern scale factor:1;
    • line antialiasing:false。
  • LineAttributes(float lineWidth,int linePattern,boolean lineAntialiasing),用相关参数创建一个LineAttributes类的对象。

各参数含义:

  • lineWidth:线宽,以像素为单位;
  • linePattern:线型,PATTERN_SOLID,PATTERN_DASH,PATTERN_DOT,PATTERN_DASH_DOT;
  • lineAntialiasing:是否打开反走样标志。

LineAttributes类的方法:

  • setLineWidth(float lineWidth)方法:改变线宽,以象素为单位,缺省时线宽为一个象素宽度。

  • setLinePattern(int linePattern)方法:改变线型

    线类型定义包括:

    • PATTERN_SOLID,为实线,这也是缺省的线条类型。

    • PATTERN_DASH,为虚线,以8个象素为单位交替画线与不画线。

    • PATTERN_DOT,为点线。

    • PATTERN_DASH_DOT,虚的点画线。

    • PATTERN_USER_DEFINED,定义用户自定义的线类型。

      image-20211023181305061

  • setLineAntialiasingEnable(Boolean state)方法:设置是否打开或关闭反走样开关。参数state的取值为true或false。true表示打开反走样功能,false表示关闭。缺省时反走样功能关闭。

运用上文类进行代码实战——DisplayLines

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.LineArray;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class DisplayLines extends Applet{

	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup=new BranchGroup();
		//背景
		BoundingSphere boundingSphere=new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
		Color3f color3f=new Color3f(1.f,1.f,1.f);
		Background background=new Background(color3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);
		//光线
		Color3f dircolor3f =new Color3f(1.f,0.f,0.f);
		//指向(0.f,0.f,-1.f)而不是光源在这 z轴对向我们 x轴向右 y轴向上
		Vector3f vector3f=new Vector3f(0.f,0.f,-1.f);
		DirectionalLight directionalLight=new DirectionalLight(dircolor3f,vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);
		//移动权限
		TransformGroup group=new TransformGroup();
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(group);

		//鼠标旋转放大平移
		MouseRotate mouseRotate=new MouseRotate();
		mouseRotate.setTransformGroup(group);
		branchGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);
		
		MouseZoom mouseZoom=new MouseZoom();
		mouseZoom.setTransformGroup(group);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);
		
		MouseTranslate mouseTranslate=new MouseTranslate();
		mouseTranslate.setTransformGroup(group);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);
		//将线加入 b必须是加到TransformGroup对象 否则上文设置无意义 无法移动
		group.addChild(shape3d());
		branchGroup.compile();
		return branchGroup;
	}

	public Shape3D shape3d() {
		Shape3D shape3d=new Shape3D();
		//定义点坐标
		float vertexes[]={   .8f,0.5f,0.f,  -0.8f,.8f,0.0f,
		                    0.8f,0.0f,0.0f,  -0.8f,0.5f,0.0f,
		                    0.8f,-0.5f,0.0f, -0.8f,0.2f,0.0f };
		//定义颜色
		float colors[]= { 1.0f,0.f,.0f,   0.0f,1.f,.0f,
		                  0.0f,0.f,1.f,   1.0f,1.0f,0.f,
		                  0.0f,1.0f,1.f,  1.f,0.f,1.0f};
		//定义线数组 6位6个顶点
		LineArray array=new LineArray(6, LineArray.COORDINATES|LineArray.COLOR_3);
		array.setCoordinates(0, vertexes);
		array.setColors(0, colors);
		//定义线属性
		LineAttributes attributes=new LineAttributes();
		attributes.setLineWidth(20.f);
		attributes.setLineAntialiasingEnable(true);
		attributes.setLinePattern(LineAttributes.PATTERN_SOLID);
		Appearance appearance=new Appearance();
		appearance.setLineAttributes(attributes);
		shape3d.setGeometry(array);
		shape3d.setAppearance(appearance);
		return shape3d;
	}
	public DisplayLines() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration=SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d=new Canvas3D(configuration);
		add("Center",canvas3d);
		BranchGroup branchGroup=createBranchGroup();
		SimpleUniverse simpleUniverse=new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MainFrame(new DisplayLines(), 300,300);
	}

}

image-20211023190435738

IndexedLineArray类

构造函数:

  • IndexedLineArray(int vertexCount,int vertexFormat,int indexCount)
  • 用相关参数创建一个空的IndexedLineArray对象
  • 各参数含义:
    • vertexCount:表示顶点的总数
    • vertexFormat:表示顶点的格式
    • indexCount:表示在已经定义的顶点中所选择的索引点的总数。

方法(不确定 应该是)

//设置指定索引点处的坐标。
SetCoordinateint index,Point3f coordinate)
//设置index与新的坐标索引相对应。
SetCoordinateIndexint index,int coordinateindex)
//设置从index开始与新的坐标索引数组中的索引相对应。
setCoordinateIndices(int index,int[] coordinateIndices)
//设置在index处点的颜色值
setColor(int index, Color3f color)
//设置新的颜色索引
setColorIndex(int index,int colorIndex)
//设置从index开始与新的点颜色索引数组中的索引相对应。
setColorIndices(int index,int[] colorIndices)
//用来设置法向量索引。
setNormalIndex(int index,int normalIndex)
setNormalIndices(int index,int[] normalIndices)

运用进上文实战代码DisplayLines

  • 修改其shape3D方法

    	public Shape3D shape3d() {
    		Shape3D shape3d=new Shape3D();
    		//定义点坐标
    		float vertexes[]={   .8f,0.5f,0.f,  -0.8f,.8f,0.0f,
    		                    0.8f,0.0f,0.0f,  -0.8f,0.5f,0.0f,
    		                    0.8f,-0.5f,0.0f, -0.8f,0.2f,0.0f };
    		//定义颜色
    		float colors[]= { 1.0f,0.f,.0f,   0.0f,1.f,.0f,
    		                  0.0f,0.f,1.f,   1.0f,1.0f,0.f,
    		                  0.0f,1.0f,1.f,  1.f,0.f,1.0f};
    		//IndexedLineArray所需参数
    		int vCount=6; 
    		int indexCount=4;	
    		int index[]={0,1,3,5};
    		//定义线数组 6位6个顶点
    		IndexedLineArray array=new IndexedLineArray(vCount, LineArray.COORDINATES|LineArray.COLOR_3,indexCount);
    		array.setCoordinates(0, vertexes);
    		array.setCoordinateIndices(0, index);
    		array.setColors(0, colors);
    		array.setColorIndices(0, index);
    		//定义线属性
    		LineAttributes attributes=new LineAttributes();
    		attributes.setLineWidth(20.f);
    		attributes.setLineAntialiasingEnable(true);
    		attributes.setLinePattern(LineAttributes.PATTERN_SOLID);
    		Appearance appearance=new Appearance();
    		appearance.setLineAttributes(attributes);
    		shape3d.setGeometry(array);
    		shape3d.setAppearance(appearance);
    		return shape3d;
    	}
    
  • 结果:

    image-20211024095505447

LineStripArray类

LineStripArray类的构造函数

  • LineStripArray(int vertexCount,int vertexFormat,int[] stripVertexCounts),用给定参数创建一个空的LineStripArray类的对象。

  • Strip的英文含义是带、条的意思。

  • 该构造函数将定义好的数据点分组,然后分别连成几段连续的线段,分成几个组,就连成几条带(几个Strip)。

  • 各条之间互不连接。

  • 下图0123和4567分别为两个组,是两个带(带之间不连接,组内连续)。

    image-20211024095906121

  • 各参数含义如下:

    • vertexCount:LineStripArray类的对象中包含的总的顶点数
    • vertexFormat:顶点格式。
    • stripVertexCounts一维整形数组:
      **1.**在一个LineStripArray类的对象中可能包含有多个子Strip,子Strip的数量由stripVertexCounts一维整形数组所包含的元素个数确定
      2.每个Strip包含属于该Strip的顶点,每个子Strip所包含的顶点数由相应的stripVertexCounts一维整形数组的元素值确定
      3.所有Strip中的顶点总数之和为vertexCount的值,
      4.一维数组stripVertexCounts包含有多少个元素,LineStripArray类的对象就包含几个子Strip,每个Strip根据其对应的stripVertexCounts[i]元素中包含的顶点数(也就是
      stripVertexCounts[i]元素的值
      )按照一维数组元素的次序依次从前向后从坐标数组中取顶点坐标值。因此,vertexCount=stripVertexCounts[0]+stripVertexCounts[1]+…+ stripVertexCounts[n]

运用上文类进行代码实战——DisplayLineStrip

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.LineStripArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class DisplayLineStrip extends Applet{
	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup = new BranchGroup();
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Color3f color3f = new Color3f(1.f, 1.f, 1.f);
		Background background = new Background(color3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);
		Color3f dirColor3f = new Color3f(1.f, 0.f, 0.f);
		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);

		TransformGroup group = new TransformGroup();
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(group);
		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(group);
		branchGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);

		MouseTranslate mouseTranslate = new MouseTranslate();
		mouseTranslate.setTransformGroup(group);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);

		MouseZoom mouseZoom = new MouseZoom();
		mouseZoom.setTransformGroup(group);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);
		// 图形
		group.addChild(shape3d());
		branchGroup.compile();
		return branchGroup;

	}

	public Shape3D shape3d() {
		Shape3D shape3d = new Shape3D();
		float vertexes[] = { -0.8f, 0.5f, 0.0f, 0.8f, 0.9f, 0.0f, -0.8f, 0.2f, 0.0f, 0.8f, 0.7f, 0.0f, -0.8f, -0.2f,
				0.0f, 0.8f, -0.5f, 0.0f, -0.8f, -0.5f, 0.0f, 0.8f, -.8f, 0.0f, };
		float colors[] = { 1.0f, 0.f, .0f, 0.0f, 1.f, .0f, 0.0f, 0.f, 1.f, 1.0f, 1.0f, 0.f, 0.0f, 1.0f, 1.f, 1.f, 0.f,
				1.0f, 0.0f, .0f, 0.f, 0.3f, 0.8f, 0.0f, };
		int [] substrips=new int [2];
		substrips[0]=4;
		substrips[1]=4;
        		//数组只有一个元素就只有一个带会全部连续,使用下两行会如此
//		int[] substrips=new int[1];
//		 substrips[0]=8;  
		LineStripArray array=new LineStripArray(8, LineStripArray.COORDINATES|LineStripArray.COLOR_3, substrips);
		array.setCoordinates(0, vertexes);
		array.setColors(0, colors);
		LineAttributes attributes=new LineAttributes();
		attributes.setLineWidth(9.0f);
		attributes.setLineAntialiasingEnable(true);
		attributes.setLinePattern(0);
		Appearance appearance=new Appearance();
		appearance.setLineAttributes(attributes);
		shape3d.setGeometry(array);
		shape3d.setAppearance(appearance);
		return shape3d;

	}
	public DisplayLineStrip() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration=SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d=new Canvas3D(configuration);
		add("Center",canvas3d);
		BranchGroup branchGroup=createBranchGroup();
		SimpleUniverse simpleUniverse=new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MainFrame(new DisplayLineStrip(), 300,300);
	}

}

结果:

image-20211024102932706

多边形属性类PolygonAttributes类

  • PolygonAttributes类用来定义多边形(这些基本多边形包括:三角形,三角形带,三角形扇,四边形)显示时的相关属性

  • 多边形属性包括以下内容。

    • 显示模式Rasterization mode
      定义多边形显示方式,以三种方式显示。
      1.以点的方式显示*:POLYGON_POINT:多边形以顶点方式显示,则只显示所有顶点。
      2.轮廓线方式显示:POLYGON_LINE:多边形以线方式显示。
      3.填充多边形方式显示:POLYGON_FILL:以填充的多边形面的方式显示,这种模式是缺省显示模式。

    • 对面侧的选择Face culling
      Cull英文含义就是剔除的意思。因为一个面有两个侧面,在看一个面的时候,一次只能看到一个侧面,另一个侧面不可见。选择的原则是按照法向量进行。

      各参数含义如下
      CULL_NONE:在计算与显示一个面时,一个面的两侧都参加计算,也就是不分正反面。

      image-20211027204416040

      CULL_BACK:只显示与计算正面(法向量指向的一面),不计算反面。这是缺省时的显示模式。

      image-20211027204525223

      CULL_FRONT:只显示与计算反面(法向量反向的一面),不计算正面

      image-20211027204555320

      实际运用:
      1.如果曲面的所有小多边形面的法向量指向不一致,则采用第一种显示模式。这种显示模式要对一个面的两侧都进行计算,在个体比较复杂时,计算量比较大
      2.如果曲面的所有小多边形面的法向量指向一致,则采用第二种、第三种显示模式。这种显示模式只对一个面的一侧进行计算,在个体比较复杂时,能节约大约一半的计算量

      注意:
      Back-face normal flip:在多边形显示之前是否不考虑点的反向法向量。True:表示考虑点的反向法向量;false:表示不要考虑。缺省值为false。

  • PolygonAttributes()构造函数:用缺省参数创建一个空的PolygonAttributes类的对象。

    各项参数缺省值如下:

    cull face : CULL_BACK	        //对面侧选择
    back face normal flip : false  //是否考虑反向法向量
    polygon mode : POLYGON_FILL   //显示模式
    polygon offset : 0.0
    polygon offset factor : 0.0
    
  • PolygonAttributes方法

    • *setCullFace(int cullFace)*方法:该方法用来设置PolygonAttributes类的对象中的cullFace变量的值。其值为下列值中的一种:CULL_NONE、CULL_FRONT、CULL_BACK
    • *setPolygonMode(int polygonMode)*方法:该方法用来设置PolygonAttributes类的对象中的显示模式项的值。其值为下列值中的一种POLYGON_FILL、POLYGON_LINE、POLYGON_POINT。
    • setBackFaceNormalFlip(boolean backFaceNormalFlip)方法:该方法用来设置PolygonAttributes类的对象中的BackFaceNormalFlip项的值。其值为下列值中的一种:True、False。在多边形显示之前是否不考虑点的反向法向量。True:表示在多边形显示之前考虑点的反向法向量;false:表示在多边形显示之前不考虑点的反向法向量。缺省值为false。

多边形可视化的填充算法

  • 多边形在显示时的填充算法也称为区域填充算法。区域填充算法就是在给定的平面多边形区域内,用给定的颜色通过某种填充算法填充该多边形区域内的所有象素点。

  • 区域填充算法主要有两种算法:(1)种子填色算法;(2)扫描线填色算法。下面就分别介绍。

    • 种子填色算法:

      • 种子填色算法首先在要填充的多边形区域内选择一个填色种子点(Seed Point),然后以该种子点为基础,通过与多边形边界的象素点相比较进行填色。因此,这种种子填色算法又称为边界填色(Boundary Filling)算法。它的功能是,给出多边形光栅化后的边界位置及边界颜色代码boundary_color,以及多边形内的一个种子点P(x,y)位置,要求用给定的颜色fill_color填满该多边形。在填充时要判断当前填充象素点与边界象素点之间的关系。

      • 种子填色算法主要有两种:1)四邻法;2)八邻法。
        1).四邻法所走的填充路线为:上、下、左、右。在填充时要判断当前填充象素点与边界象素点之间的关系。如果要填充的象素点在多边形的边界之内,则进行填充;如果要填充的象素点在多边形的边界之外,则不填充;如果要填充的象素点正好在多边形的边界上,则保留边界象素点颜色。

        image-20211027195850557

      • 2).八邻法所走的填充路线为:上、下、左、右、左上、左下、右上、右下。在填充时要判断当前填充象素点与边界象素点之间的关系。

        image-20211027195916963

    • 扫描线填色算法

      1.扫描线填色算法(Scan-Line Filling)是一种运算效率比较高的多边形填充算法。这类算法是建立在多边形边界的基础上。
      2.算法的基本思想:
      多边形以n、x_array、y_array的形式给出,其中,x_array、y_array为两个一维数组,x_array、y_array中分别存放着多边形的n个顶点的x、y坐标。
      用水平扫描线从上到下扫描这个由点与线段定义的多边形。每根扫描线与多边形各边产生一系列交点。这些交点按照x坐标值从小到大的顺序进行分类排列。将分类后的交点成对取出,作为两个端点。通过判断,对属于多边形内部的线段,以需要填的颜色画水平直线。而对属于多边形外的线段,不用进行填充。多边形被扫描完毕后,填色也就完成。

      image-20211027200046019

三角面TriangleArray类

  • TriangleArray类的构造函数

    • TriangleArray(int vertexCount,int vertexFormat):用相关参数创建一个空的TriangleArray类的对象。参数vertexCount、vertexFormat 为顶点数和定点格式。

    • TriangleArray类以一维顶点数组给出顶点的坐标值,从前向后依次以三个顶点形成一个三角形,并且上一个三角形与下一个三角形之间没有公用顶点

      image-20211027200710137

运用上文类进行代码实战——DisplayLineStrip

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TriangleArray;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class DisplayTriangles extends Applet{
	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup = new BranchGroup();
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Color3f bgcolor3f = new Color3f(1.f, 1.f, 1.f);
		Background background = new Background(bgcolor3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);

		Color3f dirColor3f = new Color3f(1.f, 0.f, 0.f);
		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);

		TransformGroup group = new TransformGroup();
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(group);

		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(group);
		mouseRotate.setSchedulingBounds(boundingSphere);
		branchGroup.addChild(mouseRotate);
		MouseZoom mouseZoom = new MouseZoom();
		mouseZoom.setTransformGroup(group);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);
		MouseTranslate mouseTranslate = new MouseTranslate();
		mouseTranslate.setTransformGroup(group);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);
		// 图形
		group.addChild(new MyTriangleArray());
		branchGroup.compile();
		return branchGroup;

	}
	public DisplayTriangles() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration=SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d=new Canvas3D(configuration);
		add("Center",canvas3d);
		BranchGroup branchGroup=createBranchGroup();
		SimpleUniverse simpleUniverse=new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MainFrame(new DisplayTriangles(), 300, 300);
	}

}

class MyTriangleArray extends Shape3D {
	public MyTriangleArray() {
		int vCount = 12;
		float vertexes[] = { -0.6f, 0.9f, 0.f, -0.6f, -0.9f, 0.2f, -0.4f, 0.9f, -0.2f, -0.2f, -0.9f, 0.2f, 0.0f, 0.9f,
				-0.2f, 0.0f, -0.9f, 0.2f, 0.2f, 0.7f, 0.0f, 0.2f, -0.9f, 0.3f, 0.5f, 0.8f, -0.3f, 0.6f, -.9f, 0.0f,
				0.8f, 0.9f, 0.2f, 0.8f, -0.8f, 0.3f };
		float colors[] = { 0.0f, 0.5f, 1.f, 0.0f, 0.5f, 1.f, 0.0f, 0.8f, .0f, 1.0f, 0.0f, 0.3f, 0.0f, 1.0f, 0.5f, 0.9f,
				1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 0.8f, 0.0f,
				1.0f, 0.5f, 0.0f };
		
		TriangleArray triangleArray=new TriangleArray(vCount, TriangleArray.COORDINATES|TriangleArray.COLOR_3);
		triangleArray.setCoordinates(0, vertexes);
		triangleArray.setColors(0, colors);
		PolygonAttributes polygonAttributes=new PolygonAttributes();
		polygonAttributes.setCullFace(PolygonAttributes.CULL_BACK);
		Appearance appearance=new Appearance();
		appearance.setPolygonAttributes(polygonAttributes);
		this.setGeometry(triangleArray);
		this.setAppearance(appearance);
		
		
	}
}

结果:

image-20211027215743511

三角带TriangleStripArray类

  • TriangleStripArray(int vertexCount, int vertexFormat, int[] stripVertexCounts)构造函数
    应用所给的参数创建一个空的TriangleStripArray类的对象。vertexCount、vertexFormat参数的含义与前面介绍的一样。stripVertexCounts参数:是一个一维数组,该一维数组的元素个数表示将给定的顶点分为几个子三角形Strip带

  • 例如,如果给定的总的顶点数为10,stripVertexCounts[0]=6,stripVertexCounts[1]=4,表示用所给定的10个顶点生成两个子三角形Strip带,第一个子三角形Strip中含有6个顶点,第二个子三角形Strip中含有4个顶点。这两个子Strip之间没有公用的顶点。

    image-20211027205349735

  • 对于上图,在三角形Strip内,生成三角形时,第一个三角形由前三个顶点生成,第一个三角形的后两个顶点与第四个顶点形成第二个三角形,其余依次类推。
    在每一个三角形Strip内,所有的三角形都是相互连接在一起的,相邻的三角形之间有公共边。用这种方式生成的曲面具有指向相同侧的法向量。

  • 假设有12个定点,三个三角带

    		int vertexesCount = 12;
    		int stripCount[] = new int[3];
    

    这时进行点的分配,不能2 8 2的分,因为2无法构成一个三角形

    • 此时进行4 4 4的分类可以:

    image-20211027220519319

    • 此时 3 6 3的分类可以:

      image-20211027220617993

    • 也可以一个三角带 12的分类

      		int vertexesCount = 12;
      		int stripCount[] = new int[1];
      

      image-20211028151743768

代码展示:

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TriangleArray;
import javax.media.j3d.TriangleStripArray;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class TriangleStripArrays extends Applet {
	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup = new BranchGroup();
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Color3f bgcolor3f = new Color3f(1.f, 1.f, 1.f);
		Background background = new Background(bgcolor3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);

		Color3f dirColor3f = new Color3f(1.f, 0.f, 0.f);
		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);

		TransformGroup group = new TransformGroup();
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(group);

		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(group);
		mouseRotate.setSchedulingBounds(boundingSphere);
		branchGroup.addChild(mouseRotate);
		MouseZoom mouseZoom = new MouseZoom();
		mouseZoom.setTransformGroup(group);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);
		MouseTranslate mouseTranslate = new MouseTranslate();
		mouseTranslate.setTransformGroup(group);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);
		// 图形
		group.addChild(new TriangleStrip());
		branchGroup.compile();
		return branchGroup;

	}

	public TriangleStripArrays() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration = SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d = new Canvas3D(configuration);
		add("Center", canvas3d);
		BranchGroup branchGroup = createBranchGroup();
		SimpleUniverse simpleUniverse = new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MainFrame(new TriangleStripArrays(), 300, 300);
	}

}

class TriangleStrip extends Shape3D {
	public TriangleStrip() {
		int vertexesCount = 12;
//		int stripCount[] = new int[3];
		int stripCount[] = new int[1];
		float vertexes[] = { -0.9f, 0.9f, 0.f, -0.8f, -0.9f, 0.2f, -0.6f, 0.8f, -0.2f, -0.4f, -0.8f, 0.2f, -0.3f, 0.9f,
				-0.2f, -0.2f, -0.9f, 0.2f, 0.4f, 0.7f, 0.0f, 0.4f, -0.7f, 0.3f, 0.6f, 0.9f, -0.3f, 0.6f, -.9f, 0.0f,
				0.9f, 0.8f, 0.2f, 0.8f, -0.8f, 0.3f };
		float colors[] = { 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.8f, .0f, 1.0f, 0.0f, 0.3f, 0.0f, 1.0f, 0.5f,
				0.9f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 0.8f,
				0.0f, 1.0f, 0.5f, 0.0f };
//		stripCount[0] = 3;
//		stripCount[1] = 6;
//		stripCount[2] = 3;
		stripCount[0]=12;

		TriangleStripArray triangleArray = new TriangleStripArray(vertexesCount,
				TriangleStripArray.COORDINATES | TriangleStripArray.COLOR_3,stripCount);
		triangleArray.setCoordinates(0, vertexes);
		triangleArray.setColors(0, colors);
		PolygonAttributes polygonAttributes = new PolygonAttributes();
		polygonAttributes.setCullFace(PolygonAttributes.CULL_NONE);
		Appearance appearance = new Appearance();
		appearance.setPolygonAttributes(polygonAttributes);
		this.setGeometry(triangleArray);
		this.setAppearance(appearance);

	}
}

三角扇TriangleFanArray类

TriangleFanArray(int vertexCount,int vertexFormat,int[] stripVertexCounts)构造函数

  • 用相关参数创建一个空的TriangleFanArray类的对象。vertexCount、vertexFormat、stripVertexCounts 各参数的含义和三角带相同。
  • TriangleFanArray类在组织三角形时,以第一个顶点为公用顶点,依次与其余顶点分别连接形成三角形。用这种方法生成的一系列三角形公用第一个顶点。其中给定的顶点数最少为3个。用这种方法生成的所有三角形面具有指向同侧的法向量

image-20211028152230803

  • 代码展示:

    package java3d;
    
    import java.applet.Applet;
    import java.awt.BorderLayout;
    import java.awt.GraphicsConfiguration;
    
    import javax.media.j3d.Appearance;
    import javax.media.j3d.Background;
    import javax.media.j3d.BoundingSphere;
    import javax.media.j3d.BranchGroup;
    import javax.media.j3d.Canvas3D;
    import javax.media.j3d.DirectionalLight;
    import javax.media.j3d.PolygonAttributes;
    import javax.media.j3d.Shape3D;
    import javax.media.j3d.TransformGroup;
    import javax.vecmath.Color3f;
    import javax.vecmath.Point3d;
    import javax.vecmath.Vector3f;
    import javax.media.j3d.TriangleFanArray;
    
    import com.sun.j3d.utils.applet.MainFrame;
    import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
    import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
    import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
    import com.sun.j3d.utils.universe.SimpleUniverse;
    
    public class MyTriangleFanArray extends Applet {
    	public BranchGroup createBranchGroup() {
    		BranchGroup branchGroup = new BranchGroup();
    		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
    		Color3f bgcolor3f = new Color3f(1.f, 1.f, 1.f);
    		Background background = new Background(bgcolor3f);
    		background.setApplicationBounds(boundingSphere);
    		branchGroup.addChild(background);
    
    		Color3f dirColor3f = new Color3f(1.f, 0.f, 0.f);
    		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
    		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
    		directionalLight.setInfluencingBounds(boundingSphere);
    		branchGroup.addChild(directionalLight);
    
    		TransformGroup group = new TransformGroup();
    		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    		branchGroup.addChild(group);
    
    		MouseRotate mouseRotate = new MouseRotate();
    		mouseRotate.setTransformGroup(group);
    		mouseRotate.setSchedulingBounds(boundingSphere);
    		branchGroup.addChild(mouseRotate);
    		MouseZoom mouseZoom = new MouseZoom();
    		mouseZoom.setTransformGroup(group);
    		branchGroup.addChild(mouseZoom);
    		mouseZoom.setSchedulingBounds(boundingSphere);
    		MouseTranslate mouseTranslate = new MouseTranslate();
    		mouseTranslate.setTransformGroup(group);
    		branchGroup.addChild(mouseTranslate);
    		mouseTranslate.setSchedulingBounds(boundingSphere);
    		// 图形
    		group.addChild(new MyTriangleFanArray1());
    		branchGroup.compile();
    		return branchGroup;
    
    	}
    
    	public MyTriangleFanArray() {
    		setLayout(new BorderLayout());
    		GraphicsConfiguration configuration = SimpleUniverse.getPreferredConfiguration();
    		Canvas3D canvas3d = new Canvas3D(configuration);
    		add("Center", canvas3d);
    		BranchGroup branchGroup = createBranchGroup();
    		SimpleUniverse simpleUniverse = new SimpleUniverse(canvas3d);
    		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
    		simpleUniverse.addBranchGraph(branchGroup);
    	}
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		new MainFrame(new MyTriangleFanArray(), 300, 300);
    	}
    
    }
    
    class MyTriangleFanArray1 extends Shape3D {
    	public MyTriangleFanArray1() {
    		int vertexesCount = 12;
    		int stripCount[] = new int[1];
    		// int stripCount[]=new int[2];
    		// int stripCount[]=new int[3];
    
    		float vertexes[] = { .0f, 0.9f, 0.0f, -1.f, -0.8f, 0.f, -0.8f, -0.6f, -0.2f, -0.6f, -0.9f, 0.2f, -0.4f, -0.8f,
    				-0.2f, 0.f, -0.8f, 0.2f, 0.2f, -0.5f, 0.0f, 0.4f, -0.6f, -0.5f, 0.6f, -0.8f, -0.3f, 0.8f, -0.9f, -0.2f,
    				0.9f, -0.7f, -0.2f, 1.1f, -0.8f, -0.3f };
    		float colors[] = { 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.8f, .0f, 1.0f, 0.0f, 0.3f, 0.0f, 1.0f, 0.5f,
    				0.9f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 0.8f,
    				0.0f, 1.0f, 0.5f, 0.0f };
    
    //		stripCount[0] = 3;
    //		stripCount[1] = 6;
    //		stripCount[2] = 3;
    		stripCount[0] = 12;
    		// stripCount[1]=4;
    		// stripCount[2]=4;
    		TriangleFanArray triangleFanarray = new TriangleFanArray(vertexesCount,
    				TriangleFanArray.COORDINATES | TriangleFanArray.COLOR_3, stripCount);
    		triangleFanarray.setCoordinates(0,vertexes);
    		triangleFanarray.setColors(0,colors);
    
    		PolygonAttributes polygonAttributes = new PolygonAttributes();
    //		polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
    		polygonAttributes.setCullFace(PolygonAttributes.CULL_NONE);
    		Appearance appearance = new Appearance();
    		appearance.setPolygonAttributes(polygonAttributes);
    		this.setGeometry(triangleFanarray);
    		this.setAppearance(appearance);
    
    	}
    }
    
    

    image-20211028153946271

  • ColoringAttributes类改变上三角扇的颜色,其余代码与上相同

    		TriangleFanArray triangleFanarray = new TriangleFanArray(vertexesCount,TriangleFanArray.COORDINATES | TriangleFanArray.NORMALS, stripCount);//此处改为NORMALS
    		triangleFanarray.setCoordinates(0,vertexes);
    //		triangleFanarray.setColors(0,colors);此句去除
    
    		PolygonAttributes polygonAttributes = new PolygonAttributes();
    		polygonAttributes.setCullFace(PolygonAttributes.CULL_NONE);
    		Appearance appearance = new Appearance();
    		//!!!!!!!添加下三行
    		ColoringAttributes coloringAttributes =new ColoringAttributes();
    		coloringAttributes.setColor(1.f, 0.f, 0.f);
    		appearance.setColoringAttributes(coloringAttributes);
    

    image-20211028155039411

  • 如果在程序中不定义顶点颜色,也不用ColoringAttributes类的对象来定义颜色,
    还可用Appearance类中的Material材质的发射光颜色(如红色)生成多边形面的颜色,则在法向量为0的情况下依然能显示三角形面,但是多边形面的连接的细节不清楚。部分程序如下,其它部分与上相同。这种方式定义的光由于是材质的自发光,因此无需光照也能显示

    		Color3f red = new Color3f(1.0f, .0f, .0f);
    		Material material=new Material(); 
    		material.setEmissiveColor(red);
    		appearance.setMaterial(material);
    		appearance.setPolygonAttributes(polygonAttributes);
    		this.setGeometry(triangleFanarray);
    		this.setAppearance(appearance);
    
  • 顶点颜色决定最后显示颜色程序,ColoringAttributes类的对象定义的颜色与Appearance类中Material类中的颜色都存在的情况下,除非有特别说明,否则以顶点的颜色生成面的颜色。

IndexedTriangleArray类

IndexedTriangleArray(int vertexCount,int vertexFormat,int indexCount)构造函数:

  • vertexCount、vertexFormat参数的含义与前面介绍的相同。indexCount参数是指从总的顶点数中选择出的顶点总数允许顶点重复使用,允许indexCount超过vertexCount的值

  • 用该类时,首先需要根据给定顶点的一维数组的序号,建立要用到的顶点的索引数组index(自己创建一个index数组),该数组是一个一维数组,每个元素保存选择出的一个顶点的序号。然后再用继承自IndexedGeometryArray方法setColorIndices(0,index),setCoordinateIndices(0,index)方法分别设置颜色数组、坐标数组与索引数组之间的对应关系。

  • 代码:

    package java3d;
    
    import java.applet.Applet;
    import java.awt.BorderLayout;
    import java.awt.GraphicsConfiguration;
    
    import javax.media.j3d.Appearance;
    import javax.media.j3d.Background;
    import javax.media.j3d.BoundingSphere;
    import javax.media.j3d.BranchGroup;
    import javax.media.j3d.Canvas3D;
    import javax.media.j3d.ColoringAttributes;
    import javax.media.j3d.DirectionalLight;
    import javax.media.j3d.IndexedTriangleArray;
    import javax.media.j3d.Material;
    import javax.media.j3d.PolygonAttributes;
    import javax.media.j3d.Shape3D;
    import javax.media.j3d.TransformGroup;
    import javax.vecmath.Color3f;
    import javax.vecmath.Point3d;
    import javax.vecmath.Vector3f;
    import javax.media.j3d.TriangleFanArray;
    
    import com.sun.j3d.utils.applet.MainFrame;
    import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
    import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
    import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
    import com.sun.j3d.utils.universe.SimpleUniverse;
    
    public class IndexedTriangleArrayTest extends Applet {
    	public BranchGroup createBranchGroup() {
    		BranchGroup branchGroup = new BranchGroup();
    		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
    		Color3f bgcolor3f = new Color3f(1.f, 1.f, 1.f);
    		Background background = new Background(bgcolor3f);
    		background.setApplicationBounds(boundingSphere);
    		branchGroup.addChild(background);
    
    		Color3f dirColor3f = new Color3f(1.f, 0.f, 0.f);
    		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
    		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
    		directionalLight.setInfluencingBounds(boundingSphere);
    		branchGroup.addChild(directionalLight);
    
    		TransformGroup group = new TransformGroup();
    		group.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    		group.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    		branchGroup.addChild(group);
    
    		MouseRotate mouseRotate = new MouseRotate();
    		mouseRotate.setTransformGroup(group);
    		mouseRotate.setSchedulingBounds(boundingSphere);
    		branchGroup.addChild(mouseRotate);
    		MouseZoom mouseZoom = new MouseZoom();
    		mouseZoom.setTransformGroup(group);
    		branchGroup.addChild(mouseZoom);
    		mouseZoom.setSchedulingBounds(boundingSphere);
    		MouseTranslate mouseTranslate = new MouseTranslate();
    		mouseTranslate.setTransformGroup(group);
    		branchGroup.addChild(mouseTranslate);
    		mouseTranslate.setSchedulingBounds(boundingSphere);
    		// 图形
    		group.addChild(new MyTriangleFanArray2());
    		branchGroup.compile();
    		return branchGroup;
    
    	}
    
    	public IndexedTriangleArrayTest() {
    		setLayout(new BorderLayout());
    		GraphicsConfiguration configuration = SimpleUniverse.getPreferredConfiguration();
    		Canvas3D canvas3d = new Canvas3D(configuration);
    		add("Center", canvas3d);
    		BranchGroup branchGroup = createBranchGroup();
    		SimpleUniverse simpleUniverse = new SimpleUniverse(canvas3d);
    		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
    		simpleUniverse.addBranchGraph(branchGroup);
    	}
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		new MainFrame(new IndexedTriangleArrayTest(), 300, 300);
    	}
    
    }
    
    class MyTriangleFanArray2 extends Shape3D {
    	public MyTriangleFanArray2() {
    		int vertexesCount = 12;
    		int indexcount=6;
    
    		// int stripCount[]=new int[2];
    		// int stripCount[]=new int[3];
    
    		float vertexes[] = { -.9f, 0.8f, 0.0f, -0.8f, -0.8f, 0.2f, -0.6f, -0.4f, -0.2f, -0.4f, -0.9f, 0.2f, -0.2f, 0.8f,
    				-0.2f, 0.f, -0.8f, 0.2f, 0.2f, -0.5f, 0.0f, 0.4f, 0.6f, -0.5f, 0.6f, -0.8f, -0.3f, 0.8f, -0.9f, -0.2f,
    				0.9f, 0.7f, -0.2f, 1.1f, -0.8f, -0.3f };
    		float colors[] = { 0.0f, 0.5f, 1.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.8f, .0f, 1.0f, 0.0f, 0.3f, 0.0f, 1.0f, 0.5f,
    				0.9f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f, 0.8f,
    				0.0f, 1.0f, 0.5f, 0.0f };
    
    		int[] index = { 0, 1, 3, 5, 7, 9 };
    		IndexedTriangleArray indextrianglearray=new IndexedTriangleArray(vertexesCount,
    				IndexedTriangleArray.COORDINATES|IndexedTriangleArray.COLOR_3,indexcount);
    
    		indextrianglearray.setCoordinates(0, vertexes);
    		indextrianglearray.setColors(0,colors);
    		indextrianglearray.setCoordinateIndices(0,index);
    		indextrianglearray.setColorIndices(0, index);
    
    		PolygonAttributes polygonAttributes = new PolygonAttributes();
    //		polygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
    		polygonAttributes.setCullFace(PolygonAttributes.CULL_NONE);
    		Appearance appearance = new Appearance();
    
    		appearance.setPolygonAttributes(polygonAttributes);
    		this.setGeometry(indextrianglearray);
    		this.setAppearance(appearance);
    
    	}
    }
    
    

    image-20211028161939925

四边面QuadArray类和IndexedQuadArray类

  • QuadArray(int vertexCount,int vertexFormat)构造函数
    vertexCount与 vertexFormat参数的含义与前面介绍的一样。所给顶点数最少应为4个
    QuadArray类以顶点坐标数组中给出的一维顶点数组,从前向后依次以四个顶点形成一个四边形面,并且相邻两个四边形面之间没有公用顶点。给定的总的顶点数必须是4的倍数

  • IndexedQuadArray(int vertexCount,int vertexFormat,int indexCount)构造函数:

颜色属性ColoringAttributes类

ColoringAttributes类定义所选择的颜色与光照模型(也称为阴影模型)。

  • 设置颜色:用setColor方法设置ColoringAttributes类的对象中的R、G、B颜色分量值。这种颜色只能用于不可分割的几何体。如果光照明(Lighting)被激活,则材质对象中所设置的颜色(Material Colors)在光照明模型中生成几何体的最终颜色。当在不可分割的几何体中定义了顶点颜色时,则顶点颜色取代ColoringAttributes类中设置的颜色,除非顶点的颜色被忽略。

  • 光照模型Shading Model):
    用setShadeModel()方法设置ColoringAttributes对象中的真实感光照模型
    阴影模型有下列几种:
    FASTEST:应用可获得的最快的方式产生光照模型,可能会依赖于硬件。
    NICEST:应用可获得的方法产生最好(高质量)的真实感图形的方式,可能会依赖于硬件
    SHADE_FLAT:应用平面光照模型,该模型在原始几何体之间不进行颜色插值。
    SHADE_GOURAUD:应用Gouraud光滑光照明模型,这种光照模型在原始体的各顶点之间光滑地插值颜色,这种原始几何体以很多不同的颜色画出来,并且每个顶点的颜色单独处理。这种模型是真实感比较强的、光滑的光照模型。这种光照明模型是默认的光照模型。

  • ColoringAttributes类的构造函数如下:
    1.ColoringAttributes(),用缺省参数创建一个ColoringAttributes对象。
    缺省时:
    color = white (1,1,1);
    shade model = SHADE_GOURAUD。
    2.ColoringAttributes(Color3f color,int shadeModel),用 color所表示的颜色与shadeModel变量创建一个ColoringAttributes对象
    3.ColoringAttributes(float red, float green, float blue, int shadeModel),用R、G、B颜色分量与shadeModel变量创建ColoringAttributes对象。

  • ColoringAttributes类的方法如下:
    setColor(Color3f color)方法:设置颜色
    setColor(float r,float g,float b)方法:设置颜色
    setShadeModel(int shadeModel)方法:设置光照明模式

  • ColoringAttributes类中颜色的设置方法

    • 直接用ColoringAttributes类构造函数在创建其对象时设置其颜色。

      (1)ColoringAttributes coloringAttributes=new ColoringAttributes (Color3f color);
      (2)ColoringAttributes coloringAttributes=New ColoringAttributes(float red,float green,float blue);

    • 用ColoringAttributes类的setColor方法设置颜色:
      ColoringAttributes coloringAttributes=new ColoringAttributes();
      (1)coloringAttributes.setColor(Color3f color);
      (2)coloringAttributes.setColor(float r,float g,float b)。

材质Material类

​ Material类的对象定义一个三维物体在光照情况下的外观。如果在一个Appearance类的对象中的Material类的对象一项为null,则光照效果对所有包含该Appearance类的对象的节点不起作用

  • 在Material类的对象中可设置的属性如下:

    • 环境光颜色Ambient color:是在材质表面反射的环境光,包含红、绿、蓝三色,颜色取值范围0.0到1.0,缺省颜色值为(0.2,0.2,0.2)。
    • 散射光颜色Diffuse color:也称为漫射光,当光照射时,物体材质表现出的红、绿、蓝颜色,颜色取值范围0.0到1.0,缺省颜色值为(1.0, 1.0, 1.0)。
    • 镜面反射光颜色Specular color:材质的镜面反射光也称为高光(highlights)。在光照下,物体的镜面反射的红、绿、蓝颜色,颜色取值范围0.0到1.0,缺省颜色值为(1.0, 1.0, 1.0)。
    • 物体放射的光颜色Emissive color:表示物体放射出的红、绿、蓝颜色光,颜色取值范围0.0到1.0,缺省颜色值为(0.0, 0.0, 0.0)。
    • 物体的发亮特性Shininess:表示物体材质的光亮程度,取值范围[1.0,128.0],1.0表示不发亮,128.0表示很亮,最高亮度。超出该范围的值无意义。缺省发亮值为64。
  • 颜色靶子Color target:对应于每个顶点颜色的Material类的对象中材质颜色靶子是下列值之一:AMBIENT,EMISSIVE,DIFFUSE,SPECULAR,AMBIENT_AND_DIFFUSE(都是上面的可设置属性)。缺省值的颜色靶子为DIFFUSE。也就是说,如果将顶点颜色的靶子设为Material类的对象中的AMBIENT,则当顶点的颜色存在,在光照明方程中,用顶点颜色代替AmbientColor进行计算。

  • Material类的构造函数如下。

    • Material():用缺省参数创建一个 Material类的对象。各项缺省参数如下:
      lighting enable:true
      ambient color:(0.2, 0.2, 0.2)
      emmisive color:(0.0, 0.0, 0.0)
      diffuse color:(1.0, 1.0, 1.0)
      specular color:(1.0, 1.0, 1.0)
      shininess:64
      color target:DIFFUSE
    • Material(Color3f ambientColor,Color3f emissiveColor,Color3f diffuseColor, Color3f specularColor, float shininess)
      用指定参数创建一个 Material类的对象。
  • Material类的相关方法如下。

    • setAmbientColor(Color3f color),用指定的color参数设置环境光颜色。color表示材质的环境光颜色。在有些情况下,环境光颜色会被每个顶点的颜色覆盖。如果在一个几何元素中,顶点的颜色存在,使用光照, colorTarget的取值为 AMBIENT或AMBIENT_AND_DIFFUSE,并且顶点的颜色没有被忽略,则在光照明模型计算中,用顶点颜色代替Material中的AmbientColor进行计算
    • setAmbientColor(float r,float g,float b)方法,用r、g、b为红、绿、蓝颜色分量设置环境光颜色。
    • setEmissiveColor(Color3f color)方法设置放射光
    • setEmissiveColor(float r,float g,float b)方法设置放射光。
      在有些情况下,发射光颜色会被每个顶点的颜色覆盖。如果在一个几何元素中,顶点的颜色存在,使用光照,colorTarget的取值为EMISSIVE,并且顶点的颜色没有被忽略,则在光照明模型计算中,用顶点颜色代替材质Material中的EMISSIVE进行计算。
    • setDiffuseColor(Color3f color)、setDiffuseColor(float r,float g, float b)方法用来设置散射光颜色,用法及参数含义同上
    • setDiffuseColor(float r,float g,float b,float a)方法用来设置散射光颜色,其中,a表示一个alpha元素,用来设置透明度值。在有些情况下,散射光颜色会被每个顶点的颜色覆盖。如果在一个几何元素中,顶点的颜色存在,使用光照,colorTarget的取值为DIFFUSE或者AMBIENT_AND_DIFFUSE,并且顶点的颜色没有被忽略,则在光照明模型计算中,用顶点颜色代替材质Material中的散射光颜色进行计算。
    • setSpecularColor(Color3f color)方法用来设置镜面反射光颜色。
      setSpecularColor(float r,float g,float b)方法用来设置镜面反射光颜色,用法及参数含义同上。在有些情况下,反射光颜色会被每个顶点的颜色覆盖。如果在一个几何元素中,顶点的颜色存在,使用光照,colorTarget的取值为SPECULAR,并且顶点的颜色没有被忽略,则在光照明模型计算中,用顶点颜色代替材质Material中的反射光颜色进行计算。
    • setShininess(float shininess),设置发亮值
    • setLightingEnable(boolean state),在appearance元素的对象中,打开或关闭光照明。参数值true 表示打开(使用)光照,false表示关闭(不使用)光照。
    • setColorTarget(int colorTarget)方法,设置针对全部顶点颜色的颜色靶子。对于一个给定的Shape3D节点,如果有光照,并且顶点的颜色存在,则所有顶点颜色将替代Material对象中的颜色colorTarget起作用。当关闭光照,或者当所有的顶点颜色不存在时,则颜色靶子colorTarget被忽略。缺省时的颜色靶子是DIFFUSE。colorTarget的取值是下列值之一:AMBIENT,EMISSIVE,DIFFUSE,SPECULAR,AMBIENT_AND_DIFFUSE。
  • Material类的对象的属性设置如下。

    • 用Material类的构造函数直接设置:
      Material material=new Material(Color3f ambientColor,Color3f emissiveColor,Color3f diffuseColor,Color3f specularColor,float shininess);

    • Material material=new Material();
      向Material类的对象material中加入各种外观属性所用的方法:

      1)material.setAmbientColor(Color3f color);
      (2)material.setAmbientColor(float r,float g,float b);
      (3)material.setEmissiveColor(Color3f color);
      (4)material.setEmissiveColor(float r,float g,float b);
      (5)material.setDiffuseColor(Color3f color);
      (6)material.setDiffuseColor(float r, float g, float b);
      (7)material.setSpecularColor(Color3f color);
      (8)material.setSpecularColor(float r, float g, float b);
      (9)material.setShininess(float shininess)

透明属性TransparencyAttributes类

TransparencyAttributes类的对象定义所有几何体透明度的属性。

  • 物体透明度的属性如下。

    • 透明模式(Transparency mode)
      定义透明度如何应用到这个Appearance的几何组件对象中。
      1.FASTEST:应用最快可获得的方法实现透明
      2.NICEST:应用最好的可获得的方法实现透明
      3.SCREEN_DOOR:应用screen-door透明模式,通过象素的透明来近似地实现透明参数。
      4.BLENDED:应用alpha混合透明模式。混合方程由srcBlendFunction和 dstBlendFunction属性确定。缺省时的方程为:alphasrcsrc+ (1-alphasrc)dst,其中alphasrc=1-transparency。如果几何体的顶点颜色包括alpha值,则该alpha值将与在TransparencyAttributes定义的透明度值进行混合计算。在这种情况下,对每个象素应用于混合计算的alpha值如下,alphasrc=alphapix*(1-transparency)。

      5.NONE:没有透明,完全不透明(opaque)

    • 透明度值(Transparency value)
      取值在0.0到1.0之间,0.0表示不透明,1.0表示完全透明
      相关构造函数如下:
      (1)TransparencyAttributes()
      用缺省参数创建一个TransparencyAttributes类的对象。缺省参数值如下:透明模式为NONE,透明度值为0.0,则完全不透明。
      (2)TransparencyAttributes(int tMode,float tVal)
      用指定参数创建一个TransparencyAttributes类的对象。tMode表示透明模式,tVal表示透明度值

    • 相关方法如下
      setTransparencyMode(int transparencyMode)方法:设置透明模式
      setTransparency(float transparency)方法:设置外观对象appearance中的透明度值

    • TransparencyAttributes类的对象参数设置:
      *1.*直接用TransparencyAttributes类构造函数在创建其对象时设置其参数
      TransparencyAttributes transparency=new TransparencyAttributes(int tMode,float tVal);
      *2.*用TransparencyAttributes类的setTransparency(float transparency)方法设置
      TransparencyAttributes transparency=new TransparencyAttributes ();
      transparency.setTransparency(float transparency);

光源Light类

​ Light类叶子结点是一个抽象类,其中定义的一组参数属于所有类型的光。这些参数包括光颜色,光照开关标志,和一个光的作用范围。
​ 光源的的类型包括:平行光源(directional light),点光源(point light),环境光(ambient light)。Java 3D支持任意数量的光源,但在作用范围内激活的光源数量是依赖于执行的,不能在这里定义。

  • 光颜色Light Color
    Java 3D的光照模型近似地模拟自然界中光照的情况。光颜色包含红、绿、蓝三个分量。每个分量取值范围为0.0到1.0。如果在一个场景中定义了多个光源,这些光源都照射相关对象,则总的光效果是这单个光效果的叠加。对大于1的光强度则截取为1.0,表示最亮的光。

  • 几何体材质颜色Material Colors

    • 在Java 3D的光照模型中,当几何体的表面吸收或反射光的时候,光源对场景中的物体才起作用。Java 3D通过计算物体所反射的红、绿、蓝光的比率来近似地表示物体颜色。一个纯绿色的物体吸收所有照射在其上的红光和蓝光,只反射绿色的光。一个绿色物体白光照射下,绿色光被反射,红、蓝光被吸收,物体看起来就是绿色。当一个绿色物体用红光照射,则该红光被吸收,该物体显示成黑色
    • 每个几何体的表面都具有某种材质属性,来定义光源如何影响其外观。根据几何体表面不同类型,几何体可能会以不同的方式反射光。几何体也可以自己发光。Java 3D的光照明模型定义了5种独立的组件作为对象表面的材质属性:自发光颜色emitted color,环境光颜色ambient color, 散射光颜色diffuse color,反射光颜色specular color,和发亮属性shininess。所有这些材质属性独立计算,然后叠加在一起定义对象最终在光源环境下的外观。其中的一个例外就是,环境光对镜面反射没有贡献。对象的所有材质属性在Material类中定义。
  • 光的作用范围(Influencing Bounds

    • 在Java 3D中,光的作用范围由一个Bounds类的对象或者一个BoundingLeaf类的对象定义。应当注意,如果两个对象都设置了,则BoundingLeaf类的对象覆盖Bounds类的对象,一个Bounds类的对象是一个封闭的凸体。Bounds类的对象定义了三种不同类型的包围体:与坐标轴平行的长方体,一个球体,和一个凸多面体
    • 一个BoundingLeaf类的对象也定义了一个作用范围,但是允许一个应用程序在一个坐标系中定义一个包围范围(在该BoundingLeaf类的对象的局部坐标系中定义)。
    • 限定光的作用范围。为了控制计算量,光照也可限制在一组由Group类的对象定义的节点。附加到一个Group节点中的所有节点通过一个范围列表(list of scopes)定义。Light类的方法允许设置、增加、插入、删除和枚举在范围列表(list of scopes)中定义的节点。
  • Light类的构造函数

    • Light()构造函数
      用缺省参数创建一个Light结点。缺省参数值如下:
      enable flag: true
      color: white (1,1,1)
      scope: empty (universe scope)
      influencing bounds: null
      influencing bounding leaf: null
    • Light(Color3f color)构造函数
      用指定的颜色创建一个光结点。Color表示光源的颜色
    • Light(boolean lightOn,Color3f color)构造函数
      用指定的光开关标志与颜色创建一个光结点。lightOn值为true时,表示光开,false表示光关。
  • Light类的对象的颜色参数设置如下。

    • 直接用Light类的构造函数在创建其对象时设置该类的颜色:
      (1)Light light=new Light (Color3f color)
      (2)Light light=new Light(boolean lightOn,Color3f color);
    • 用Light类的setColor方法设置:
      (1)Light light=new Light();
      (2)light.setColor(Color3f color);
  • Light类的方法:
    setEnable(boolean state):通过state变量控制光开、光关,state值为true 时表示光开,为false时表示光关。
    setInfluencingBounds(Bounds region):设置光作用范围为region。只有当BoundingLeaf类的对象为null时该设置才起作用。
    setColor(Color3f color)方法:设置光的当前颜色。

下面介绍几种最常用的光源:点光源、平行光源与环境光

点光源PointLight类

  • 定义与衰减系数

    • 点光源PointLight类在三维空间的一个固定点上定义一种衰减的光源,该种光源从光发出点出发,在所有方向的辐射是相等的。PointLight类具有与Light类节点相同的属性,也就是具有一个固定位置和衰减系数。
    • 点光源对三维型体表面上散射光与发射光有贡献,这两种光分别依赖于曲面上点的位置与该点法向量指向。点光源对环境光反射部分没有贡献。
    • 一个点光源通过其衰减系数(Attenuation factor)反映其衰减,该衰减随着距光源中心距离的增加而增加,也就是距离越远,光的亮度衰减得越大。点光源的衰减系数包含下列三个值:固定衰减(Constant attenuation);线型衰减(Linear attenuation);二次方衰减(Quadratic attenuation)。
  • 下面介绍PointLight类的构造函数与方法。

    • 构造函数

      1.PointLight()构造函数:用缺省参数创建一个PointLight节点。缺省参数为:位置 (0,0,0),衰减系数(1,0,0)。

      2.PointLight(Color3f color,Point3f position,Point3f attenuation)构造函数:用给定的光颜色、光源位置、衰减系数创建一个点光源。衰减系数的参数顺序为(固定衰减系数,线性衰减系数,二次方衰减系数)

      3.PointLight(boolean lightOn,Color3f color,Point3f position, Point3f attenuation)构造函数:用给定的光颜色、光源位置、衰减系数创建一个点光源,并且用lightOn参数设定了光源是开还是关。

    • 方法

      setPosition(Point3f position)方法:设置点光源位置。
      setPosition(float x,float y,float z)方法:用x、y、z坐标值设置点光源位置。
      setAttenuation(Point3f attenuation)方法:设置点光源的三个衰减系数。
      setAttenuation(floa constant,float linear,float quadratic)方法:设置点光源的三个衰减系数。

平行光源DirectionalLight类

  • 平行光定义一种光源在无限远处的有方向的光。该类和一个光节点一样具有相同的参数,只是多了一个表示光方向的Vector3f向量参数。平行光对三维形体表面的散射光与发射光有贡献,这种情况下,三维形体表面的散射光与发射光与三维物体的指向有关,与曲面上点的位置没有关系。平行光对三维形体表面的环境光反射没有贡献。

  • DirectionalLight构造函数与方法:

    • 1.DirectionalLight()构造函数:用缺省参数创建一个DirectionalLight平行光源节点,缺省的照射方向为(0,0,-1),也就是沿着z轴的反方向。
      2.DirectionalLight(Color3f color,Vector3f direction)构造函数:用给定的颜色与照射方向创建一个DirectionalLight平行光源节点。
      3.DirectionalLight(boolean lightOn,Color3f color,Vector3f direction)构造函数:用给定的颜色与照射方向创建一个DirectionalLight平行光源节点,并且用lightOn参数设定了光源是开还是关。

    • 1.setDirection(Vector3f direction)方法:设置光照方向。
      2.setDirection(float x,float y,float z)方法:用x、y、z三个浮点值组成的向量设置光照方向。

  • 环境光源AmbientLight类

    • 环境光源是指来自于所有方向的一种光源。环境光源AmbientLight类的对象具有与Light类节点相同的属性,其包括光颜色、光的作用范围和一个表示光源开或光源关参数。环境光源在三维型体表面产生的反射与三维型体表面的位置及指向无关。环境光源只有一个环境反射组件,不包含散射与镜面反射组件。

    • AmbientLight构造函数

      AmbientLight()构造函数:用缺省参数创建一个环境光源。
      AmbientLight(Color3f color)构造函数:用给定颜色参数创建一个环境光。
      AmbientLight(boolean lightOn, Color3f color)构造函数:用给定的颜色参数及lightOn光开关参数创建一个环境光源,。

运用上文类进行代码实战——TransparencyAttributesTest

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Material;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class TransparencyAttributesTest extends Applet{
	
	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup=new BranchGroup();
		BoundingSphere boundingSphere=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);
		Color3f bgColor3f=new Color3f(1.f,1.f,1.f);
		Background background=new Background(bgColor3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);
		
		Color3f dirColor3f=new Color3f(1.f,1.f,1.f);
		Vector3f vector3f=new Vector3f(-1.f,-1.f,-1.0f);
		DirectionalLight directionalLight=new DirectionalLight(dirColor3f, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);
		
		Appearance app1=new Appearance();
		Material material1=new Material();
		//设置散射光颜色
		material1.setDiffuseColor(new Color3f(1.0f,.0f,0.0f));
		app1.setMaterial(material1);
		//定义球体的透明度,透明模式选NICEST=1,透明度0.6f
		TransparencyAttributes transparencyAttributes1=new TransparencyAttributes(1,.6f);
		app1.setTransparencyAttributes(transparencyAttributes1);
		
		Appearance app2=new Appearance();
		Material material2=new Material();
		material2.setDiffuseColor(new Color3f(.0f,1.0f,0.0f));
		app2.setMaterial(material2);
		TransparencyAttributes transparencyAttributes2=new TransparencyAttributes(1,.8f);
		app2.setTransparencyAttributes(transparencyAttributes2);
		
		Appearance app3=new Appearance();
		Material material3=new Material();
		material3.setDiffuseColor(new Color3f(.0f,.0f,1.0f));
		app3.setMaterial(material3);
		app3.setTransparencyAttributes(transparencyAttributes2);
		
		Appearance app4=new Appearance();
		Material material4=new Material();
		material4.setDiffuseColor(new Color3f(.0f,1.0f,1.0f));
		app4.setMaterial(material4);
		app4.setTransparencyAttributes(transparencyAttributes2);
		
		TransformGroup transformGroup=new TransformGroup();
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(transformGroup);
		
		MouseRotate mouseRotate=new MouseRotate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);
		MouseZoom mouseZoom=new MouseZoom();
		mouseZoom.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);
		MouseTranslate mouseTranslate=new MouseTranslate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);
		
		TransformGroup group1=new TransformGroup();
		group1.addChild(new Sphere(.9f,1,100,app1));
		
		Transform3D transform3d1=new Transform3D();
		transform3d1.setTranslation(new Vector3f(-0.2f,0.1f,0.2f));
		TransformGroup group2=new TransformGroup(transform3d1);
		group2.addChild(new Box(0.2f,0.2f,0.2f,app2));
		
		Transform3D transform3d2=new Transform3D();
		transform3d2.setTranslation(new Vector3f(-0.2f,0.1f,0.2f));
		TransformGroup group3=new TransformGroup(transform3d2);
		group3.addChild(new Sphere(.6f,1,100,app3)); 
		
		Transform3D transform3d3=new Transform3D();
		transform3d3.setTranslation(new Vector3f(0.4f,0.2f,-0.4f));
		TransformGroup group4=new TransformGroup(transform3d3);
		group4.addChild(new Sphere(.3f,1,100,app4));
		
		transformGroup.addChild(group1);
		transformGroup.addChild(group2);
		transformGroup.addChild(group3);
		transformGroup.addChild(group4);
		
		branchGroup.compile();
		return branchGroup;
		
	}
	
	public TransparencyAttributesTest() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration=SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d=new Canvas3D(configuration);
		add("Center",canvas3d);
		BranchGroup branchGroup=createBranchGroup();
		SimpleUniverse simpleUniverse=new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
		
	}
	
	public static void main(String[] args) {
		new MainFrame(new TransparencyAttributesTest(), 300, 300);
	}

}

image-20211029205637179

线型数据点与一(二)维数组表示

  • 线型数据点包括直线型数据点与曲线型数据点,每个数据点具有x、y、z坐标,线型数据点示意图如下。

    image-20211031095032618

  • 一维数组表示线性数据点:

    • float[] array=new float[7];或者可分为两步定义:float[] array;array=new float[7];
      每一个数组元素只能存一个浮点数,数组元素的序号就是数据的序号。
    • 如果空间直线上有7个数据点,每一个数据点都有x、y、z三个坐标值,要表示这7个数据点的x、y、z坐标值,如果用一维数组就需要定义三个一维数组,分别存放每个数据点的x、y、z坐标值。
      float[] X=new float[7];
      float[] Y=new float[7];
      float[] Z=new float[7];
  • 二维数组表示线性数据点:

    • 用X[0]、Y[0]、Z[0]表示第一个点的x、y、z坐标值,

      用X[1]、Y[1]、Z[1]表示第二个点的x、y、z坐标值,

      依次类推,用X[6]、Y[6]、Z[6]表示第七个点的x、y、z坐标值。

      用三个一维数组表示线型数据点坐标值比较复杂,可考虑用二维数组来表示这种线型数据点坐标值。

    • 如果用二维数组,则只需先定义一个二维数组
      float[][] Pointsxyz=new float[7] [3];
      用二维数组第一维的序号表示点的序号,用第二维的三个元素值分别表示一个数据点的x、y、z坐标值。

    • 例如:

      Pointsxyz[0] [0]、Pointsxyz[0] [1]、Pointsxyz[0] [2]分别表示第一个数据点的x、y、z坐标值Pointsxyz[1] [0]、Pointsxyz[1] [1]、Pointsxyz[1] [2]分别表示第二个数据点的x、y、z坐标值依次类推,Pointsxyz[6] [0]、Pointsxyz[6] [1]、Pointsxyz[6] [2]分别表示第七个数据点的x、y、z坐标值。

平面型数据点与三维数组表示

  • 平面型与曲面型网状数据点示意图如下图。图中圆括号内的两个数据分别表示平面格点数据的行、列编号,每个点有其x、y、z坐标值。对于平面型与曲面型网状数据点,用三维数组表示最为方便。

    image-20211031095836544

  • 三维数组的定义方式为:
    float[][][] surfacepointsxyz=new float[4] [4] [3];
    对于如上图所示的平面型点格数据,总共有4*4=16个数据点,每个点有x、y、z坐标值。要表示这种数据采用三维数组最合适。用三维数组surfacepointsxyz[4] [4] [3]的前两维表示平面格点的行列序号,第三维的三个元素值分别表示一个格点的x、y、z坐标值。

    例如,要表示A点的x、y、z坐标,用三维数组元素表示为:
    surfacepointsxyz[2] [2] [0]、surfacepointsxyz[2] [2] [1]、surfacepointsxyz[2] [2] [2]。

四边形与三角形网格曲面

四边形网格表示

  • 在曲面设计中,一个曲面最常用的网格表示形式为三角网格与四边网格。三角形是多边形中边数最少的一种多边形,因此,三角形网格可以表示比较复杂的曲面形状。所以,三角网格在逆向工程三维型体重建、快速原型系统中得到了很重要应用。

  • 一个四边形可分解为两个三角形,因此,四边形不是边数最少的多边形。用四边网格表示比较规则的曲面形状比较合适。

  • 也可用各种边数高于四边形的多边形的组合来表示一个曲面,这种多边形最终都能分解为一系列三角形的表示方式。

  • 对一个体的表示也可采用三角网格、四边网格、边数高于四边形的多边形网格,不同的多边形也可混合使用。其中,最常用的依然是三角网格与四边网格

  • 下面介绍对给定的空间数据点,如何实现这些数据点的三角网格与四边网格表示。

    • 四边网格型数据示意图如下图

      image-20211031100645883

    • 在上图网格中,总共给出了16个数据点,16个数据点可连成9个四边形。可用QuadArray类进行定义。

      QuadArray SurfaceQuadArray=New QuadArray(9*4,GeometryArray.COORDINATES|GeometryArray.NORMALS);
      

      9*4:在该四边数组中,将这种网格曲面可看作由9个四边形组成。9*4表示该数组中所给定的顶点总数,一个四边形有四个顶点,9个四边形就有36个顶点,其中两个四边形公用的顶点重复计算。
      NORMALS:并且,需要指定每个四边形的法向量,一个平面四边形只有一个法向量,这个法向量分配给这个四边形的每个顶点。所有四边形法向量的计算按照右手螺旋规则进行,这可保证所有四边形具有相同侧的法向量

    • 定义一个三维数组存放这种网格数据。
      float[][][] SurfacePointxyz=new float[4] [4] [3];
      QuadArray类的对象SurfaceQuadArray中每一个元素表示一个四边形,该四边形中包含有四个顶点,顶点存放顺序按照法向量的计算顺序。如果需要取法向量的反方向,则只需将法向量反向,或者改变计算法向量顶点的顺序。

      对于第一个四边形来说,法向量的计算与顶点的存放顺序应该为:点(0,0)、点(1,0)、点(1,1)、点(0,1)由上图可知次顺序为逆时针,右手螺旋定则可得法向量垂直于此面。第二个四边形法向量的计算与顶点的存放顺序应该为:点(0,1)、点(1,1)、点(1,2)、点(0,2)。其中两个四边形中有两个顶点是重复的。其余依次类推。

    • 在QuadArray类中,四边形数组中的所有四边形的所有顶点都要统一编号,编号从0开始。

      例如

      第一个四边形的四个顶点(点(0,0)、点(1,0)、点(1,1)、点(0,1))的编号分别为:0、1、2、3
      第二个四边形的四个顶点(点(0,1)、点(1,1)、点(1,2)、点(0,2))的编号紧接着第一个四边形分别为:4、5、6、7
      即使对两个四边形重复的顶点,也要按四边形单独编号顺序依次进行编号。其余四边形编号,依次类推。

四边形网格实例——旋转体代码展示

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Geometry;
import javax.media.j3d.Material;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class YfRotationQuadarray extends Applet {
	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup = new BranchGroup();
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Color3f color3f = new Color3f(1.f, 1.f, 1.f);
		Background background = new Background(color3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);

		Color3f dirColor3f = new Color3f(1.f, 0.f, 0.f);
		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);

		TransformGroup transformGroup = new TransformGroup();
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(transformGroup);

		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);

		MouseZoom mouseZoom = new MouseZoom();
		mouseZoom.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);

		MouseTranslate mouseTranslate = new MouseTranslate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseTranslate);
		mouseRotate.setSchedulingBounds(boundingSphere);
		// add
		transformGroup.addChild(new SurfaceDisplay());

		branchGroup.compile();
		return branchGroup;

	}

	public YfRotationQuadarray() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration=SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d=new Canvas3D(configuration);
		add("Center",canvas3d);
		BranchGroup branchGroup=createBranchGroup();
		SimpleUniverse simpleUniverse=new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
		
	}
	
	public static void main(String[] args) {
		new MainFrame(new YfRotationQuadarray(), 300,300);
	}

}

class SurfaceDisplay extends Shape3D {
	public SurfaceDisplay() {
		this.setAppearance(createAppearance());
		this.setGeometry(creaGeometry());
	}

	// 5行每行51个 每个点xyz3个坐标
	float[][][] SurfacePointsxyz = new float[5][51][3];

	public Geometry creaGeometry() {
		int i, j, k, c;
		int n0 = 50;
		float theta;

		// 定义在xoy平面内的旋转线,旋转轴为y轴
		float[] Xp0 = { .3f, .4f, .5f, .6f, .9f };// 有5层 宽度从下向上递增,所以x也增加
		float[] Yp0 = { -.4f, -.2f, 0.f, .2f, .5f };// y的高度
		// 计算对圆周n0等分后所得的旋转角 2π/n0
		theta = 2.f * (float) Math.PI / n0;
		for (i = 0; i < 5; i++) {
			for (j = 0; j < n0 + 1; j++) {
				SurfacePointsxyz[i][j][0] = Xp0[i] * (float) Math.cos(theta * j);
				SurfacePointsxyz[i][j][1] = Yp0[i];
				SurfacePointsxyz[i][j][2] = Xp0[i] * (float) Math.sin(theta * j);

			}
		}

		// 按顺时针方向设置每个四边形点的坐标值(5层每层51个四边形4个顶点),求法向量
		QuadArray quadArray = new QuadArray(5 * n0 * 4, QuadArray.COORDINATES | QuadArray.NORMALS);
		// 该变量用来对顶点按顺序编号,该编号是连续的,不能重复
		c = 0;
		// 垂直y方向有5个点但是以四边形来看 垂直方向只有4个四边形,n0同样因此少一
		for (i = 0; i < 4; i++) {
			for (j = 0; j < n0; j++) {
				// 设置一个四边形的点
				Point3f A = new Point3f(SurfacePointsxyz[i][j][0], SurfacePointsxyz[i][j][1],
						SurfacePointsxyz[i][j][2]);
				Point3f B = new Point3f(SurfacePointsxyz[i + 1][j][0], SurfacePointsxyz[i + 1][j][1],
						SurfacePointsxyz[i + 1][j][2]);
				Point3f C = new Point3f(SurfacePointsxyz[i + 1][j + 1][0], SurfacePointsxyz[i + 1][j + 1][1],
						SurfacePointsxyz[i + 1][j + 1][2]);
				Point3f D = new Point3f(SurfacePointsxyz[i][j + 1][0], SurfacePointsxyz[i][j + 1][1],
						SurfacePointsxyz[i][j + 1][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);
				// 把由a,b所得法向量付给n
				Vector3f n = new Vector3f();
                //求b和a的叉积
				n.cross(b, a);
				// 这个方式是把当前向量单位化(对本向量进行操作,使长度变为1)
				n.normalize();

				// 从c序号处开始设置quadArray对象中顶点数组的坐标值
				quadArray.setCoordinate(c, A);
				quadArray.setCoordinate(c + 1, B);
				quadArray.setCoordinate(c + 2, C);
				quadArray.setCoordinate(c + 3, D);

				// 设置点的序号所对应的法向量
				quadArray.setNormal(c, n);
				quadArray.setNormal(c + 1, n);
				quadArray.setNormal(c + 2, n);
				quadArray.setNormal(c + 3, n);
				c = c + 4;

			}

		}
		return quadArray;
	}

	public Appearance createAppearance() {
		// 指定外观,这样才有明暗效果
		PolygonAttributes polygona = new PolygonAttributes();
		// 表示在多边形显示之前考虑点的反向法向量
		polygona.setBackFaceNormalFlip(true);
		// 对面侧的选择
		polygona.setCullFace(PolygonAttributes.CULL_NONE);
		// polygona.setPolygonMode(PolygonAttributes.POLYGON_LINE);
		// polygona.setPolygonMode(PolygonAttributes.POLYGON_POINT);

		Appearance appearance = new Appearance();
		appearance.setPolygonAttributes(polygona);
		Material material = new Material();
		Color3f white = new Color3f(1.0f, .0f, .0f);

		Color3f red = new Color3f(.0f, .0f, 1.0f);
		// 设置散射光
		material.setDiffuseColor(white);
		// 设置镜面反射光material.setSpecularColor(red);
		// 设置发亮值material.setShininess(20.0f);
		appearance.setMaterial(material);
		return appearance;

	}

}

image-20211102203410667

三角形网格曲面展示

  • 在下图三角网格中,将每一个四边形分为两个三角形,总共给出了16个点的数据,16个数据点可连成18个三角形。

    image-20211102204543895

  • 可用TriangleArray类定义上图这种三角网格数据。

    •   TriangleArray SurfaceTriangleArray=new TriangleArray(18*3,GeometryArray.COORDINATES|GeometryArray.NORMALS);
      
    • 在上图三角形数组中,将这种网格曲面可看作由18个三角形组成。18*3表示该数组中所给定的顶点总数,一个三角形有3个顶点,18个三角形就有54个顶点,其中两个三角形公用的顶点重复计算。

    • 需要指定每个三角形的法向量,一个三角形只有一个法向量,这个法向量分配给这个三角形的每个顶点。所有三角形法向量的计算按照右手螺旋规则进行,这可保证所有三角形具有相同侧的法向量

  • 定义相同的三维数组来存放这种网格数据。
    float[][][] SurfacePointxyz=new float[4] [4] [3];

    • TriangleArray类的对象SurfaceTriangleArray中每一个元素表示一个三角形,该三角形中包含有3个顶点,顶点存放顺序按照法向量的计算顺序。如果需要取法向量的反方向,则只需将法向量反向,或者改变计算法向量顶点的顺序。
    • (1)第一个三角形顶点存放顺序为:点(0,1)、点(0,0)、点(1,0);
      (2)第二个三角形顶点存放顺序为:点(0,1)、点(1,0)、点(1,1)。在TriangleArray类的三角形数组中每个三角形顶点的编号和四边形数组相似。
      当然,也可使用TriangleStripArray类来构造三角网格曲面,但这里介绍的三角网格的构造方法是最基本的处理方法,可解决复杂曲面的设计问题。

三角形网格实例——旋转体代码展示

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Geometry;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Material;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TriangleArray;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class YfRotationTrianglearray extends Applet {

	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup = new BranchGroup();
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Color3f bgcolor3f = new Color3f(1.f, 1.f, 1.f);
		Background background = new Background(bgcolor3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);

		Color3f dirColor = new Color3f(1.0f, 0.0f, 0.0f);
		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
		DirectionalLight directionalLight = new DirectionalLight(dirColor, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);

		TransformGroup transformGroup = new TransformGroup();
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(transformGroup);

		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);

		MouseZoom mouseZoom = new MouseZoom();
		mouseZoom.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);

		MouseTranslate mouseTranslate = new MouseTranslate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseTranslate);
		mouseRotate.setSchedulingBounds(boundingSphere);

		// add
		transformGroup.addChild(new SurfaceDisplay1());
		branchGroup.compile();
		return branchGroup;

	}

	public YfRotationTrianglearray() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration = SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d = new Canvas3D(configuration);
		add("Center", canvas3d);
		BranchGroup branchGroup = createBranchGroup();
		SimpleUniverse simpleUniverse = new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);
	}

	public static void main(String[] args) {
		new MainFrame(new YfRotationTrianglearray(), 300, 300);
	}

}

class SurfaceDisplay1 extends Shape3D{
	public SurfaceDisplay1() {
		this.setAppearance(createAppearance());
		this.setGeometry(createGeometry());
	}

	float[][][] SurfacePointsxyz = new float[5][51][3];

	public Geometry createGeometry() {
		int i, j, k, c;
		int nn = 50;
		float theata;
		// 定义xoy平面的旋转线,旋转轴为y轴
		float[] Xp0 = { .5f, .2f, .8f, .5f, .9f };// 有5层 宽度从下向上变化,所以x也变化
		float[] Yp0 = { -.4f, -.2f, -0.1f, .2f, .5f };// y的高度
		// 计算对圆周n0等分后所得的旋转角 2π/n0
		theata = 2.f * (float) Math.PI / nn;
		// 计算旋转面上点的x,y,z坐标值
		for (i = 0; i < 5; i++) {
			for (j = 0; j < nn + 1; j++) {
				SurfacePointsxyz[i][j][0] = Xp0[i] * (float) Math.cos(theata * j);
				SurfacePointsxyz[i][j][1] = Yp0[i];
				SurfacePointsxyz[i][j][2] = Xp0[i] * (float) Math.sin(theata * j);
			}
		}

		TriangleArray triangleArray = new TriangleArray(5 * nn * 2 * 3,
				GeometryArray.COORDINATES | GeometryArray.NORMALS);
		c=0;
		for( i=0;i<4;i++) {
			for(j=0;j<nn;j++) {
				//第一个三角形
				Point3f A = new Point3f(SurfacePointsxyz[i][j][0], SurfacePointsxyz[i][j][1],
						SurfacePointsxyz[i][j][2]);
				Point3f B = new Point3f(SurfacePointsxyz[i + 1][j][0], SurfacePointsxyz[i + 1][j][1],
						SurfacePointsxyz[i + 1][j][2]);
				Point3f C = new Point3f(SurfacePointsxyz[i][j + 1][0], SurfacePointsxyz[i][j + 1][1],
						SurfacePointsxyz[i][j + 1][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);
				// 把由a,b所得法向量付给n
				Vector3f n = new Vector3f();
				//求b和a的叉积
				n.cross(b, a);
				// 这个方式是把当前向量单位化(对本向量进行操作,使长度变为1)
				n.normalize();
				
				// 从c序号处开始设置quadArray对象中顶点数组的坐标值
				triangleArray.setCoordinate(c, A);
				triangleArray.setCoordinate(c + 1, B);
				triangleArray.setCoordinate(c + 2, C);
				// 设置点的序号所对应的法向量
				triangleArray.setNormal(c, n);
				triangleArray.setNormal(c + 1, n);
				triangleArray.setNormal(c + 2, n);
				c=c+3;
				//第二个三角形
				Point3f A0 = new Point3f(SurfacePointsxyz[i][j+1][0], SurfacePointsxyz[i][j+1][1],
						SurfacePointsxyz[i][j+1][2]);
				Point3f B0 = new Point3f(SurfacePointsxyz[i + 1][j][0], SurfacePointsxyz[i + 1][j][1],
						SurfacePointsxyz[i + 1][j][2]);
				Point3f C0 = new Point3f(SurfacePointsxyz[i + 1][j + 1][0], SurfacePointsxyz[i + 1][j + 1][1],
						SurfacePointsxyz[i + 1][j + 1][2]);
				//计算法向量
				Vector3f a0 = new Vector3f(A0.x - B0.x, A0.y - B0.y, A0.z - B0.z);
				Vector3f b0 = new Vector3f(C0.x - B0.x, C0.y - B0.y, C0.z - B0.z);
				// 把由a,b所得法向量付给n
				Vector3f n0 = new Vector3f();
				//求b和a的叉积
				n0.cross(b0, a0);
				// 这个方式是把当前向量单位化(对本向量进行操作,使长度变为1)
				n0.normalize();
				
				// 从c序号处开始设置quadArray对象中顶点数组的坐标值
				triangleArray.setCoordinate(c, A0);
				triangleArray.setCoordinate(c + 1, B0);
				triangleArray.setCoordinate(c + 2, C0);
				// 设置点的序号所对应的法向量
				triangleArray.setNormal(c, n0);
				triangleArray.setNormal(c + 1, n0);
				triangleArray.setNormal(c + 2, n0);
				c=c+3;
			}
		}
		return triangleArray;
	}
	public Appearance createAppearance() {
		// 指定外观,这样才有明暗效果
		PolygonAttributes polygona = new PolygonAttributes();
		// 表示在多边形显示之前考虑点的反向法向量
		polygona.setBackFaceNormalFlip(true);
		// 对面侧的选择
		polygona.setCullFace(PolygonAttributes.CULL_NONE);
		// polygona.setPolygonMode(PolygonAttributes.POLYGON_LINE);
		// polygona.setPolygonMode(PolygonAttributes.POLYGON_POINT);

		Appearance appearance = new Appearance();
		appearance.setPolygonAttributes(polygona);
		Material material = new Material();
		Color3f white = new Color3f(1.0f, .0f, .0f);

		Color3f red = new Color3f(.0f, .0f, 1.0f);
		// 设置散射光
		material.setDiffuseColor(white);
		// 设置镜面反射光material.setSpecularColor(red);
		// 设置发亮值material.setShininess(20.0f);
		appearance.setMaterial(material);
		return appearance;

	}
}

image-20211102221804095

三角网格与四边网格混合使用实例

  • 一种最常用的旋转体是球体,下面以球体为例进行说明三角网格与四边网格混合使用。
    球心在原点,半径为R的球形面。
    首先在xoy平面内对半圆的180度进行等分,求得所有等分点(绿色实现)
    然后对该半圆的所有等分点绕y轴旋转360度,就可生成球体表面上所有的数据点;(绿色实线按红线旋转)
    利用这些数据点可将球顶与球底组织成两个三角网格或两个三角形扇,中间部分则全部为四边网格。

    image-20211102205110073

  • 下面介绍旋转过程

    • 首先需要计算球体表面的数据点,这时需要给定球体表面在横向与纵向的等分点数n1和n2,等分数越大,显示的球面越精确。由等分点数计算等分角。
    • 在横向用n2对360度角进行等分,在纵向用n1对180度角进行等分。确定了等分角后,在给定半径的条件下,就可用双重for循环计算各分点处的x、y、z坐标值。根据这些坐标值就可以用三角网格与四边网格的方式显示该球面。球体表面点的x、y、z坐标计算示意图如上图
    • 由于TriangleArray与QuadArray属于同一个等价类,因此可用Shape3D的addGeometry方法将其加入到同一个Shape3D节点,
    • 此时,三角网格与四边网格具有同一个Appearance外观。
      如果想让三角网格与四边网格部分分别具有不同Appearance外观,则要将其分别加入到不同的Shape3D节点,这样不同的Shape3D节点可有不同的Appearance外观。
  • 代码展示:

package java3d;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Material;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TriangleArray;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

//球由两个三角形网格和一个四边形网格组成
public class SphereTriangleQuadsurfacenew extends Applet {

	public BranchGroup createBranchGroup() {
		BranchGroup branchGroup = new BranchGroup();
		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Color3f bgcolor3f = new Color3f(1.f, 1.f, 1.f);
		Background background = new Background(bgcolor3f);
		background.setApplicationBounds(boundingSphere);
		branchGroup.addChild(background);

		Color3f dirColor3f = new Color3f(1.f, 1.f, 1.f);
		Vector3f vector3f = new Vector3f(0.f, 0.f, -1.f);
		DirectionalLight directionalLight = new DirectionalLight(dirColor3f, vector3f);
		directionalLight.setInfluencingBounds(boundingSphere);
		branchGroup.addChild(directionalLight);

		TransformGroup transformGroup = new TransformGroup();
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		branchGroup.addChild(transformGroup);

		MouseRotate mouseRotate = new MouseRotate();
		mouseRotate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseRotate);
		mouseRotate.setSchedulingBounds(boundingSphere);

		MouseZoom mouseZoom = new MouseZoom();
		mouseZoom.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseZoom);
		mouseZoom.setSchedulingBounds(boundingSphere);

		MouseTranslate mouseTranslate = new MouseTranslate();
		mouseTranslate.setTransformGroup(transformGroup);
		branchGroup.addChild(mouseTranslate);
		mouseTranslate.setSchedulingBounds(boundingSphere);

		// add
		transformGroup.addChild(new SphereQuadArrayDisplay());
		transformGroup.addChild(new SphereTriangleArrayDisplay());
		branchGroup.compile();
		return branchGroup;

	}

	public SphereTriangleQuadsurfacenew() {
		setLayout(new BorderLayout());
		GraphicsConfiguration configuration = SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas3d = new Canvas3D(configuration);
		add("Center", canvas3d);
		BranchGroup branchGroup = createBranchGroup();
		SimpleUniverse simpleUniverse = new SimpleUniverse(canvas3d);
		simpleUniverse.getViewingPlatform().setNominalViewingTransform();
		simpleUniverse.addBranchGraph(branchGroup);

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MainFrame(new SphereTriangleQuadsurfacenew(), 300, 300);
	}

}

class SphereTriangleArrayDisplay extends Shape3D {
	SphereTriangleArrayDisplay() {// 定义两个TriangleArray数组
		float theta1, theta2;// 等分角
		float R = 0.8f;// 球体半径
		int i, j, k;
		int nn1 = 20, nn2 = 50;// 对球体表面的纵向与横向等分点数
		TriangleArray Trianglesurface1 = new TriangleArray(nn2 * 3, TriangleArray.COORDINATES | TriangleArray.NORMALS);

		TriangleArray Trianglesurface2 = new TriangleArray(nn2 * 3, TriangleArray.COORDINATES | TriangleArray.NORMALS);
		// 定义存放球体体表数据点的数组
		float[][][] spherexyz = new float[100][200][3];

		theta1 = (float) Math.PI / nn1;// 纵向分角180°
		theta2 = 2.0f * (float) Math.PI / nn2;// 横向分角360°

		// 球体表坐标点计算
		// 内层为横向外层为纵向
		for (i = 0; i < nn1 + 1; i++) {
			for (j = 0; j < nn2 + 1; j++) {
				spherexyz[i][j][0] = R * (float) Math.sin(i * theta1) * (float) Math.cos(j * theta2);
				spherexyz[i][j][1] = R * (float) Math.cos(i * theta1);
				spherexyz[i][j][2] = R * (float) Math.sin(i * theta1) * (float) Math.sin(j * theta2);
			}
		}

		int c = 0;// 以顶点数累加的方式设置点的序号
		Point3f A01 = new Point3f(spherexyz[0][0][0], spherexyz[0][0][1], spherexyz[0][0][2]);
		for (j = 0; j < nn2; j++) {
			Point3f A1 = new Point3f(spherexyz[1][j][0], spherexyz[1][j][1], spherexyz[1][j][2]);
			Point3f A2 = new Point3f(spherexyz[1][j + 1][0], spherexyz[1][j + 1][1], spherexyz[1][j + 1][2]);
			// 设置法向量
			Vector3f a = new Vector3f(A1.x - A01.x, A1.y - A01.y, A1.z - A01.z);
			Vector3f b = new Vector3f(A2.x - A01.x, A2.y - A01.y, A2.z - A01.z);
			Vector3f n = new Vector3f();
			n.cross(a, b);
			n.normalize();
			// 设置点序号及坐标
			Trianglesurface1.setCoordinate(c, A01);
			Trianglesurface1.setCoordinate(c + 1, A1);
			Trianglesurface1.setCoordinate(c + 2, A2);
			// 设置点法向量
			Trianglesurface1.setNormal(c, n);
			Trianglesurface1.setNormal(c + 1, n);
			Trianglesurface1.setNormal(c + 2, n);

			c = c + 3;
		}
		c = 0;

		Point3f A02 = new Point3f(spherexyz[nn1][0][0], spherexyz[nn1][0][1], spherexyz[nn1][0][2]);
		for (j = 0; j < nn2; j++) {
			Point3f A1 = new Point3f(spherexyz[nn1 - 1][j][0], spherexyz[nn1 - 1][j][1], spherexyz[nn1 - 1][j][2]);

			Point3f A2 = new Point3f(spherexyz[nn1 - 1][j + 1][0], spherexyz[nn1 - 1][j + 1][1],
					spherexyz[nn1 - 1][j + 1][2]);
			Vector3f a = new Vector3f(A1.x - A02.x, A1.y - A02.y, A1.z - A02.z);
			Vector3f b = new Vector3f(A2.x - A02.x, A2.y - A02.y, A2.z - A02.z);
			Vector3f n = new Vector3f();
			n.cross(a, b);
			n.normalize();
			// 设置点序号及坐标
			Trianglesurface2.setCoordinate(c, A02);
			Trianglesurface2.setCoordinate(c + 1, A1);
			Trianglesurface2.setCoordinate(c + 2, A2);
			// 设置点法向量
			Trianglesurface2.setNormal(c, n);
			Trianglesurface2.setNormal(c + 1, n);
			Trianglesurface2.setNormal(c + 2, n);
			c = c + 3;
		}
		this.addGeometry(Trianglesurface1);
		this.addGeometry(Trianglesurface2);
		this.setAppearance(createAppearance0());
	}

	Appearance createAppearance0() {// 指定外观
		PolygonAttributes polygona = new PolygonAttributes();

		polygona.setCullFace(PolygonAttributes.CULL_NONE);
		polygona.setBackFaceNormalFlip(true);
		// polygona.setPolygonMode(PolygonAttributes.POLYGON_LINE);
		Appearance appearance = new Appearance();
		appearance.setPolygonAttributes(polygona);
		Material material = new Material();
		Color3f red = new Color3f(0.0f, 1.0f, 0.0f);
		material.setDiffuseColor(red);
		appearance.setMaterial(material);
		return appearance;

	}
}

class SphereQuadArrayDisplay extends Shape3D {
	SphereQuadArrayDisplay() {
		// 计算球面上点的x、y、z坐标
		int nn1 = 20, nn2 = 50;
		float theta1, theta2;
		float R = 0.8f;
		int i, j, k;
		float[][][] spherexyz = new float[100][200][3];
		theta1 = (float) Math.PI / nn1;
		theta2 = 2.0f * (float) Math.PI / nn2;
		for (i = 0; i < nn1 + 1; i++)
			for (j = 0; j < nn2 + 1; j++) {
				spherexyz[i][j][0] = R * (float) Math.sin(i * theta1) * (float) Math.cos(j * theta2);
				spherexyz[i][j][1] = R * (float) Math.cos(i * theta1);
				spherexyz[i][j][2] = R * (float) Math.sin(i * theta1) * (float) Math.sin(j * theta2);
			}
		QuadArray Quadsurface = new QuadArray((nn1 - 2) * nn2 * 4, GeometryArray.COORDINATES | GeometryArray.NORMALS);
		int c = 0;// 以顶点数累加的方式设置数组中顶点的序号
		for (i = 1; i < nn1 - 1; i++) {
			for (j = 0; j < nn2; j++) {// 设置一个四边形上的4个点坐标值
				Point3f A = new Point3f(spherexyz[i][j][0], spherexyz[i][j][1], spherexyz[i][j][2]);
				Point3f B = new Point3f(spherexyz[i][j + 1][0], spherexyz[i][j + 1][1], spherexyz[i][j + 1][2]);
				Point3f C = new Point3f(spherexyz[i + 1][j + 1][0], spherexyz[i + 1][j + 1][1],
						spherexyz[i + 1][j + 1][2]);
				Point3f D = new Point3f(spherexyz[i + 1][j][0], spherexyz[i + 1][j][1], spherexyz[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();
				// 设置点的序号
				Quadsurface.setCoordinate(c, A);
				Quadsurface.setCoordinate(c + 1, B);
				Quadsurface.setCoordinate(c + 2, C);
				Quadsurface.setCoordinate(c + 3, D);
				// 按序号设置点法向量
				Quadsurface.setNormal(c, n);
				Quadsurface.setNormal(c + 1, n);
				Quadsurface.setNormal(c + 2, n);
				Quadsurface.setNormal(c + 3, n);
				c = c + 4;
			}
			this.addGeometry(Quadsurface);
			this.setAppearance(createAppearance0());
		}
	}

	Appearance createAppearance0() {// 指定外观
		PolygonAttributes polygona = new PolygonAttributes();
		polygona.setCullFace(PolygonAttributes.CULL_NONE);
		polygona.setBackFaceNormalFlip(true);
		// polygona.setPolygonMode(PolygonAttributes.POLYGON_LINE);
		Appearance appearance = new Appearance();
		appearance.setPolygonAttributes(polygona);
		Material material = new Material();
		Color3f red = new Color3f(1.0f, .0f, .0f);
		// material.setAmbientColor(red);
		// material.setSpecularColor(red);
		material.setDiffuseColor(red);
		// material.setEmissiveColor(red);
		// material.setShininess(50.f);
		appearance.setMaterial(material);
		return appearance;
	}
}

image-20211104104636178

  • 18
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java语言图形界面设计基础详解Java语言中的图形界面设计主要依赖于Java Swing库和Java AWT库。Swing库是一个基于Java AWT库的扩展,提供了更丰富的控件和更好的外观。 在Java中,图形界面设计主要分为以下几个步骤: 1. 创建窗口(JFrame):使用JFrame创建窗口,可以设置窗口的大小、标题、关闭方式等属性。 2. 添加控件(JButton、JLabel、JTextField等):使用各种控件创建需要的控件,然后使用窗口的add()方法将控件添加到窗口中。 3. 设置控件属性:可以设置控件的大小、位置、文本、字体、颜色等属性。 4. 添加事件处理器:为控件添加事件处理器,可以在用户操作控件时响应相应的事件。 5. 显示窗口:使用窗口的setVisible()方法将窗口显示出来。 下面是一个简单的Java图形界面程序示例: ```java import javax.swing.*; public class MyFrame extends JFrame { public MyFrame() { // 设置窗口标题 setTitle("My Frame"); // 设置窗口大小 setSize(300, 200); // 设置窗口关闭方式 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 创建一个按钮 JButton button = new JButton("Click me"); // 将按钮添加到窗口中 add(button); // 显示窗口 setVisible(true); } public static void main(String[] args) { // 创建窗口对象 MyFrame frame = new MyFrame(); } } ``` 这个程序创建了一个窗口,并在窗口中添加了一个按钮。当用户点击按钮时,可以响应相应的事件处理器,实现更复杂的交互逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值