This project is read-only.

Programmatic Shadow

May 3, 2013 at 4:23 AM
Hi folks, I see in the samples how to add shadows in XAML using material groups, but what is the programmatic equivalent? This is where I'm stuck, I can't find a way to use MaterialGroups or MaterialParts in the code.

My model:
                                    // Prepare the model
                                    Microsoft.Xna.Framework.Graphics.Model modelSource = content.Load<Microsoft.Xna.Framework.Graphics.Model>(reader["FileName"].ToString());
                                    nineModel = new Nine.Graphics.Model(modelSource);
                                    nineModel.Transform = Matrix.CreateScale(s) * Matrix.CreateRotationX(r.X) * Matrix.CreateRotationY(r.Y) * Matrix.CreateRotationZ(r.Z) * Matrix.CreateTranslation(p);

                                    // Assign basic material
                                    BasicMaterial basicMaterial = new BasicMaterial(this.GraphicsDevice);
                                    basicMaterial.DiffuseColor = new Vector3(1, 1, 1);
                                    basicMaterial.SpecularColor = new Vector3(0.1f, 0.1f, 0.1f);
                                    basicMaterial.LightingEnabled = true;
                                    nineModel.Material = basicMaterial;

                                    // Add to the scene
                                    scene.Add(nineModel);
My lights:
            currentAmbient = new AmbientLight(scene.GetGraphicsDevice());
            currentAmbient.AmbientLightColor = new Vector3(0.2f, 0.2f, 0.2f);
            scene.Add(currentAmbient);

            currentDirectional = new DirectionalLight(scene.GetGraphicsDevice());
            currentDirectional.DiffuseColor = new Vector3(0.8f, 0.8f, 0.8f);
            currentDirectional.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
            currentDirectional.Direction = new Vector3(-1.0f, -1.0f, -1.0f);
            currentDirectional.CastShadow = true;

            ShadowMap map = new ShadowMap(scene.GetGraphicsDevice());
            map.Size = 512;
            currentDirectional.ShadowMap = map;
            scene.Add(currentDirectional);
Thoughts?

Thanks,
James
May 3, 2013 at 4:30 AM
There is no programatic way to create material groups, since dynamic shader compilation is not supported in game runtime. You can build a material group using XAML and later use ContentManager.Load method to load an instance of the material with shadows.
May 3, 2013 at 2:40 PM
Gotcha, thanks.

Is there a way to create my directional lights programmatically (as shown above in the second code box) but load the material group for the models from the XAML? I ask because I'd like to be able to change the "DirectionalLight.Direction" throughout the game and therefore need access to the class. Also, I need to load my models programmatically - looking through this, I can see how to load a model and group with XAML, but how can I load a model programmatically and assign the material defined in XAML?

Thanks,
James
May 4, 2013 at 1:49 AM
Edited May 4, 2013 at 1:50 AM
In case anyone is wondering, this is how I solved it. Create a XAML called "Shadow.xaml" with the following contents:
<Scene xmlns="http://schemas.microsoft.com/nine/2011/xaml">
    <Model>
        <Model.Material>
            <MaterialGroup>
                <DiffuseMaterialPart />
                <SpecularMaterialPart />
                <SpecularMaterialPart />
                <ShadowMapMaterialPart />
                <DirectionalLightMaterialPart />
            </MaterialGroup>
        </Model.Material>
    </Model>

</Scene>
Load and assign the scene and material group as follows:
            // Test shadows
            Scene shadowScene = content.Load<Scene>("XAML/Shadow");
            Material shadowMaterial = ((Nine.Graphics.Model)shadowScene.Children[0]).Material;

            characterModel = new Nine.Graphics.Model(content.Load<Microsoft.Xna.Framework.Graphics.Model>("Models/Objects/cylinder2h1d"));
            characterModel.Material = shadowMaterial;
            scene.Add(characterModel);
For animations, add the skinned part as necessary. Yufeih, if you see any problems with this method, let me know!
May 4, 2013 at 3:41 AM
Edited May 4, 2013 at 3:43 AM
I think you are able to create the MaterialGroup without the hacking the Model. Pseudo code:
<MaterialGroup xmlns="http://schemas.microsoft.com/nine/2011/xaml">
    <DiffuseMaterialPart /> 
    <SpecularMaterialPart />
    <ShadowMapMaterialPart />
    <DirectionalLightMaterialPart />
</MaterialGroup>
If you want to adjust the material parameters independently for each model instance, you will want to use ContentManager.Create method to create a new material group instance for each model, ContentManager.Load method will always return the same MaterialGroup instance.
characterModel = new Nine.Graphics.Model(content.Load<Microsoft.Xna.Framework.Graphics.Model>("Models/Objects/cylinder2h1d"));
characterModel.Material = content.Create<MaterialGroup>("Shadow")
scene.Add(characterModel);
May 4, 2013 at 9:38 PM
Great reply, thanks :)
May 7, 2013 at 1:20 AM
Two questions on the same topic:
  1. I've asked in the past, but are cascaded shadow maps in the pipeline?
  2. If I have a large area of items to be drawn with shadows, obviously there becomes some large pixelation from the shadow edges - do you have any suggestions for mitigating this?
Thanks, this is still a great project :)

James