Colors 在javafx上为三角形网格中的单个三角形着色

Colors 在javafx上为三角形网格中的单个三角形着色,colors,javafx,geometry,mesh,javafx-3d,Colors,Javafx,Geometry,Mesh,Javafx 3d,我在JAVAFX中有一个三角形网格对象,希望 为三角形网格的各个三角形着色 或 为每个三角形的各个顶点上色,并根据每个顶点的颜色插值对三角形上色(例如,使用Gouraud着色) 特定的三角形网格对象是一个具有数百万个面的图标球体(这就是我使用三角形网格的原因:我需要速度) 我没有使用纹理坐标,因为我无法使用JAVAFX找到一个清晰的解释,另外我希望有一个更简单的方法。在JAVAFX 3D网格中着色的方式是由您指定的材质决定的。对于一个网格,只有一种材质,不可能将不同材质划分为同一网格的不同三角形

我在JAVAFX中有一个三角形网格对象,希望

  • 为三角形网格的各个三角形着色
  • 为每个三角形的各个顶点上色,并根据每个顶点的颜色插值对三角形上色(例如,使用Gouraud着色)
  • 特定的三角形网格对象是一个具有数百万个面的图标球体(这就是我使用三角形网格的原因:我需要速度)


    我没有使用纹理坐标,因为我无法使用JAVAFX找到一个清晰的解释,另外我希望有一个更简单的方法。

    在JAVAFX 3D网格中着色的方式是由您指定的材质决定的。对于一个网格,只有一种材质,不可能将不同材质划分为同一网格的不同三角形

    所以,如果你想避免纹理,恐怕唯一的方法就是在同一个网格中对具有相同颜色的三角形进行分组,并创建尽可能多的网格作为颜色

    相反,使用纹理是相对容易的…,因为只有一个网格、一种材质和一个具有所有颜色的图像

    我制作了一个二十面体的例子,为它构建了一个三角形,并添加了一个纹理来给所有的面上色

    为此,我们需要:

    • 12个顶点的三维坐标
    • 纹理uv贴图的2D规格化坐标
    • 还有那20张脸。每个面由6个索引p0、t0、p1、t1、p3、t3定义,其中p0、p1、p2和p3是点数组的索引,t0、t1、t2和t3是texCoords数组的索引

      公共类二十面体网格扩展了MeshView{

      public IcosahedronMesh(){
          setMesh(createCube());
      }
      private TriangleMesh createCube() {
          TriangleMesh m = new TriangleMesh();
      
          // POINTS
          m.getPoints().addAll(
              0f, 0f, -0.951057f, 
              0f, 0f, 0.951057f, 
              -0.850651f, 0f, -0.425325f, 
              0.850651f, 0f, 0.425325f, 
              0.688191f, -0.5f, -0.425325f, 
              0.688191f, 0.5f, -0.425325f, 
              -0.688191f, -0.5f, 0.425325f, 
              -0.688191f, 0.5f, 0.425325f, 
              -0.262866f, -0.809017f, -0.425325f, 
              -0.262866f, 0.809017f, -0.425325f, 
              0.262866f, -0.809017f, 0.425325f, 
              0.262866f, 0.809017f, 0.425325f
          );
      
          // TEXTURES
          m.getTexCoords().addAll(
                  0.181818f, 0f, 
                  0.363636f, 0f, 
                  0.545455f, 0f, 
                  0.727273f, 0f, 
                  0.909091f, 0f,
                  0.0909091f, 0.333333f,
                  0.272727f, 0.333333f, 
                  0.454545f, 0.333333f, 
                  0.636364f, 0.333333f, 
                  0.818182f, 0.333333f, 
                  1f, 0.333333f, 
                  0f, 0.666667f, 
                  0.181818f, 0.666667f, 
                  0.363636f, 0.666667f, 
                  0.545455f, 0.666667f, 
                  0.727273f, 0.666667f, 
                  0.909091f, 0.666667f, 
                  0.0909091f, 1f, 
                  0.272727f, 1f, 
                  0.454545f, 1f, 
                  0.636364f, 1f, 
                  0.818182f, 1f
          );
      
          // FACES
          m.getFaces().addAll(
                  1, 6, 11, 5, 7, 0, 
                  1, 12, 7, 11, 6, 5, 
                  1, 7, 6, 6, 10, 1, 
                  1, 13, 10, 12, 3, 6, 
                  1, 8, 3, 7, 11, 2,
                  4, 14, 8, 13, 0, 7, 
                  5, 9, 4, 8, 0, 3, 
                  9, 15, 5, 14, 0, 8, 
                  2, 10, 9, 9, 0, 4, 
                  8, 16, 2, 15, 0, 9,
                  11, 5, 9, 6, 7, 12,
                  7, 11, 2, 12, 6, 17, 
                  6, 6, 8, 7, 10, 13, 
                  10, 12, 4, 13, 3, 18, 
                  3, 7, 5, 8, 11, 14,
                  4, 13, 10, 14, 8, 19, 
                  5, 8, 3, 9, 4, 15, 
                  9, 14, 11, 15, 5, 20, 
                  2, 9, 7, 10, 9, 16, 
                  8, 15, 6, 16, 2, 21
          );
          return m;
      }
      
      }

    现在我们需要一个基于二十面体网络的图像,每个面的颜色如下:

    (找到图像)

    注意,映射是从(0,0)到(1,1)标准化坐标到图像(左,上)到(右,下)像素的

    让我们最后创建场景,加载网格并将纹理添加到其材质:

    @Override
    public void start(Stage primaryStage) throws Exception {
        Group sceneRoot = new Group();
        Scene scene = new Scene(sceneRoot, 600, 600, true, SceneAntialiasing.BALANCED);
        scene.setFill(Color.BLACK);
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setNearClip(0.1);
        camera.setFarClip(10000.0);
        camera.setTranslateZ(-4);
        scene.setCamera(camera);
    
        IcosahedronMesh mesh = new IcosahedronMesh();
        mesh.setCullFace(CullFace.FRONT);
        PhongMaterial mat = new PhongMaterial();
        mat.setDiffuseMap(new Image(getClass().getResourceAsStream("icosah_net.png")));
        mesh.setMaterial(mat);
        Rotate rotateY = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
        mesh.getTransforms().addAll(new Rotate(30,Rotate.X_AXIS),rotateY);
    
        sceneRoot.getChildren().addAll(mesh, new AmbientLight(Color.WHITE));
    
        primaryStage.setTitle("JavaFX 3D - Icosahedron");
        primaryStage.setScene(scene);
        primaryStage.show();        
    }
    
    这就是它的样子:

    编辑

    现在,如果考虑如何应用纹理,可以使用所需的调色板将图像简化为多个正方形:

    纹理坐标可以真正简化:

    m.getTexCoords().addAll(
            0.1f, 0.5f, // 0 red
            0.3f, 0.5f, // 1 green
            0.5f, 0.5f, // 2 blue
            0.7f, 0.5f, // 3 yellow
            0.9f, 0.5f  // 4 orange
    );
    
    最后,我们必须将这些点映射到我们的脸上。遵循与网络映像相同的模式:

    m.getFaces().addAll(
            1, 0, 11, 0, 7, 0, 
            1, 4, 7, 4, 6, 4, 
            1, 4, 6, 4, 10, 4, 
            1, 2, 10, 2, 3, 2, 
            1, 2, 3, 2, 11, 2,                
            4, 3, 8, 3, 0, 3, 
            5, 3, 4, 3, 0, 3, 
            9, 1, 5, 1, 0, 1, 
            2, 1, 9, 1, 0, 1, 
            8, 0, 2, 0, 0, 0, 
    
            11, 3, 9, 3, 7, 3,
            7, 1, 2, 1, 6, 1, 
            6, 1, 8, 1, 10, 1, 
            10, 0, 4, 0, 3, 0, 
            3, 0, 5, 0, 11, 0,
    
            4, 4, 10, 4, 8, 4, 
            5, 4, 3, 4, 4, 4, 
            9, 2, 11, 2, 5, 2, 
            2, 2, 7, 2, 9, 2, 
            8, 3, 6, 3, 2, 3
    );
    
    现在我们将有一个非常整洁的二十面体,因为我们去掉了图像的边界和糟糕的分辨率:


    这可以扩展到任何三角形网格,也可以使用任何来细化三角形。

    最后一次编辑(使用彩色正方形调色板)确实很有帮助,因为我已经为我的icosphere指定了颜色贴图功能。我会尽快发布我完成的代码,只要我做了更改。谢谢是的,当然,因为提供完整的图像可能非常困难。使用颜色映射功能,您无论如何都需要创建一个小图像,但您可以在运行时使用
    Snapshot
    !。顺便说一句,我也做了…的算法,有没有一种方法可以让我不用写一个图像文件到磁盘(或外部设备)来使用纹理?换句话说:我可以使用特定的纹理而不必使用图像吗?由于我的颜色映射将在运行时更改,我不希望每次运行时都必须写入磁盘。此外,对于使用我的应用程序的人来说,这可能是一个安全问题(写入磁盘)@JoseI已经发布了在F(X)yz库中创建icosphere和调色板的所有代码。@AlvaroIzParrilla同时,您是否找到了不写入磁盘的解决方案?