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

This is a continuation of the previous question (see Coloring individual triangles in a triangular grid 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 write an image file to disk (or an external device) to use the texture?

In other words: can I use a specific texture without using an image?

Since my color map will change at runtime, I donโ€™t want to write to disk every time I run it. Also, it could be a security issue (burning to disk) for someone using my application. (With javafx)

+1
source share
2 answers

As @ Jens-Peter-Haack shows, with Snapshot you can create any image you want and then apply this image as a diffusion map. To do this, you need to create several nodes, fill them with the required colors, group them in some container, and then take a picture.

There is a direct approach where you can create an image with a picture of colors using PixelWriter .

Say you want 256 colors, this method will return an image with 256 pixels, where each pixel has one of these colors. For simplicity, I added two simple ways to create 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); } 

When you have an image object, you can install a diffuse map:

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

But you still need to ensure that the new texture is displayed correctly.

To do this, you need to match the vertices of the grid with a pixel in the image.

First, we need a way to map the colors to the texture coordinates on the grid. 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 of m.getFaces() , as shown here .

If we assign a color to each vertex in our icosahedron, we select a color from the entire palette (scaling up or down in the number of colors and vertices), and then set each 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:

enter image description here

EDIT

When playing with texture coordinates, instead of displaying a node with color, you can add some function and easily create a contour graph, for example:

enter image description here

+1
source

You can create a texture that will be used for filling, etc. in your code using any graphic object and convert it to an image in memory without touching the disk.

The following example creates 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; } 

enter image description here

+2
source

All Articles