How to create hollow cylinder and truncated cone with JavaFX?

前端 未结 3 709
既然无缘
既然无缘 2021-01-26 07:20

I\'m learning JavaFX 3D. So far I have not found a way how I can create the following objects:

  • Hollow cylinder
  • Truncated cone

Can someone p

相关标签:
3条回答
  • 2021-01-26 07:58

    I know it's an old question but I've been trying to solve similar problem so here is my solution for truncated cone:

    public class Cone extends Group{
    
    int rounds = 360;
    int r1 = 100;
    int r2 = 50;
    int h = 100;
    
    public Cone() {
        Group cone = new Group();
        PhongMaterial material = new PhongMaterial(Color.BLUE);
    
        float[] points = new float[rounds *12];
        float[] textCoords = {
                0.5f, 0,
                0, 1,
                1, 1
        };
        int[] faces = new int[rounds *12];
    
        for(int i= 0; i<rounds; i++){
            int index = i*12;
            //0
            points[index] = (float)Math.cos(Math.toRadians(i))*r2;
            points[index+1] = (float)Math.sin(Math.toRadians(i))*r2;
            points[index+2] = h/2;
            //1
            points[index+3] = (float)Math.cos(Math.toRadians(i))*r1;
            points[index+4] = (float)Math.sin(Math.toRadians(i))*r1;
            points[index+5] = -h/2;
            //2
            points[index+6] = (float)Math.cos(Math.toRadians(i+1))*r1;
            points[index+7] = (float)Math.sin(Math.toRadians(i+1))*r1;
            points[index+8] = -h/2;
            //3
            points[index+9] = (float)Math.cos(Math.toRadians(i+1))*r2;
            points[index+10] = (float)Math.sin(Math.toRadians(i+1))*r2;
            points[index+11] = h/2;        
        }
    
        for(int i = 0; i<rounds ; i++){
            int index = i*12;
            faces[index]=i*4;
            faces[index+1]=0;
            faces[index+2]=i*4+1;
            faces[index+3]=1;
            faces[index+4]=i*4+2;
            faces[index+5]=2;
    
            faces[index+6]=i*4;
            faces[index+7]=0;
            faces[index+8]=i*4+2;
            faces[index+9]=1;
            faces[index+10]=i*4+3;
            faces[index+11]=2;
        }
    
        TriangleMesh mesh = new TriangleMesh();
        mesh.getPoints().addAll(points);
        mesh.getTexCoords().addAll(textCoords);
        mesh.getFaces().addAll(faces);
    
        Cylinder circle1 = new Cylinder(r1, 0.1);
        circle1.setMaterial(material);
        circle1.setTranslateZ( -h / 2);
        circle1.setRotationAxis(Rotate.X_AXIS);
        circle1.setRotate(90);
    
        Cylinder circle2 = new Cylinder(r2, 0.1);
        circle2.setMaterial(material);
        circle2.setTranslateZ( h / 2);
        circle2.setRotationAxis(Rotate.X_AXIS);
        circle2.setRotate(90);
    
    
         MeshView meshView = new MeshView();
        meshView.setMesh(mesh);
        meshView.setMaterial(material);
        //meshView.setDrawMode(DrawMode.LINE);
        cone.getChildren().addAll(meshView);
        Rotate r1 = new Rotate(90, Rotate.X_AXIS);
        cone.getTransforms().add(r1);
        getChildren().addAll(cone);
    }
    

    Hope this helps someone in the future!

    0 讨论(0)
  • 2021-01-26 07:59

    I started using the code supplied in an other answer on this page, but I wanted to make it as a single mesh without the cylinders in the ends. I also calculated better texture coordinates and normals. (I use Vecmath for the normal calculation. This should probably be changed to Apache commons math or something more modern...)

     /**
     * Create a cone shape. Origin is center of base (bottom circle). Height is along the Y axis
     * @param m A given TirangleMesh
     * @param res The resolution of the circles
     * @param radius The base radius
     * @param topRadius The top radius. If this is > 0 the cone is capped
     * @param height The height of the cone along the Y axis
     * @param texture The texture
     */
    public static void createCone(TriangleMesh m, int res, float radius, float topRadius, float height, TextureMapping texture)
    {
      if (texture == null)
        texture = defaultTextureMapping;
    
      m.setVertexFormat(VertexFormat.POINT_NORMAL_TEXCOORD);
          
      float[] v = new float[res * 6]; //vertices
      float[] n = new float[(res+2)*3]; //face normals
      float[] uv = new float[(res * 8) + 4]; //texture coordinates
      int[] f = new int[18*(2*res-2)]; // faces ((divisions * 18) + ((divisions-2)*18))
      
      float radPerDiv = ((float)Math.PI * 2f) / res;
      
      int tv = res * 3; //top plane vertices start index
      int tuv = (res+1) * 2; //top plane uv start index
      int bcuv = tuv * 2;//(res * 4) + 4; //bottom cap uv start index
      int tcuv = bcuv + (res * 2); //bottom cap uv start index
      for(int i = 0; i < res; i++)
      {
        int vi = i*3;  
        float cos = (float) Math.cos(radPerDiv*(i));
        float sin = (float) Math.sin(radPerDiv*(i));
        //bottom plane vertices
        v[vi] = cos * radius; //X
        v[vi + 1] = 0; //Y
        v[vi + 2] = sin * radius; //Z
        
        //top plane vertices
        v[tv + vi] = cos * topRadius; //X
        v[tv + vi + 1] = height; //Y
        v[tv + vi + 2] = sin * topRadius; //Z
        
        int uvi = i*2;
        //texture coordinate side down
        uv[uvi] = 1f-((float)i/(float)res);
        uv[uvi + 1] = 1f;
        
        //texture coordinate side up
        uv[tuv + uvi] = uv[uvi];
        uv[tuv + uvi + 1] = 0;
        
        //texture coordinate bottom cap
        uv[bcuv + uvi] = (1f+cos)/2f;
        uv[bcuv + uvi + 1] = (1f+sin)/2f;
        
        //texture coordinate top cap
        uv[tcuv + uvi] = (1f-cos)/2f;
        uv[tcuv + uvi + 1] = (1f+sin)/2f;
        
        //face normals
        if(i>0)
        {
          Vector3f p0 = new Vector3f(v[vi - 3], v[vi - 2], v[vi - 1]);
          Vector3f p1 = new Vector3f(v[vi], v[vi + 1], v[vi + 2]);
          Vector3f p2 = new Vector3f(v[tv + vi], v[tv + vi + 1], v[tv + vi + 2]);
          p1.sub(p0);
          p2.sub(p0);
          p0.cross(p2, p1);
          p0.normalize();
          n[vi - 3] = p0.x;
          n[vi - 2] = p0.y;
          n[vi - 1] = p0.z;
        }
        if(i==res-1)
        {
          Vector3f p0 = new Vector3f(v[vi], v[vi + 1], v[vi + 2]);
          Vector3f p1 = new Vector3f(v[0], v[1], v[2]);
          Vector3f p2 = new Vector3f(v[tv], v[tv + 1], v[tv + 2]);
          p1.sub(p0);
          p2.sub(p0);
          p0.cross(p2, p1);
          p0.normalize();
          n[vi] = p0.x;
          n[vi + 1] = p0.y;
          n[vi + 2] = p0.z;
        }
        
        //faces around
        int fi = i*18; 
        //first triangle of face
        f[fi] = i; //vertex
        f[fi+1] = i; //normal
        f[fi+2] = i; //uv
        
        f[fi+3] = res+i; //vertex
        f[fi+4] = i; //normal
        f[fi+5] = res+1+i; //uv
        
        f[fi+6] = i+1; //vertex
        f[fi+7] = i+1; //normal
        f[fi+8] = i+1; //uv
        
        //second triangle of face 
        f[fi+9] = i+1; //vertex
        f[fi+10] = i+1; //normal
        f[fi+11] = i+1; //uv
        
        f[fi+12] = res+i; //vertex
        f[fi+13] = i; //normal
        f[fi+14] = res+1+i; //uv
        
        f[fi+15] = res+i+1; //vertex
        f[fi+16] = i+1; //normal
        f[fi+17] = res+2+i; //uv
        
        //wrap around, use the first vertices/normals
        if(i==res-1)
        {
          f[fi+6] = 0; //vertex
          f[fi+9] = 0; //vertex
          f[fi+15] = res; //vertex
          
          f[fi+7] = 0; //normal
          f[fi+10] = 0; //normal
          f[fi+16] = 0; //normal
        }
        
        //top and bottom caps
        int fi2 = (i*9)+(res*18); //start index for bottom cap. Start after cone side is done
        int fi3 = fi2 + (res*9) - 18; //fi2 + ((divisions - 2) * 9) //start index for top cap. Start after the bottom cap is done 
        int uv2 = (res*2)+2; //start index of bottom cap texture coordinate 
        int uv3 = (res*3)+2; //start index of top cap texture coordinate 
        if(i<res-2)
        {
          //bottom cap
          f[fi2] = 0;
          f[fi2+1] = res; //normal
          f[fi2+2] = uv2; //uv
          
          f[fi2+3] = i+1;
          f[fi2+4] = res; //normal
          f[fi2+5] = uv2 + i+1; //uv
          
          f[fi2+6] = i+2;
          f[fi2+7] = res; //normal
          f[fi2+8] = uv2 + i+2; //uv
          
          //top cap
          f[fi3] = res;
          f[fi3+1] = res + 1; //normal
          f[fi3+2] = uv3; //uv
          
          f[fi3+3] = res+i+2;
          f[fi3+4] = res + 1; //normal
          f[fi3+5] = uv3  + i+2; //uv
          
          f[fi3+6] = res+i+1;
          f[fi3+7] = res + 1; //normal
          f[fi3+8] = uv3  + i+1; //uv
        }
      }
      
      //smooth normals
      float[] ns = new float[n.length];
      Vector3f n0 = new Vector3f();
      Vector3f n1 = new Vector3f();
      for(int i = 0; i < res; i++)
      {
        int p0 = i*3;
        int p1 = (i-1)*3;
        if(i==0)
          p1 = (res-1)*3;    
        n0.set(n[p0], n[p0+1], n[p0+2]);
        n1.set(n[p1], n[p1+1], n[p1+2]);
        n0.add(n1);
        n0.normalize();
        
        ns[p0] = n0.x;
        ns[p0+1] = n0.y;
        ns[p0+2] = n0.z;
      }
      
      int ni = res * 3;
      ns[ni + 1] = -1; //bottom cap normal Y axis
      ns[ni + 4] = 1; //top cap normal Y axis
      
      uv[tuv-1] = 1; //bottom ring end uv coordinate
      
      //set all data to mesh
      m.getPoints().setAll(v);
      m.getNormals().setAll(ns);
      m.getTexCoords().setAll(uv);
      m.getFaces().setAll(f);
    }
    

    Edit: And here is code for a hollow cone (or cylinder, just set both rads to same value) Here I am using JavaFX vectors in stead of Vecmath

    /**
     * Create a hollow cone shape. Origin is center of base (bottom circle). Height is along the Y axis
     * @param m A given TirangleMesh
     * @param res The resolution of the circles
     * @param radius The base radius
     * @param topRadius The top radius. If this is > 0 the cone is capped
     * @param height The height of the cone along the Y axis
     * @param thickness The thickness of the cone wall
     * @param center If the origo shall be in the center, False
     * @param texture The texture
     */
    public static void createHollowCone(TriangleMesh m, int res, float radius, float topRadius, float height, float thickness, boolean center, TextureMapping texture)
    {
      if (texture == null)
        texture = defaultTextureMapping;
      
      m.setVertexFormat(VertexFormat.POINT_NORMAL_TEXCOORD);
    
      float[] v = new float[res * 12]; //vertices
      float[] n = new float[res*3]; //face normals (raw)
      float[] uv = new float[(res * 24) + 8]; //texture coordinates
      int[] f = new int[res*72]; // faces 
      
      float radPerDiv = ((float)Math.PI * 2f) / res;
      float buvf = 1-(thickness/radius);
      float tuvf = 1-(thickness/topRadius);
      
      int otcvsi = res * 3; //outside top circle vertices start index
      int ibcvsi = res * 6; //inside bottom circle vertices start index
      int itcvsi = res * 9; //inside top circle vertices start index
      
      int ifsi = res*18; //inside faces start index
      int bfsi = res*36; //bottom faces start index
      int tfsi = res*54; //bottom faces start index
      
      int tuvsi = (res+1) * 2; //top plane uv start index
      int bcuvsi = tuvsi * 2;//(res * 4) + 4; //bottom cap uv start index
      int tcuvsi = bcuvsi + (res * 4); //bottom cap uv start index
      
      int bcfuvsi = bcuvsi/2; //bottom cap faces uv start index
      int tcfuvsi = tcuvsi/2; //top cap faces uv start index
      for(int i = 0; i < res; i++)
      {
        int vi = i*3;  
        float cos = (float) Math.cos(radPerDiv*(i));
        float sin = (float) Math.sin(radPerDiv*(i));
        
        //outside bottom circle vertices
        v[vi] = cos * radius; //X
        v[vi + 1] = center?-height/2f:0; //Y
        v[vi + 2] = sin * radius; //Z
        
        //outside top circle vertices
        v[otcvsi + vi] = cos * topRadius; //X
        v[otcvsi + vi + 1] = center?height/2f:height; //Y
        v[otcvsi + vi + 2] = sin * topRadius; //Z
        
        //inside bottom circle vertices
        v[ibcvsi + vi] = cos * (radius-thickness); //X
        v[ibcvsi + vi + 1] = center?-height/2f:0; //Y
        v[ibcvsi + vi + 2] = sin * (radius-thickness); //Z
        
        //inside top circle vertices
        v[itcvsi + vi] = cos * (topRadius-thickness); //X
        v[itcvsi + vi + 1] = center?height/2f:height; //Y
        v[itcvsi + vi + 2] = sin * (topRadius-thickness); //Z
        
        
        int uvi = i*2;
        //texture coordinate outer side down
        uv[uvi] = 1f-((float)i/(float)res);
        uv[uvi + 1] = 1f;
        
        //texture coordinate outer side up
        uv[tuvsi + uvi] = uv[uvi];
        uv[tuvsi + uvi + 1] = 0;
        
        //texture coordinate bottom
        uv[bcuvsi + uvi] = (1f+cos)/2f;
        uv[bcuvsi + uvi + 1] = (1f-sin)/2f;
         
        uv[(res*2)+bcuvsi + uvi] = (1f+(cos*buvf))/2f;
        uv[(res*2)+bcuvsi + uvi + 1] = (1f-(sin*buvf))/2f;
        
        //texture coordinate top cap
        uv[tcuvsi + uvi] = (1f+cos)/2f;
        uv[tcuvsi + uvi + 1] = (1f+sin)/2f;
        
        uv[(res*2)+tcuvsi + uvi] = (1f+(cos*tuvf))/2f;
        uv[(res*2)+tcuvsi + uvi + 1] = (1f+(sin*tuvf))/2f;      
        //face normals
        if(i>0)
        {
          Point3D p0 = new Point3D(v[vi - 3], v[vi - 2], v[vi - 1]);
          Point3D p1 = new Point3D(v[vi], v[vi + 1], v[vi + 2]);
          Point3D p2 = new Point3D(v[otcvsi + vi], v[otcvsi + vi + 1], v[otcvsi + vi + 2]);
          p1 = p1.subtract(p0);
          p2 = p2.subtract(p0);
          p0 = p2.crossProduct(p1);
          p0 = p0.normalize();
          n[vi - 3] = (float)p0.getX();
          n[vi - 2] = (float)p0.getY();
          n[vi - 1] = (float)p0.getZ();
        }
        if(i==res-1)
        {
          Point3D p0 = new Point3D(v[vi], v[vi + 1], v[vi + 2]);
          Point3D p1 = new Point3D(v[0], v[1], v[2]);
          Point3D p2 = new Point3D(v[otcvsi], v[otcvsi + 1], v[otcvsi + 2]);
          p1 = p1.subtract(p0);
          p2 = p2.subtract(p0);
          p0 = p2.crossProduct(p1);
          p0 = p0.normalize();
          n[vi] = (float)p0.getX();
          n[vi + 1] = (float)p0.getY();
          n[vi + 2] = (float)p0.getZ();
        }
       
        int fi = i*18; 
        //faces around outside
        
        //first triangle of face
        f[fi] = i; //vertex
        f[fi+1] = i; //normal
        f[fi+2] = i; //uv
        
        f[fi+3] = res+i; //vertex
        f[fi+4] = i; //normal
        f[fi+5] = res+1+i; //uv
        
        f[fi+6] = i+1; //vertex
        f[fi+7] = i+1; //normal
        f[fi+8] = i+1; //uv
        
        //second triangle of face 
        f[fi+9] = i+1; //vertex
        f[fi+10] = i+1; //normal
        f[fi+11] = i+1; //uv
        
        f[fi+12] = res+i; //vertex
        f[fi+13] = i; //normal
        f[fi+14] = res+1+i; //uv
        
        f[fi+15] = res+i+1; //vertex
        f[fi+16] = i+1; //normal
        f[fi+17] = res+2+i; //uv
        
        //faces around inside
        //first triangle of face
        f[ifsi+fi] = (res*2)+i; //vertex
        f[ifsi+fi+1] = res+i; //normal
        f[ifsi+fi+2] = res-i; //uv
        
        f[ifsi+fi+3] = (res*2)+i+1; //vertex
        f[ifsi+fi+4] = res+i+1; //normal
        f[ifsi+fi+5] = res-1-i; //uv
        
        f[ifsi+fi+6] = (res*3)+i; //vertex
        f[ifsi+fi+7] = res+i; //normal
        f[ifsi+fi+8] = res+res+1-i; //uv
        
        //second triangle of face 
        f[ifsi+fi+9] = (res*2)+i+1; //vertex
        f[ifsi+fi+10] = res+i+1; //normal
        f[ifsi+fi+11] = res-1-i; //uv
        
        f[ifsi+fi+12] = (res*3)+i+1; //vertex
        f[ifsi+fi+13] = res+i+1; //normal
        f[ifsi+fi+14] = res+res-i; //uv
        
        f[ifsi+fi+15] = (res*3)+i; //vertex
        f[ifsi+fi+16] = res+i; //normal
        f[ifsi+fi+17] = res+res+1-i; //uv
        
        //faces on bottom
        //first triangle of face
    
        f[bfsi+fi] = i; //vertex 0
        f[bfsi+fi+1] = res*2; //normal
        f[bfsi+fi+2] = bcfuvsi+i; //uv
        
        f[bfsi+fi+3] = i+1; //vertex 1
        f[bfsi+fi+4] = res*2; //normal
        f[bfsi+fi+5] = bcfuvsi+i+1; //uv
        
        f[bfsi+fi+6] = (res*2)+i+1; //vertex n+1
        f[bfsi+fi+7] = res*2; //normal
        f[bfsi+fi+8] = bcfuvsi+res+i+1; //uv
        
        
        //second triangle of face 
        f[bfsi+fi+9] = (res*2)+i+1; //vertex n+1
        f[bfsi+fi+10] = res*2; //normal
        f[bfsi+fi+11] = bcfuvsi+res+i+1; //uv
        
        f[bfsi+fi+12] = (res*2)+i; //vertex n
        f[bfsi+fi+13] = res*2; //normal
        f[bfsi+fi+14] = bcfuvsi+res+i; //uv
        
        f[bfsi+fi+15] = i; //vertex 0
        f[bfsi+fi+16] = res*2; //normal
        f[bfsi+fi+17] = bcfuvsi+i; //uv
        
        //faces on top
        //first triangle of face
        f[tfsi+fi] = res+i; //vertex 0
        f[tfsi+fi+1] = res*2+1; //normal
        f[tfsi+fi+2] = tcfuvsi+i; //uv
        
        f[tfsi+fi+3] = (res*3)+i; //vertex n
        f[tfsi+fi+4] = res*2+1; //normal
        f[tfsi+fi+5] = tcfuvsi+res+i; //uv
        
        f[tfsi+fi+6] = (res*3)+i+1; //vertex n+1
        f[tfsi+fi+7] = res*2+1; //normal
        f[tfsi+fi+8] = tcfuvsi+res+i+1; //uv
        
        //second triangle of face 
        f[tfsi+fi+9] = (res*3)+i+1; //vertex n+1
        f[tfsi+fi+10] = res*2+1; //normal
        f[tfsi+fi+11] = tcfuvsi+res+i+1; //uv
        
        f[tfsi+fi+12] = res+i+1; //vertex 1
        f[tfsi+fi+13] = res*2+1; //normal
        f[tfsi+fi+14] = tcfuvsi+i+1; //uv
        
        f[tfsi+fi+15] = res+i; //vertex 0
        f[tfsi+fi+16] = res*2+1; //normal
        f[tfsi+fi+17] = tcfuvsi+i; //uv
        
        //wrap around, use the first vertices/normals
        if(i==res-1)
        {
          f[fi+6] = 0; //vertex
          f[fi+9] = 0; //vertex
          f[fi+15] = res; //vertex
          
          f[ifsi+fi+3] = res*2; //vertex
          f[ifsi+fi+9] = res*2; //vertex
          f[ifsi+fi+12] = res*3; //vertex
          
          f[bfsi+fi+3] = 0; //vertex
          f[bfsi+fi+6] = res*2; //vertex
          f[bfsi+fi+9] = res*2; //vertex
          
          f[tfsi+fi+6] = res*3; //vertex
          f[tfsi+fi+9] = res*3; //vertex
          f[tfsi+fi+12] = res; //vertex
          
          
          f[fi+7] = 0; //normal
          f[fi+10] = 0; //normal
          f[fi+16] = 0; //normal
          
          f[ifsi+fi+4] = res; //normal
          f[ifsi+fi+10] = res; //normal
          f[ifsi+fi+13] = res; //normal
          
          
          f[bfsi+fi+5] = bcfuvsi; //uv
          f[bfsi+fi+8] = bcfuvsi+res; //uv
          f[bfsi+fi+11] = bcfuvsi+res; //uv
          
          f[tfsi+fi+8] = tcfuvsi+res; //uv
          f[tfsi+fi+11] = tcfuvsi+res; //uv
          f[tfsi+fi+14] = tcfuvsi; //uv
          
          
        }
        
        
      }
      
      //smooth normals
      float[] ns = new float[(n.length*2)+6];
      int ni = res * 3;
      for(int i = 0; i < res; i++)
      {
        int p0 = i*3;
        int p1 = (i-1)*3;
        if(i==0)
          p1 = (res-1)*3;    
        Point3D n0 = new Point3D(n[p0], n[p0+1], n[p0+2]);
        Point3D n1 = new Point3D(n[p1], n[p1+1], n[p1+2]);
        n0 = n0.add(n1);
        n0 = n0.normalize();
    
        ns[p0] = (float)n0.getX();
        ns[p0+1] = (float)n0.getY();
        ns[p0+2] = (float)n0.getZ();
        
        n0 = n0.multiply(-1);
        ns[ni+p0] = (float)n0.getX();
        ns[ni+p0+1] = (float)n0.getY();
        ns[ni+p0+2] = (float)n0.getZ();
    
      }
      
      ni = res * 6;
      ns[ni + 1] = -1; //bottom cap normal Y axis
      ns[ni + 4] = 1; //top cap normal Y axis
      
      uv[tuvsi-1] = 1; //bottom ring end uv coordinate
      
      
      //set all data to mesh
      m.getPoints().setAll(v);
      m.getNormals().setAll(ns);
      m.getTexCoords().setAll(uv);
      m.getFaces().setAll(f);
    }
    
    0 讨论(0)
  • 2021-01-26 08:20

    The first - create a cylinder, and use two different appearance objects - one for cylinder, side, and one for the two bases. For the two bases, use an invisible appearance (rendering attributes). For info on how to set different appearances to bases, set thread: http://forum.java.sun.com/thread.jspa?threadID=663825&tstart=0

    The second - use a clipping plane to clip of the bottom and top of the cylinder, and you have a hollow cylinder.

    Those two methods will give you a hollow cylinder with a COMPLETELY empty interior.

    If you're looking to have walls with a given thickness, there is a boolean operations set available on the internet. Create a large cylinder, and subtract a smaller cylinder. For info on the boolean op set, set this thread: http://forum.java.sun.com/thread.jspa?threadID=658612&tstart=0

    Finally, it's really pretty easy to create a cylinder's geometry yourself, and it can be automated really easily with a loop. I would create four separate geometries: one for the inner cylinder with the rendered faces on the inside, one for the outer cylinder, with the rendered faces on the outside, one for the base, a disc with a hole in the middle and bottom surfaces rendered, and one for the top, another disc with a hole in the middle, and top surfaces rendered.

    That can all be done pretty easily with a triangle strip array.

    0 讨论(0)
提交回复
热议问题