AB4D Forum

Full Version: ReadingComplete
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'm having an issue with the ReadingComplete function. If I load a very small file i have no troubles or if i my modelLoaded function after the model has loaded everything works great. However when i use the ReadingComplete function it seem to run the function before everything has loaded. Have I done something wrong?

MainWindow.xaml.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.IO;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using Ab3d;

namespace Simple_3ds_loading
{
    public partial class MainWindow : Window
    {

         // spin timer
        private DispatcherTimer dTimer;
        private int count;
        
        Ab3d.Reader3ds newReader3ds;
        Model3DGroup modelGroup;

        //transforms
        Transform3DGroup myTransform3DGroup = new Transform3DGroup();
        ScaleTransform3D myScaleTransform3D = new ScaleTransform3D();
        RotateTransform3D myRotateTransform3D = new RotateTransform3D();
        AxisAngleRotation3D myAxisAngleRotation3d = new AxisAngleRotation3D();

        //camra and light
        PerspectiveCamera myPCamera = new PerspectiveCamera();
        DirectionalLight myDirectionalLight = new DirectionalLight();

        public MainWindow()
        {  
            InitializeComponent();
        }

        private void myPageLoaded(object sender, EventArgs e)
        {
            loadModel();
        }

        void loadModel()
        {
            //bring up the choose file dialog
            Microsoft.Win32.OpenFileDialog loadWho = new Microsoft.Win32.OpenFileDialog();
            loadWho.Filter = "3-D files (.3ds)|*.3ds";
            //loadWho.FilterIndex = 0;
            Nullable<bool> result = loadWho.ShowDialog(this);
            if (result == true)
            {
                newReader3ds = new Ab3d.Reader3ds();
                newReader3ds.ThrowMissingTextureException = true;
                newReader3ds.ReadingComplete += new EventHandler(newReader3ds_ReadingComplete);

                Console.WriteLine("--");
                Console.WriteLine(loadWho.FileName);

                try
                {
                    modelGroup = newReader3ds.ReadFile(loadWho.FileName, Viewport1);
                }
                catch (Reader3ds.MissingTextureException f)
                {
                    MessageBox.Show("Missing texture: " + f.MissingTextureFileName);
                    newReader3ds.ThrowMissingTextureException = false;
                    modelGroup = newReader3ds.ReadFile(loadWho.FileName, Viewport1);
                }
              

            }
            else
            {
                //must load a file
                loadModel();
            }
        }

        void OnClick1(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("pressed");
            modelLoaded();
        }


        private void newReader3ds_ReadingComplete(Object sender, EventArgs e)
        {
            Console.WriteLine("we think the model is finished loading");

            //modelLoaded();
        }


        private void modelLoaded()
        {
            //Set camera values.
            myPCamera = (Viewport1.Camera as PerspectiveCamera);
            //myPCamera.FarPlaneDistance = 5000;
            //myPCamera.NearPlaneDistance = 1;
            myPCamera.FieldOfView = 60;
            myPCamera.Position = new Point3D(0, 60, 300);
            myPCamera.LookDirection = new Vector3D(0, -.2, -1);
            myPCamera.UpDirection = new Vector3D(0, 1, 0);

            // Directional light values.
            myDirectionalLight.Color = Colors.White;
            myDirectionalLight.Direction = new Vector3D(0, -1, 0);
            modelGroup.Children.Add(myDirectionalLight);

            //get bounds
            Rect3D objectBounds = modelGroup.Bounds;

            //deside how big to make it.
            double resizePer = (300 / objectBounds.SizeX);
            double resizePerY = (300 / objectBounds.SizeY);
            double resizePerZ = (300 / objectBounds.SizeZ);
            if (resizePerY < resizePer)
            {
                resizePer = resizePerY;
            }
            if (resizePerZ < resizePer)
            {
                resizePer = resizePerZ;
            }

            //set the size
            myScaleTransform3D.ScaleX = resizePer;
            myScaleTransform3D.ScaleY = resizePer;
            myScaleTransform3D.ScaleZ = resizePer;
            myTransform3DGroup.Children.Add(myScaleTransform3D);

            // Create a transformation that i can use to do some rotating.
            myAxisAngleRotation3d.Axis = new Vector3D(0, 3, 0);
            myAxisAngleRotation3d.Angle = 0;
            myRotateTransform3D.Rotation = myAxisAngleRotation3d;
            myTransform3DGroup.Children.Add(myRotateTransform3D);
            modelGroup.Transform = myTransform3DGroup;

            //start the timer to give us some spinning...for fun.
            count = 100;
            dTimer = new DispatcherTimer();
            dTimer.Interval = new TimeSpan(100000);
            dTimer.Tick += new EventHandler(dTimer_Tick);
            dTimer.Start();        
        }
    
        void dTimer_Tick(object sender, EventArgs e)
        {
            count++;
            if (count > 660)
            {
                count = 100;
            }
            if (count > 300)
            {
                //and this makes it spin.
                myAxisAngleRotation3d.Angle = (count-300)*-1;

            }

        }

    }
}

MainWindow.xaml
Code:
<Window x:Class="Simple_3ds_loading.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="800"
        Loaded="myPageLoaded">
    <Grid>
        <Viewport3D Name="Viewport1" ClipToBounds="True"></Viewport3D>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="691,526,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="OnClick1" ClickMode="Press"/>
    </Grid>
</Window>

thanks,
Bryan
If you are reading 3ds file from code, there is really no need to use ReadingComplete.

Because reading is synchronous you can just call ReadFile method and when it returns the reading is complete. The event is primary used for use in XAML (for Model3ds or using Reader3ds in XAML as resource) - there you need an event to know when loading of 3ds file is complete.


The problem with your code is that the read Model3DGroup is stored into modelGroup field from the ReadFile method:

modelGroup = newReader3ds.ReadFile(loadWho.FileName, Viewport1);

But the ReadingComplete event is fired just before the return statement in ReadFile - so your modelLoaded method is called before the modelGroup is set.

As already said - just forget the ReadingComplete and call the modelLoaded after the ReadFile.


By the way I am working on new version of Reader3ds where you will have ProgressChanged event to show progress while reading more complex files (just like it already exist in ReaderWmf and ReaderSvg).

Also there will be no need to use Reader3ds.MissingTextureException any more - it will be replaced by much better ResolveTextureFileCallback delegate.

The new version could be available in a week or two so stay in touch.
Ok, made some changes...

Scraped the "ReadingComplete" part and commented out the "ThrowMissingTextureException" just to simplify.

Still HAD problems. For some reason on some Models (large ones over one meg, missing one or more textures.) there would be no 3d camera in the view port so when i tried to adjust the camera it would return an error. What I ended up doing is adding a camera to the XAML part of my code and that seems to work for all models. My theory is that sometimes ReadFile adds a camera form me and sometimes it does not.

Here is one of the files i was having trouble with:

http://artist-3d.com/free_3d_models/dnm/...ount=count



Thanks,
Bryan
absolutely great codes!
Reader3ds only read cameras if they are defined in 3ds file.
You can get the collection of all cameras that are defined in 3ds file from Cameras property on Reader3ds.

If you are using Read method to read the 3ds file and specify the Viewport3D parameter and there is at least one camera defined in 3ds file, the first read camera is applied to the Viewport3D. If there are no cameras defined in 3ds file no camera is applied to Viewport3D. If you know that there are more cameras defined, you can also pass the cameraIndex as an additional parameter to Read method.

If it also possible to skip reading cameras with setting the ImportCameras to false. By default its value is true to enable reading cameras.


If you do not know if 3ds file will have cameras defined, I would recommend you to check the Cameras collection after reading the 3ds file. If there are no camera defined, you should create a fallback camera. I recommend that you measure the read scene and create a camera based on the size of read objects - see the CreateFreeCamera method in the Animator3ds sample.