Why doesn't the diffuse map apply to my MeshView?

Problem

I would like to apply a diffuse map to a MeshView. When I apply diffuse map material to a MeshView, it is not displayed. However, the same material applies to the box.

Question

What do I need to do to apply a diffuse map to a MeshView?

the code

The code generates an image with random noise. The image is used as a diffuse map in PhongMaterial. The image is displayed above it with a box with the applied material and above the MeshView box (pyramid) with the applied material. Material is not visible on the pyramid. You can use drag and drop to rotate.

import java.util.Random; import javafx.application.Application; import javafx.geometry.Point3D; import javafx.scene.Group; import javafx.scene.PerspectiveCamera; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.Box; import javafx.scene.shape.DrawMode; import javafx.scene.shape.MeshView; import javafx.scene.shape.TriangleMesh; import javafx.scene.transform.Rotate; import javafx.stage.Stage; public class Test extends Application { private double mousePosX, mousePosY; private double mouseOldX, mouseOldY; private final Rotate rotateX = new Rotate(20, Rotate.X_AXIS); private final Rotate rotateY = new Rotate(-45, Rotate.Y_AXIS); @Override public void start(Stage primaryStage) { // cube Group group = new Group(); // size of the cube double size = 400; group.getTransforms().addAll(rotateX, rotateY); Image diffuseMap = createImage( size); // show noise image ImageView iv = new ImageView( diffuseMap); iv.setTranslateX(-0.5*size); iv.setTranslateY(-0.20*size); iv.setRotate(90); iv.setRotationAxis(new Point3D(1,0,0)); group.getChildren().add( iv); // create material out of the noise image PhongMaterial material = new PhongMaterial(); material.setDiffuseMap(diffuseMap); // create box with noise diffuse map Box box = new Box( 100,100,100); box.setMaterial(material); group.getChildren().add( box); // create pyramid with diffuse map float h = 150; // Height float s = 150; // Side TriangleMesh pyramidMesh = new TriangleMesh(); pyramidMesh.getTexCoords().addAll(1,1,1,0,0,1,0,0); pyramidMesh.getPoints().addAll( 0, 0, 0, // Point 0 - Top 0, h, -s/2, // Point 1 - Front -s/2, h, 0, // Point 2 - Left s/2, h, 0, // Point 3 - Back 0, h, s/2 // Point 4 - Right ); pyramidMesh.getFaces().addAll( 0,0, 2,0, 1,0, // Front left face 0,0, 1,0, 3,0, // Front right face 0,0, 3,0, 4,0, // Back right face 0,0, 4,0, 2,0, // Back left face 4,0, 1,0, 2,0, // Bottom rear face 4,0, 3,0, 1,0 // Bottom front face ); MeshView pyramid = new MeshView(pyramidMesh); pyramid.setDrawMode(DrawMode.FILL); pyramid.setTranslateY(-250); // apply material // TODO: why is the diffuse map not displayed? pyramid.setMaterial(material); group.getChildren().add(pyramid); // scene StackPane root = new StackPane(); root.getChildren().add(group); Scene scene = new Scene(root, 1600, 900, true, SceneAntialiasing.BALANCED); scene.setCamera(new PerspectiveCamera()); // interaction listeners scene.setOnMousePressed(me -> { mouseOldX = me.getSceneX(); mouseOldY = me.getSceneY(); }); scene.setOnMouseDragged(me -> { mousePosX = me.getSceneX(); mousePosY = me.getSceneY(); rotateX.setAngle(rotateX.getAngle()-(mousePosY - mouseOldY)); rotateY.setAngle(rotateY.getAngle()+(mousePosX - mouseOldX)); mouseOldX = mousePosX; mouseOldY = mousePosY; }); primaryStage.setResizable(false); primaryStage.setScene(scene); primaryStage.show(); } /** * Create image with random noise */ public Image createImage( double size) { Random rnd = new Random(); int width = (int) size; int height = (int) size; WritableImage wr = new WritableImage(width, height); PixelWriter pw = wr.getPixelWriter(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Color color = Color.rgb(rnd.nextInt( 256), rnd.nextInt( 256), rnd.nextInt( 256)); pw.setColor(x, y, color); } } return wr; } public static void main(String[] args) { launch(args); } } 

Screenshot

enter image description here

Thank you for help!

+1
javafx javafx-3d
source share
1 answer

Problem

This form consists of 6 separate figures. Four triangles meet at point A. And the rectangle below, because these are triangles, you need two triangles to create a rectangle. The following figure shows a top view of this form.

topview

As you can see, we have 5 points. Therefore, they must be added to the points of the TriangleMesh. One point consists of a teapel of three float values ​​(x, y, z). Thus, this array always consists of sizes 3, 6, 9, ..., 15, etc.

Textures

If you have an image as the material of your grid (like you), you need to get the coordinates of the texture and add the coordinates of the images to them. But what have you added here? These are the 2D coordinates of your image that you want to set as material. It starts with (0.0, 0.0) (u0, v0) and rises to (1.0, 1.0) (u1, v1). This is the 2D coordination of the part of the image that you want to display on your 3D grid. Since you only have a noisy image, you can do from 0.0 to 1.1, but you need 3 points for the triangle.

Facing

Now you need to make the lining. This is similar to the fact that you want to place some plates in the space between the lines of your shape. As you have already seen, you must add four parts for the triangles and two parts for the bottom.

The face is a tuple of six values. Since we draw triangles, it is always something like: from a point, point, point. Thus, a tuple consists of 6 values. p0, t0, p1, t1, p2, t2. These values ​​are indices for points and texture arrays. p0 points to the first tuple of the point array tree, t0 points to the first two sets of texture coordinates array.

(counter) clockwise

My explanation may not be entirely correct, but here is how I understood it:

The JavaFX camera by default works counterclockwise, so if you place faces counterclockwise, your faces will be visible to the camera. Individuals do not access, this is done internally in JavaFX for performance issues. The reverse face will not be displayed by any material unless you set the reject back.

To view the bottom of this triangle, the camera must change its perspective, so it is clockwise. And again the same thing with a face in front and behind.

In your example, I named the points, because now you can see which faces I displayed first and which finally. For example:

ABC is the first person for me, it is the triangle between points A, B and C. These points get their texture from the image coordinates of the material.

For more details, see the blog post by Jose Pereda: http://jperedadnr.blogspot.de/2015/01/creating-and-texturing-javafx-3d-shapes.html

I hope you understand everything, and then below you will find my solution.

Decision

 import java.util.Random; import javafx.application.Application; import javafx.geometry.Point3D; import javafx.scene.Group; import javafx.scene.PerspectiveCamera; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.Box; import javafx.scene.shape.DrawMode; import javafx.scene.shape.MeshView; import javafx.scene.shape.TriangleMesh; import javafx.scene.transform.Rotate; import javafx.stage.Stage; public class Test extends Application { private double mousePosX, mousePosY; private double mouseOldX, mouseOldY; private final Rotate rotateX = new Rotate(20, Rotate.X_AXIS); private final Rotate rotateY = new Rotate(-45, Rotate.Y_AXIS); @Override public void start(Stage primaryStage) { // cube Group group = new Group(); // size of the cube double size = 400; group.getTransforms().addAll(rotateX, rotateY); Image diffuseMap = createImage(size); // show noise image ImageView iv = new ImageView(diffuseMap); iv.setTranslateX(-0.5 * size); iv.setTranslateY(-0.20 * size); iv.setRotate(90); iv.setRotationAxis(new Point3D(1, 0, 0)); group.getChildren().add(iv); // create material out of the noise image PhongMaterial material = new PhongMaterial(); material.setDiffuseMap(diffuseMap); // create box with noise diffuse map Box box = new Box(100, 100, 100); box.setMaterial(material); group.getChildren().add(box); // create pyramid with diffuse map float h = 150; // Height float s = 150; // Side float hs = s / 2; // coordinates of the mapped image float x0 = 0.0f; float y0 = 0.0f; float x1 = 1.0f; float y1 = 1.0f; TriangleMesh pyramidMesh = new TriangleMesh(); pyramidMesh.getPoints().addAll( // 0.0f, 0.0f, 0.0f, // A 0 Top of Pyramid hs, h, -hs, // B 1 hs, h, hs, // C 2 -hs, h, hs, // D 3 -hs, h, -hs // E 4 ); pyramidMesh.getTexCoords().addAll( // x0, y0, // 0 x0, y1, // 1 x1, y0, // 2 x1, y1 // 3 ); pyramidMesh.getFaces().addAll(// index of point, index of texture, index of point, index of texture, index of point, index of texture 0, 0, 1, 1, 2, 3, // ABC (counter clockwise) 0, 0, 2, 1, 3, 3, // ACD (counter clockwise) 0, 0, 3, 1, 4, 3, // ADE (counter clockwise) 0, 0, 4, 1, 1, 3, // AEB (counter clockwise) 4, 0, 3, 1, 2, 3, // EDC (Bottom first triangle clock wise) 2, 0, 1, 1, 4, 3 // CBE (Bottom second triangle clock wise) ); MeshView pyramid = new MeshView(); pyramid.setMesh(pyramidMesh); pyramid.setDrawMode(DrawMode.FILL); pyramid.setTranslateY(-250); // apply material // TODO: why is the diffuse map not displayed? pyramid.setMaterial(material); group.getChildren().add(pyramid); // scene StackPane root = new StackPane(); root.getChildren().add(group); Scene scene = new Scene(root, 1600, 900, true, SceneAntialiasing.BALANCED); scene.setCamera(new PerspectiveCamera()); // interaction listeners scene.setOnMousePressed(me -> { mouseOldX = me.getSceneX(); mouseOldY = me.getSceneY(); }); scene.setOnMouseDragged(me -> { mousePosX = me.getSceneX(); mousePosY = me.getSceneY(); rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY)); rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX)); mouseOldX = mousePosX; mouseOldY = mousePosY; }); primaryStage.setResizable(false); primaryStage.setScene(scene); primaryStage.show(); } /** * Create image with random noise */ public Image createImage(double size) { Random rnd = new Random(); int width = (int) size; int height = (int) size; WritableImage wr = new WritableImage(width, height); PixelWriter pw = wr.getPixelWriter(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Color color = Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)); pw.setColor(x, y, color); } } return wr; } public static void main(String[] args) { launch(args); } } 

enter image description here

+4
source share

All Articles