javafx shape3d 纹理:不要拉伸图像
javafx shape3d texturing: Don't strectch the image
我现在正在使用 javafx 构建一个迷宫,我希望墙壁具有一些无缝纹理(可以重复)。迷宫是随机生成的,所以我不知道任何墙壁的大小。我开始使用 PhongMaterial with the desired texture, but it expand the image to fill the whole wall (a Box),所以我的纹理完全被拉伸了。有没有办法强制 Material 根据需要复制纹理?
代码如下:
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);
ImagePattern 之类的东西似乎是个好主意,但没有 Material 接受它。
在此先感谢您的帮助
如@fabian 所述,Box
不适合自定义纹理。默认情况下,您设置为漫反射贴图的图像将应用于其六个面中的每一个,并且正如您已经发现的那样,这意味着它将拉伸图像以适应不同的面。
使用 FXyz library, we can easily try the Carbon-Kevlar pattern。但显然我们必须 select 一个尺寸。喜欢 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();
}
虽然纹理非常适合尺寸为 100x30 的正面,但此图像会变形以适合其他尺寸为 50x50 和 100x50 的面。
解决方案 1
我们可以尝试生成我们自己的盒子,这样我们就可以决定如何应用漫反射贴图。
根据顶点和面或法线,为长方体创建 TriangleMesh
很容易。
棘手的部分是设置纹理坐标。在下面的片段中,我根据 3D 长方体的不同可能的 2D net 图像之一设置它们:
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);
}
现在我们可以生成图像了,但是使用的是净尺寸:
@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();
}
请注意,图像不再失真。
您可以调整它的大小以获得更精细或更密集的图案(具有更大的图像图案)。
请注意,您可以在 FXyz library 中找到这个长方体图元,以及许多其他 3D 图元。
您还可以找到不同的纹理模式(密度图、图像、图案...)
我现在正在使用 javafx 构建一个迷宫,我希望墙壁具有一些无缝纹理(可以重复)。迷宫是随机生成的,所以我不知道任何墙壁的大小。我开始使用 PhongMaterial with the desired texture, but it expand the image to fill the whole wall (a Box),所以我的纹理完全被拉伸了。有没有办法强制 Material 根据需要复制纹理?
代码如下:
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);
ImagePattern 之类的东西似乎是个好主意,但没有 Material 接受它。
在此先感谢您的帮助
如@fabian 所述,Box
不适合自定义纹理。默认情况下,您设置为漫反射贴图的图像将应用于其六个面中的每一个,并且正如您已经发现的那样,这意味着它将拉伸图像以适应不同的面。
使用 FXyz library, we can easily try the Carbon-Kevlar pattern。但显然我们必须 select 一个尺寸。喜欢 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();
}
虽然纹理非常适合尺寸为 100x30 的正面,但此图像会变形以适合其他尺寸为 50x50 和 100x50 的面。
解决方案 1
我们可以尝试生成我们自己的盒子,这样我们就可以决定如何应用漫反射贴图。
根据顶点和面或法线,为长方体创建 TriangleMesh
很容易。
棘手的部分是设置纹理坐标。在下面的片段中,我根据 3D 长方体的不同可能的 2D net 图像之一设置它们:
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);
}
现在我们可以生成图像了,但是使用的是净尺寸:
@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();
}
请注意,图像不再失真。
您可以调整它的大小以获得更精细或更密集的图案(具有更大的图像图案)。
请注意,您可以在 FXyz library 中找到这个长方体图元,以及许多其他 3D 图元。
您还可以找到不同的纹理模式(密度图、图像、图案...)