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

时间:2014-11-09 18:43:21

标签: colors javafx geometry mesh javafx-3d

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

  1. 三角形网格的单个三角形
    1. 对每个三角形的各个顶点进行着色,并根据每个顶点颜色的插值对三角形进行着色(例如使用Gouraud着色)。
    2. 特定的三角形网格物体是一个拥有数百万个面孔的icosphere(这就是我使用三角形网格的原因:我需要速度)。

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

1 个答案:

答案 0 :(得分:11)

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

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

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

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

为此,我们需要:

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

    公共类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;
    }
    

    }

现在我们需要一张带有每张脸颜色的图像,基于二十面体的网络,如下所示:

Net of an icosahedron

(图片找到here

请注意,映射是从(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();        
}

这就是它的样子:

Icosahedron

修改

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

Palette of colors

纹理坐标可以真正简化:

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
);

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

Improved icosahedron

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