change the camera field of view dynamically

Eduardo Gomez 4,316 Reputation points
2025-03-25T20:38:29.7266667+00:00

Hello

I am using helix toolkit, to parse and render Gcode (I think I can do this with direct x)

Buen anyway, I have a slider, that supposedly change the field of view (simulating zoom)

but it doesn't want to change anything

    <TextBlock
        Margin="5,5,0,0"
        Text="Field of view" />
    <Slider
        Grid.Column="1"
        Maximum="200"
        Minimum="10"
        Value="{x:Bind _3DViwerViewModel.FieldOfView, Mode=TwoWay}" />
</Grid>


<hx:Viewport3DX
    Grid.Row="1"
    Grid.Column="1"
    BackgroundColor="#89FFFFFF"
    Camera="{x:Bind _3DViwerViewModel.Camera, Mode=TwoWay}"
    EffectsManager="{x:Bind _3DViwerViewModel.EffectsManager}"
    FXAALevel="High"
    FixedRotationPoint="{x:Bind _3DViwerViewModel.ModelCentroid}"
    FixedRotationPointEnabled="True"
    ShowViewCube="False"
    ZoomAroundMouseDownPoint="True">

    <!--  Add lighting  -->
    <hx:DirectionalLight3D
        Direction="{x:Bind _3DViwerViewModel.Camera.LookDirection}"
        Color="#6A3685" />

    <!--  Render main content  -->
    <hx:LineGeometryModel3D
        Geometry="{x:Bind _3DViwerViewModel.Root}"
        Thickness="1.0"
        Color="#2D0C3E" />

    <!--  Optional axis  -->
    <hx:LineGeometryModel3D
        Geometry="{x:Bind _3DViwerViewModel.Axis}"
        IsRendering="{x:Bind _3DViwerViewModel.ShowAxis}"
        Thickness="1.5"
        Color="#2E9025" />
</hx:Viewport3DX>


        [ObservableProperty]
        private double fieldOfView = 45;

        // Camera for 3D visualization
        public PerspectiveCamera Camera { get; set; } = new PerspectiveCamera {
            Position = new Vector3(0, 0, 100),
            LookDirection = new Vector3(0, 0, -100),
            UpDirection = new Vector3(0, 1, 0),
            FieldOfView = 45,
        };

        // Rendering effects manager
        public DefaultEffectsManager EffectsManager { get; } = new DefaultEffectsManager();

        // Main 3D content (e.g., parsed G-code lines)
        public LineGeometry3D Root { get; }

        // Optional Axis
        public LineGeometry3D Axis { get; } = GenerateGridLines();

        public Vector3 ModelCentroid { get; } = new Vector3(0, 0, 0);

        public bool ShowAxis { get; set; } = true;

        public _3DViwerViewModel(GcodeItem gcodeContent) {
            FileContent = File.Exists(gcodeContent.FilePath)
                ? File.ReadAllText(gcodeContent.FilePath)
                : string.Empty;

            Root = GenerateGcodeGeometry(FileContent);
        }

        private LineGeometry3D GenerateGcodeGeometry(string FileContent) {
            var builder = new LineBuilder();
            var currentPosition = new Vector3(0, 0, 0);

            foreach(var line in FileContent.Split(Environment.NewLine)) {
                try {
                    if(line.TrimStart().StartsWith(";")) // Skip comments
                    {
                        continue;
                    }

                    if(line.StartsWith("G1")) // Parse movement commands
                    {
                        var parts = line.Split(' ');
                        float x = currentPosition.X;
                        float y = currentPosition.Y;
                        float z = currentPosition.Z;

                        foreach(var part in parts) {
                            if(part.StartsWith("X")) {
                                x = float.Parse(part.Substring(1));
                            }

                            if(part.StartsWith("Y")) {
                                y = float.Parse(part.Substring(1));
                            }

                            if(part.StartsWith("Z")) {
                                z = float.Parse(part.Substring(1));
                            }
                        }

                        var newPosition = new Vector3(x, y, z);
                        builder.AddLine(currentPosition, newPosition);
                        currentPosition = newPosition;
                    }
                } catch(Exception ex) {
                    Debug.WriteLine($"Error parsing line: {line}. Exception: {ex.Message}");
                }
            }

            return builder.ToLineGeometry3D();
        }

        private static LineGeometry3D GenerateGridLines() {
            var builder = new LineBuilder();

            // Create horizontal and vertical grid lines
            for(float i = -10; i <= 10; i += 1.0f) {
                // Horizontal lines
                builder.AddLine(new Vector3(-10, i, 0), new Vector3(10, i, 0));
                // Vertical lines
                builder.AddLine(new Vector3(i, -10, 0), new Vector3(i, 10, 0));
            }

            return builder.ToLineGeometry3D();
        }

        partial void OnFieldOfViewChanged(double value) {

            Debug.WriteLine($"FieldOfView changed to: {value}");
            Camera.FieldOfView = value; 
        }
    }
}

Windows development | Windows App SDK

Answer accepted by question author
Anonymous
2025-09-18T04:23:35.0933333+00:00

Hi @Eduardo Gomez ,

When you assign the camera object (_3DViwerViewModel.Camera) to the <hx:Viewport3DX>, Helix takes a reference to that object at initialization. But when you update Camera.FieldOfView in your OnFieldOfViewChanged method, Helix doesn’t automatically re-render because it isn’t listening for property change notifications on the FieldOfView property. The binding is only happening once, so mutating the existing Camera object won’t trigger an update in the viewport.


To resolve this issue, you can bind the slider to the PerspectiveCamera.FieldOfView instead of going through your ViewModel property. This way, the Viewport3DX will update as soon as the slider moves.

If you want to keep your camera in the ViewModel, you need to make sure that the binding system knows when the camera (or its properties) change. This forces the Viewport3DX to re-read the updated camera object.

If you want to know more detail, please let me know! If you think my answer is useful, please interact with the system! Thank you!

Was this answer helpful?

0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.