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

Alv*_*lla 6 geometry javafx mesh colors javafx-3d

我在JAVAFX中有一个三角形网格物体,并且想要

  1. 三角形网格的单个三角形颜色

要么

  1. 对每个三角形的各个顶点进行着色,并根据每个顶点的颜色插值(例如,使用Gouraud阴影)对三角形进行着色.

特定的三角形网格物体是一个拥有数百万个面孔的icosphere(这就是我使用三角形网格的原因:我需要速度).

我没有使用纹理坐标,因为我无法使用JAVAFX找到它的明确解释,而且我希望有一种更简单的方法.

Jos*_*eda 11

JavaFX 3D网格中的着色方式取决于您指定的材质.对于一个网格,有一种材质,并且不可能将不同的材料分配到同一网格的不同三角形.

因此,如果你想避免纹理,我担心唯一的方法是在同一个网格中将相同颜色的三角形分组,并创建如此多的网格作为颜色.

相反,纹理相对容易......因为你只有一个网格,一个材质和一个具有所有着色的图像.

我做了一个二十面体的例子,为它构建了一个三角形网格,并添加了一个纹理来为所有面部着色.

为此,我们需要:

  • 12个顶点的3D坐标,
  • 纹理的uv映射的2D标准化坐标.
  • 和20个面孔.每个面由6个索引p0,t0,p1,t1,p3,t3定义,其中p0,p1,p2和p3是点阵列的索引,并且t0,t1,t2和t3是texCoords阵列的索引.

    公共类IcosahedronMesh扩展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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    }

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

二十面体的网

(图片在这里找到)

注意,映射是从(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();        
}
Run Code Online (Sandbox Code Playgroud)

这是它的样子:

二十面体

编辑

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

调色板的颜色

纹理坐标可以真正简化:

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
);
Run Code Online (Sandbox Code Playgroud)

最后,我们必须在我们的脸上映射这些点.遵循与网络图像相同的模式:

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
);
Run Code Online (Sandbox Code Playgroud)

现在我们将拥有一个非常整洁的二十面体,因为我们摆脱了边框和图像分辨率不佳:

改进的二十面体

这可以扩展到任何三角形网格,或使用任何算法来细化三角形.