javafx3dpainttexture-mappingjavafx-3d

Painting difuse texture in javafx?


Is there a way to paint a 3d texture on a 3d surface like blender ?


Solution

  • Painting a texture in 3d scene

    painting javafx 3d texture

    getPickResult().getIntersectedTexCoord() from mouseEvent will return a point2d wich is an uv coordinate (from 0 to 1 ). In order to map it to the image pixels ; we have to multilpy u & v by image height and width (800 in this case). Once we have pixel coordinates we can paint with pixelWriter.setPixels() method . the third and fourth arguments in setPixel corresponding to the rectangle that is used to draw , in this case is a 12*12 square . Therefore , an argb array 144 length is needed to fill the square in setPixels with color values given by colorpicker result . ImageView and DifuseMap share the same WritableImage that is why painting the Shape3d will update image in imageView as well

    This is a single class javafx functional app you can try . you can rotate with right mouse button and painting with left button

    public class App extends Application {
    
        private boolean paintMode;
        private boolean rotaionMode;
        private double anchorX;
        private final WritableImage writableImage = new WritableImage(800, 800);
        private int[] colorArray;
    
        private PixelWriter pixelWriter = writableImage.getPixelWriter();
    
        @Override
        public void start(Stage stage) {
    
            // this loop will paint all writableImage object pixel with Color.WHEAT
            for (int i = 0; i < 800; i++) {
    
                for (int j = 0; j < 800; j++) {
                    pixelWriter.setColor(i, j, Color.WHEAT);
    
                }
            }
            //  giving a starting value to colorPicker
            ColorPicker picker = new ColorPicker(Color.AQUAMARINE);
    
            // giving initial valuest to colorArray
            colorArray = getColorArray(picker.getValue());
    
            picker.setOnAction(e -> colorArray = getColorArray(picker.getValue()));
    
            PerspectiveCamera camera = new PerspectiveCamera(true);
            camera.setTranslateZ(-30);
            Shape3D sphere = new Sphere(6);
            PhongMaterial material = new PhongMaterial();
            material.setDiffuseMap(writableImage);
            material.setDiffuseColor(Color.CORAL);
            sphere.setMaterial(material);
    
            sphere.setOnMousePressed(e -> {
                if (e.isSecondaryButtonDown()) {
                    anchorX = e.getSceneX();
    
                }
                rotaionMode = e.isSecondaryButtonDown();
                paintMode = e.isPrimaryButtonDown();
    
            });
    
            sphere.setOnMouseDragged(e -> {
                // painting if primary button is pressed 
                Point2D intersectedTexCoord = e.getPickResult().getIntersectedTexCoord();
                if (paintMode && intersectedTexCoord != null) {
                    // uv cordinates to writableImage x y indices 
                    int x = (int) (intersectedTexCoord.getX() * 800);
                    int y = (int) (intersectedTexCoord.getY() * 800);
    
                    // the rectangle of pixelWritter is 12*12 therefore an array 144 length of argb is needed 
                    pixelWriter.setPixels(x, y, 12, 12, PixelFormat.getIntArgbInstance(), colorArray, 0, 0);
    
                }
                // rotate if secondary button is pressred
                if (rotaionMode) {
    
                    sphere.setRotationAxis(Rotate.Y_AXIS);
    
                    sphere.setRotate(sphere.getRotate() + (e.getSceneX() - anchorX) * -0.05);
    
                }
    
            });
    
            // writableImage in imageView and difuseMap 
            ImageView imageView = new ImageView(writableImage);
            imageView.setFitHeight(300);
            imageView.setFitWidth(300);
    
            Group group = new Group(camera, sphere);
            SubScene subScene = new SubScene(group, 300, 300, true, SceneAntialiasing.BALANCED);
            subScene.setFill(Color.AQUAMARINE);
            subScene.setCamera(camera);
            HBox hBox = new HBox(picker, subScene, imageView);
            hBox.setAlignment(Pos.CENTER);
            hBox.setSpacing(30);
            Scene scene = new Scene(hBox, 800, 600);
            stage.setTitle("painting 3d texture");
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch();
        }
    
        public int[] getColorArray(Color color) {
            // get color values in doubles
            double alphaD = color.getOpacity();
            double redD = color.getRed();
            double greenD = color.getGreen();
            double blueD = color.getBlue();
    
            // double to int
            int alpha = (int) Math.round(255 * alphaD);
            int red = (int) Math.round(255 * redD);
            int green = (int) Math.round(255 * greenD);
            int blue = (int) Math.round(255 * blueD);
    
            // shifting int on hex
            alpha = (alpha << 24) & 0xFF000000;
            red = (red << 16) & 0x00FF0000;
            green = (green << 8) & 0x0000FF00;
            blue = blue & 0x000000FF;
    
            // argb value
            int argb = alpha | red | green | blue;
    
            // the rectangle of pixelWritter is 12*12 therefore an array 144 length of argb is needed 
            int[] colors = new int[144];
    
            for (int i = 0; i < colors.length; i++) {
    
                colors[i] = argb;
    
            }
    
            return colors;
        }
    }