Using texture for triangle mesh without having to read/write an image file

淺唱寂寞╮ 提交于 2019-12-02 01:59:50

问题


This is a followup on a previous question (see Coloring individual triangles in a triangle mesh on javafx) which I believe is another topic on its own.

Is there a way (with javafx) that I can get away from having to actually write to disk (or external device) an image file to use a texture?

In other words: can I use a specific texture without having to use Image?

Since my color map will change on runtime I don't want to have to write to disk every time I run it. Also, this might be a security issue (writing to disk) for someone using my app.(with javafx)


回答1:


As @Jens-Peter-Haack suggest, with Snapshot you can create any image you want, and then apply this image as the diffusion map. For that, you need to create some nodes, fill them with the colors you require, group them in some container and then take the snapshot.

There's a straight-in approach, where you can build an image with a pattern of colors using PixelWriter.

Let's say you want 256 colors, this method will return an image of 256 pixels, where each pixel has one of these colors. For simplicity I've added two simple ways of building a palette.

public static Image colorPallete(int numColors){
    int width=(int)Math.sqrt(numColors);
    int height=numColors/width;

    WritableImage img = new WritableImage(width, height);
    PixelWriter   pw  = img.getPixelWriter();
    AtomicInteger count = new AtomicInteger();
    IntStream.range(0, height).boxed()
            .forEach(y->IntStream.range(0, width).boxed()
                    .forEach(x->pw.setColor(x, y, getColor(count.getAndIncrement(),numColors))));

    // save for testing purposes
    try {            
        ImageIO.write(SwingFXUtils.fromFXImage(img, null), "jpg", new File("palette.jpg"));
    } catch (IOException ex) { }
    return img;
}

private Color getColor(int iColor, int numColors){
    // nice palette of colors 
    java.awt.Color c = java.awt.Color.getHSBColor((float) iColor / (float) numColors, 1.0f, 1.0f);
    return Color.rgb(c.getRed(), c.getGreen(), c.getBlue());

    // raw palette
    //return Color.rgb((iColor >> 16) & 0xFF, (iColor >> 8) & 0xFF, iColor & 0xFF);
}

Once you have the image object, you can set the diffuse map:

IcosahedronMesh mesh = new IcosahedronMesh();
PhongMaterial mat = new PhongMaterial();
mat.setDiffuseMap(colorPallete(256));
mesh.setMaterial(mat);

But you still have to provide the proper mapping to the new texture.

For this you need to map the vertices of the mesh to a pixel in the image.

First, we need a way to map colors with texture coordinates on the mesh. This method will return a pair of coordinates for a given color index:

public static float[] getTextureLocation(int iPoint, int numColors){
    int width=(int)Math.sqrt(numColors);
    int height=numColors/width;
    int y = iPoint/width; 
    int x = iPoint-width*y;
    return new float[]{(((float)x)/((float)width)),(((float)y)/((float)height))};
}

Finally, we add these textures to m.getTextCoords() and to the faces m.getFaces(), as shown here.

If we assign a color to every vertex in our icosahedron we pick a color from all the palette (scaling up or down according the number of colors and vertices), and then set every face with t0=p0, t1=p1, t2=p2:

IntStream.range(0,numVertices).boxed()
    .forEach(i->m.getTexCoords()
                 .addAll(getTextureLocation(i*numColors/numVertices,numColors)));

m.getFaces().addAll(
            1, 1, 11, 11, 7, 7, 
            1, 1, 7, 7, 6, 6, 
            1, 1, 6, 6, 10, 10, 
            1, 1, 10, 10, 3, 3, 
            1, 1, 3, 3, 11, 11,
            4, 4, 8, 8, 0, 0, 
            5, 5, 4, 4, 0, 0, 
            9, 9, 5, 5, 0, 0, 
            2, 2, 9, 9, 0, 0, 
            8, 8, 2, 2, 0, 0,
            11, 11, 9, 9, 7, 7,
            7, 7, 2, 2, 6, 6, 
            6, 6, 8, 8, 10, 10, 
            10, 10, 4, 4, 3, 3, 
            3, 3, 5, 5, 11, 11,
            4, 4, 10, 10, 8, 8, 
            5, 5, 3, 3, 4, 4, 
            9, 9, 11, 11, 5, 5, 
            2, 2, 7, 7, 9, 9, 
            8, 8, 6, 6, 2, 2
    );

This will give us something like this:

EDIT

Playing around with the textures coordinates, instead of mapping node with color, you can add some function and easily create a contour plot, like this:




回答2:


You might create the texture to be used for fill etc. in your code by using any graphic object and convert that into an image in memory, not touching disk.

The example below will create a texture using a green spline.

Pane testImage2(Pane pane) {
    Pane inner = new Pane();
    inner.prefWidthProperty().bind(pane.widthProperty());
    inner.prefHeightProperty().bind(pane.heightProperty());
    pane.getChildren().add(inner);

    SVGPath texture = new SVGPath();
    texture.setStroke(Color.GREEN);
    texture.setStrokeWidth(2.5);
    texture.setFill(Color.TRANSPARENT);
    texture.setContent("M 10 10 C 40 10 10 70 70 20");

    SnapshotParameters params = new SnapshotParameters();
    params.setViewport(new Rectangle2D(-5, -5, 70, 50));
    Image image = texture.snapshot(params, null);

    Paint paint = new ImagePattern(image, 5,5, 20, 20, false);
    inner.setBackground(new Background(new BackgroundFill(paint, new CornerRadii(0), new Insets(inset))));
    return pane;
}



来源:https://stackoverflow.com/questions/26881887/using-texture-for-triangle-mesh-without-having-to-read-write-an-image-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!