Search code examples
c#wpf3d

Rotating my My Model3D Object changes how it is scaled making it confusing for users


I have code to rotate and scale my model below.

My problem is after I rotate the model if I go to change the width height or depth depending on how my model was rotated it does not work as expected. For example if model was laying back and flipped upright then the height and depth know work as the other essnetially. This becomes a problem for me because I intend on letting the user edit the scale and rotation after I or an admin user does the initial proccessing. So my question is is there any way to keep it intuitive or create a copy that acts like it was never rotated or something of that order? Any pointers would be much appreciated.

My Current Code

    private void ApplyScalingAndRotation(Model3D model, double width, double height, double depth, double xRot, double yRot, double zRot)
    {
        // Retrieve the bounds of the model
        var bounds = model.Bounds;

        // Calculate the center point of the model
        var modelCenter = new Point3D(
            bounds.X + bounds.SizeX / 2,
            bounds.Y + bounds.SizeY / 2,
            bounds.Z + bounds.SizeZ / 2
        );

        // Original dimensions of the model
        double originalWidth = bounds.SizeX;
        double originalHeight = bounds.SizeY;
        double originalDepth = bounds.SizeZ;

        // Calculate scaling factors for each dimension
        double widthScaleFactor = width / originalWidth;
        double heightScaleFactor = height / originalHeight;
        double depthScaleFactor = depth / originalDepth;

        // Create a scale transformation without any rotation
        ScaleTransform3D scaleTransform = new ScaleTransform3D(
            widthScaleFactor, heightScaleFactor, depthScaleFactor,
            modelCenter.X, modelCenter.Y, modelCenter.Z
        );

        // Convert degrees to radians for rotation
        double rotationXDegrees = xRot;
        double rotationYDegrees = yRot;
        double rotationZDegrees = zRot;

        // Create rotation transformations
        RotateTransform3D rotateXTransform = new RotateTransform3D(new AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(1, 0, 0), rotationXDegrees));
        RotateTransform3D rotateYTransform = new RotateTransform3D(new AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(0, 1, 0), rotationYDegrees));
        RotateTransform3D rotateZTransform = new RotateTransform3D(new AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(0, 0, 1), rotationZDegrees));

        // Combine the rotation transformations into one Transform3DGroup
        Transform3DGroup rotationGroup = new Transform3DGroup();
        rotationGroup.Children.Add(rotateXTransform);
        rotationGroup.Children.Add(rotateYTransform);
        rotationGroup.Children.Add(rotateZTransform);

        // Combine the scale and rotation transformations into one Transform3DGroup
        Transform3DGroup combinedTransform = new Transform3DGroup();
        combinedTransform.Children.Add(scaleTransform);
        combinedTransform.Children.Add(rotationGroup);

        // Apply the combined transformation to the model
        model.Transform = combinedTransform;

    }

Solution

  • I ended up wrapping each one with model I want to rotate with another Model3DGroup and rotating that. That solves my problem.

        private void ApplyScalingAndRotation(Model3D model, double width, double height, double depth, double xRot, double yRot, double zRot)
        {
            var model3DGroup = new Model3DGroup();
    
    
            //This should hopefully make it start in the back left corner
            TranslateTransform3D translation = new TranslateTransform3D(-0.5, -0.5, -0.5);
    
            // Apply the new translation transformation to the model
            model3DGroup.Transform = translation;
    
            model3DGroup.Children.Add(model);
    
            // Retrieve the bounds of the model
            var bounds = model3DGroup.Bounds;
    
            //Calculate the center point of the model
            var modelCenter = new Point3D(
                bounds.X + bounds.SizeX / 2,
                bounds.Y + bounds.SizeY / 2,
                bounds.Z + bounds.SizeZ / 2
            );
    
            // Original dimensions of the model
            double originalWidth = bounds.SizeX;
            double originalHeight = bounds.SizeY;
            double originalDepth = bounds.SizeZ;
    
            // Calculate scaling factors for each dimension
            double widthScaleFactor = width / originalWidth;
            double heightScaleFactor = height / originalHeight;
            double depthScaleFactor = depth / originalDepth;
    
            // Create a scale transformation without any rotation
            ScaleTransform3D scaleTransform = new ScaleTransform3D(
                widthScaleFactor, heightScaleFactor, depthScaleFactor,
                modelCenter.X, modelCenter.Y, modelCenter.Z
            );
    
            // Create rotation transformations
            RotateTransform3D rotateXTransform = new RotateTransform3D(new AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(1, 0, 0), xRot));
            RotateTransform3D rotateYTransform = new RotateTransform3D(new AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(0, 1, 0), yRot));
            RotateTransform3D rotateZTransform = new RotateTransform3D(new AxisAngleRotation3D(new System.Windows.Media.Media3D.Vector3D(0, 0, 1), zRot));
    
            // Combine the rotation transformations into one Transform3DGroup
            Transform3DGroup rotationGroup = new Transform3DGroup();
            rotationGroup.Children.Add(rotateXTransform);
            rotationGroup.Children.Add(rotateYTransform);
            rotationGroup.Children.Add(rotateZTransform);
    
            // Combine the scale and rotation transformations into one Transform3DGroup
            Transform3DGroup combinedTransform = new Transform3DGroup();
            combinedTransform.Children.Add(scaleTransform);
            combinedTransform.Children.Add(rotationGroup);
    
            // Apply the combined transformation to the model
            model3DGroup.Transform = combinedTransform;
    
            ContentVisual.Content = model3DGroup;
    
    
            //So it is a model 3d group
    
    
            //Change camera not sure we need this.
    
            bounds = model.Bounds;
    
            modelCenter = new Point3D(bounds.X + bounds.SizeX / 2,
                bounds.Y + bounds.SizeY / 2,
                bounds.Z + bounds.SizeZ / 2);
    
            var modelSize = Math.Sqrt(bounds.SizeX * bounds.SizeX +
                                      bounds.SizeY * bounds.SizeY +
                                      bounds.SizeZ * bounds.SizeZ);
    
    
            Camera1.TargetPosition = modelCenter;
            Camera1.Distance = modelSize * 2;
    
        }