使用三角形网格纹理而无需读/写图像文件 [英] Using texture for triangle mesh without having to read/write an image file

查看:192
本文介绍了使用三角形网格纹理而无需读/写图像文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是对上一个问题的跟进(参见在javafx上的三角形网格中着色单个三角形)我认为这是另一个话题。



有没有办法(使用javafx)我可以远离必须实际写入磁盘(或外部设备)的图像文件以使用纹理?



换句话说:我可以使用特定的纹理而不必使用Image吗?



由于我的色彩映射会在运行时发生变化,所以每次运行时我都不想写入磁盘。此外,对于使用我的应用程序的人来说,这可能是一个安全问题(写入磁盘)。(使用javafx)

解决方案

As @ Jens-Peter-Haack建议,使用 Snapshot ,您可以创建所需的任何图像,然后将此图像应用为扩散贴图。为此,您需要创建一些节点,用您需要的颜色填充它们,将它们分组在一个容器中然后拍摄快照。



这是一种直接的方法,你可以使用 PixelWriter 建立一个带有颜色图案的图像。



假设你想要256种颜色,此方法将返回256像素的图像,其中每个像素具有这些颜色中的一种。为简单起见,我添加了两种构建调色板的简单方法。

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

//保存用于测试目的
try {
ImageIO.write(SwingFXUtils.fromFXImage(img,null),jpg,new File(palette.jpg) );
} catch(IOException ex){}
return img;
}

private Color getColor(int iColor,int numColors){
//漂亮的颜色调色板
java.awt.Color c = java.awt.Color .getHSBColor((float)iColor /(float)numColors,1.0f,1.0f);
返回Color.rgb(c.getRed(),c.getGreen(),c.getBlue());

//原始调色板
//返回Color.rgb((iColor>> 16)& 0xFF,(iColor>> 8)& 0xFF,iColor&为0xFF);
}

获得图像对象后,可以设置漫反射贴图:

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

但您仍需要为新纹理提供正确的映射。



为此你需要将网格的顶点映射到图像中的一个像素。



首先,我们需要一种方法来在网格上用纹理坐标映射颜色。此方法将返回给定颜色索引的一对坐标:

  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;
返回new float [] {(((float)x)/((float)width)),(((float)y)/((float)height))};
}

最后,我们将这些纹理添加到 m.getTextCoords ()和面 m.getFaces(),如图所示此处



如果我们为二十面体中的每个顶点指定颜色,我们从所有调色板中选择一种颜色(根据颜色和顶点的数量向上或向下缩放),然后设置每个面为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,1
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
);

这将给我们这样的东西:





编辑



使用纹理坐标,而不是使用颜色映射节点,您可以添加一些功能并轻松创建等高线图,如下所示: / p>


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)

解决方案

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:

这篇关于使用三角形网格纹理而无需读/写图像文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆