I'm working now with javafx to build a maze and I want the walls to be textured with some seamless texture (that can be repeated). The maze is randomly generated so I don't know the size of any walls. I started by using a PhongMaterial with the desired texture, but it expand the image to fill the whole wall (a Box), so my texture is totally stretched. Is there any way to force the Material to replicate the texture as needed ?
The code is like:
Image img = new Image(new FileInputStream("img.jpg"), 400, 400, true, false);
Material mat = new PhongMaterial(Color.WHITE, img, null, null, null);
Box w = new Box(100,10,10);
w.setMaterial(mat);
Something like an ImagePattern seems a good idea, but there is no Material that accept it.
Thanks in advance for any help
As @fabian mentioned, Box
is not suitable for customizing the texture. By default the image you set as diffuse map will be applied for each of its six faces, and, as you already discovered, this means that it will stretch the image to accommodate the different sides.
Using the FXyz library, we can easily try the Carbon-Kevlar pattern. But obviously we have to select a size for it. Like 100 x 30
.
@Override
public void start(Stage primaryStage) {
Box box = new Box(100, 30, 50);
PhongMaterial material = new PhongMaterial();
Patterns pattern = new Patterns(100, 30);
material.setDiffuseMap(pattern.createPattern(Patterns.CarbonPatterns.CARBON_KEVLAR, false));
box.setMaterial(material);
Scene scene = new Scene(new Group(box), 500, 400, true, SceneAntialiasing.BALANCED);
primaryStage.setScene(scene);
primaryStage.show();
}
While the texture fits perfectly fine the front face with dimensions 100x30, this image is distorted to fit in the same way the other faces 50x50 and 100x50.
Solution 1
We can try to generate our own Box, so we can decide how to apply the diffuse map.
Creating a TriangleMesh
for a cuboid is easy in terms of vertices and faces or normals.
The tricky part is setting the texture coordinates. In the following snippet I set them based on one of the different possible 2D net images of the 3D cuboid:
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 L = 2 * w + 2 * d;
float H = h + 2 * d;
float tex[] = {
d / L, 0f,
(d + w) / L, 0f,
0f, d / H,
d / L, d / H,
(d + w) / L, d / H,
(2 * d + w) / L, d / H,
1f, d / H,
0f, (d + h) / H,
d / L, (d + h) / H,
(d + w) / L, (d + h) / H,
(2 *d + w) / L, (d + h) / H,
1f, (d + h) / H,
d / L, 1f,
(d + w) / L, 1f};
float normals[] = {
1f, 0f, 0f,
-1f, 0f, 0f,
0f, 1f, 0f,
0f, -1f, 0f,
0f, 0f, 1f,
0f, 0f, -1f,
};
int faces[] = {
0, 0, 10, 2, 0, 5, 1, 0, 9,
2, 0, 5, 3, 0, 4, 1, 0, 9,
4, 1, 7, 5, 1, 8, 6, 1, 2,
6, 1, 2, 5, 1, 8, 7, 1, 3,
0, 2, 13, 1, 2, 9, 4, 2, 12,
4, 2, 12, 1, 2, 9, 5, 2, 8,
2, 3, 1, 6, 3, 0, 3, 3, 4,
3, 3, 4, 6, 3, 0, 7, 3, 3,
0, 4, 10, 4, 4, 11, 2, 4, 5,
2, 4, 5, 4, 4, 11, 6, 4, 6,
1, 5, 9, 3, 5, 4, 5, 5, 8,
5, 5, 8, 3, 5, 4, 7, 5, 3};
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);
}
Now we can generate the image, but using the net dimensions:
@Override
public void start(Stage primaryStage) {
MeshView box = createCuboid(100, 30, 50);
PhongMaterial material = new PhongMaterial();
Patterns pattern = new Patterns(300, 160);
material.setDiffuseMap(pattern.createPattern(Patterns.CarbonPatterns.CARBON_KEVLAR, false));
box.setMaterial(material);
box.getTransforms().addAll(rotateX, rotateY);
Scene scene = new Scene(new Group(box), 500, 400, true, SceneAntialiasing.BALANCED);
primaryStage.setScene(scene);
primaryStage.show();
}
Note that the image is not distorted anymore.
You can play with its size to get a more fine or dense pattern (with a bigger image pattern).
Note that you can find this Cuboid primitive in the FXyz library, among many other 3D primitives.
Also you can find different texture modes (density maps, images, patterns...)