【问题标题】:Using texture for triangle mesh without having to read/write an image file将纹理用于三角形网格,无需读取/写入图像文件
【发布时间】:2014-11-12 07:57:20
【问题描述】:

这是对上一个问题(请参阅Coloring individual triangles in a triangle mesh on javafx)的跟进,我认为这本身就是另一个主题。

有没有办法(使用 javafx)让我不必将图像文件实际写入磁盘(或外部设备)以使用纹理?

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

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

【问题讨论】:

    标签: javafx textures texture-mapping


    【解决方案1】:

    正如@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))));
    
        // 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);
    }
    

    一旦有了图像对象,就可以设置漫反射贴图了:

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

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

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

    这会给我们这样的东西:

    编辑

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

    【讨论】:

    • 太棒了!你领先于我,因为我正是使用它在曲面上绘制等高线图。竖起大拇指!
    • 我已经在 F(X)yz 库中发布了创建 icosphere 和等高线图 here 的所有代码。
    【解决方案2】:

    您可以使用任何图形对象在代码中创建用于填充等的纹理,并将其转换为内存中的图像,而不是接触磁盘。

    以下示例将使用绿色样条线创建纹理。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-05
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多