如何在JavaFX中为3D Box设置LinearGradient

时间:2019-07-15 18:32:14

标签: java javafx 3d javafx-3d

我已经找到了类似的答案,但解决方案专用于该领域。无论如何,我尝试了,当然这不是我期望的。

我使用的代码是:

Scene aux2 = new Scene(new StackPane(), 100, 100,
                new LinearGradient(0, 0, 1, 0, true, CycleMethod.REFLECT,
                        new Stop(0, Color.GREEN), new Stop(0.3, Color.YELLOW),
                        new Stop(0.6, Color.BLUE), new Stop(0.9, Color.RED)));


        WritableImage snapshot = aux2.snapshot(null);

        PhongMaterial material = new PhongMaterial();
        material.setDiffuseMap(snapshot);

        box.setMaterial(material);

效果在这里:https://imagizer.imageshack.com/img922/589/VEL43d.png

如何在框周围获得相同的填充(椭圆形),并为顶部表面设置渐变的顶部颜色?

1 个答案:

答案 0 :(得分:3)

您提到的球solution不适用于3D盒子,因为内置盒子会将完全相同的漫反射图像应用于盒子的每个平面6个面上。

另外一个solution为3D框使用了自定义网格,因此您可以以不同的方式播放漫反射图像。

我们可以使该解决方案适合您的用例,因为如果我做对了,您希望将线性渐变的同一图像应用到4个垂直面上,同时将边框颜色保留在2个水平面上。 / p>

所以我们需要这样的图像:

Scene aux2 = new Scene(new StackPane(), 10, 100,
            new LinearGradient(0, 1, 0, 0, true, CycleMethod.REFLECT,
                    new Stop(0, Color.GREEN), new Stop(0.3, Color.YELLOW),
                    new Stop(0.6, Color.BLUE), new Stop(0.9, Color.RED)));

WritableImage snapshot = aux2.snapshot(null);
PhongMaterial material = new PhongMaterial(Color.WHITE);
material.setDiffuseMap(snapshot);

请注意,我已经设置了垂直线性渐变。如果渲染该图像,您将得到类似的东西:

现在您需要生成一个长方体网格:

public MeshView createCuboid(float w, float h, float d) {
    float hw = w / 2f;
    float hh = h / 2f;
    float hd = d / 2f;

    float points[] = {
            hw,  hh,  hd,
            hw,  hh, -hd,
            hw, -hh,  hd,
            hw, -hh, -hd,
            -hw,  hh,  hd,
            -hw,  hh, -hd,
            -hw, -hh,  hd,
            -hw, -hh, -hd};

    float tex[] = {
            0.01f, 0.01f,
            0.01f, 0.99f};

    float normals[] = {
            1f,  0f,  0f,
            -1f,  0f,  0f,
            0f,  1f,  0f,
            0f, -1f,  0f,
            0f,  0f,  1f,
            0f,  0f, -1f,
    };

    int faces[] = {
            0, 0, 0, 2, 0, 1, 1, 0, 0,
            2, 0, 1, 3, 0, 1, 1, 0, 0,
            4, 1, 0, 5, 1, 0, 6, 1, 1,
            6, 1, 1, 5, 1, 0, 7, 1, 1,
            0, 2, 0, 1, 2, 0, 4, 2, 0,
            4, 2, 0, 1, 2, 0, 5, 2, 0,
            2, 3, 1, 6, 3, 1, 3, 3, 1,
            3, 3, 1, 6, 3, 1, 7, 3, 1,
            0, 4, 0, 4, 4, 0, 2, 4, 1,
            2, 4, 1, 4, 4, 0, 6, 4, 1,
            1, 5, 0, 3, 5, 1, 5, 5, 0,
            5, 5, 0, 3, 5, 1, 7, 5, 1};

    TriangleMesh mesh = new TriangleMesh();
    mesh.setVertexFormat(VertexFormat.POINT_NORMAL_TEXCOORD);
    mesh.getPoints().addAll(points);
    mesh.getTexCoords().addAll(tex);
    mesh.getNormals().addAll(normals);
    mesh.getFaces().addAll(faces);

    return new MeshView(mesh);
}

如果检查纹理坐标,我只选择了两对坐标,一个在扩散图像的底部,一个在顶部。 JavaFX将完成其余工作,以内插给定图像中的每个像素。我没有选择边框以防止图像边框处出现不同颜色的任何问题。

faces数组会为每个三角形(最多12个)列出三个顶点,三个法线和三个纹理坐标的索引。

例如,第一个三角形的顶点索引为0、2、1,每个顶点的法线为0,纹理索引为0、1、0(底部-顶部-底部)。下一个三角形具有索引2、3、1,相同的法线0和纹理索引1、1、0(顶部-顶部-底部)。请注意,底部为红色,顶部为绿色(Y坐标从图像的左上角向下)。

索引为4、5的面的纹理索引为0、0、0,因此它们将在底部,而索引面6、7的面的索引为1、1、1,因此它们将在顶部。

所以现在我们需要的是:

MeshView mv = createCuboid(10, 100, 10);
mv.setMaterial(material);
Group cuboidGroup = new Group(mv);
Scene scene = new Scene(cuboidGroup, 400, 600, true, SceneAntialiasing.BALANCED);

结果类似:

希望这是您想要的结果。否则,您可以使用渐变和网格来实现它。