Techniques and Passes
#1
Is there a way to use techniques and passes identified in an FX file?  Currently I am using 3 separate shaders as follows:

                dxDevice.EffectsManager.GetShaders(
    "MeshNormalColorShader.vs", "MeshNormalColorShader.gs", "MeshNormalColorShader.ps", vertexLayoutDesc,
    out _vertexShaderSharedResource, out _geometryShaderSharedResource, out _pixelShaderSharedResource, out _inputLayoutSharedResource,
    throwExceptionIfShadersNotFound: true);
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message); 
            }

However, it would be nice to have something like this:

dxDevice.EffectsManager.GetTechnique("MeshNormalTechnique", "file_name.fx", techniqueSharedResource);

Where the technique could contain multiple passes that constant buffer changes and/or blend & stencil setting changes.
#2
The current version of DXEngine require a little bit more work to create custom effects. An advantage of this is that this gives you better performance.

Anyway, for the future I plan to provide an easier way to add custom effects - something that will be more like in the XNA.
Andrej Benedik
#3
(06-19-2017, 09:59 AM)abenedik Wrote: The current version of DXEngine require a little bit more work to create custom effects. An advantage of this is that this gives you better performance.

Anyway, for the future I plan to provide an easier way to add custom effects - something that will be more like in the XNA.

Do you have a timeline on this?  In the mean time what is the best way to add multiple passes?  Looks like the MeshObjectNode can accept multiple materials...
MeshObjectNode(MeshBase mesh, Material[] materials);

Would you recommend using that to simulate multiple passes or multiple meshobjectnodes with the same mesh?
#4
It is hard to give a good timeline for better support for Techniques and Passes. This will probably come to the Ab3d.DXEngine version 2.3 (the next version 2.2 is already feature complete and will be released with next version of Ab3d.PowerToys - within one month time). This version will be probably released before end of this year.

To add support for multiple passes, you need to create your own Effect (derive your class from Effect class) and then all implement IMultiPassEffect interface. This interface is very simple - it defined 2 methods:

Code:
       /// <summary>
       /// Gets number of passes required to render this effect.
       /// </summary>
       /// <param name="lights">list of lights</param>
       /// <param name="renderingContext">RenderingContext</param>
       int GetRequiredRenderingPassesCount(IList<ILight> lights, RenderingContext renderingContext);

       /// <summary>
       /// Sets the constant buffers and prepares all the shader states for rendering the specified rendering pass. Before this method is called the OnApplyPerFrameSettings method must be called to set other frame settings.
       /// </summary>
       /// <param name="renderingPassIndex">zero based rendering pass index</param>
       /// <param name="renderingContext">RenderingContext</param>
       void ApplyRenderingPass(int renderingPassIndex, RenderingContext renderingContext);

With the first method you tell the DXEngine how many rendering passes this effect required.

The second method is called before DXEngine will call DrawCall to render an object with your effect. It will be called in a loop for each pass and in each iteration renderingPassIndex to the method.

I would advice that you start with a simple custom material and custom effect with one pass - use CustomShaderMaterialSample sample in Customizations folder in the main DXEngine samples project as a template. After you will have a working version of that, add IMultiPassEffect interface to your Effects class. Implement both methods and put breakpoint into the second method to see were in the rendering process you are (you can also put breakpoint into the OnApplyPerFrameSettings and ApplyMaterial methods).

In the future I also plan to provide a sample on how to do that, but currently I do not have time to do that because of vacations.
Andrej Benedik
#5
(06-23-2017, 10:13 PM)abenedik Wrote: It is hard to give a good timeline for better support for Techniques and Passes. This will probably come to the Ab3d.DXEngine version 2.3 (the next version 2.2 is already feature complete and will be released with next version of Ab3d.PowerToys - within one month time). This version will be probably released before end of this year.

To add support for multiple passes, you need to create your own Effect (derive your class from Effect class) and then all implement IMultiPassEffect interface. This interface is very simple - it defined 2 methods:

Code:
       /// <summary>
       /// Gets number of passes required to render this effect.
       /// </summary>
       /// <param name="lights">list of lights</param>
       /// <param name="renderingContext">RenderingContext</param>
       int GetRequiredRenderingPassesCount(IList<ILight> lights, RenderingContext renderingContext);

       /// <summary>
       /// Sets the constant buffers and prepares all the shader states for rendering the specified rendering pass. Before this method is called the OnApplyPerFrameSettings method must be called to set other frame settings.
       /// </summary>
       /// <param name="renderingPassIndex">zero based rendering pass index</param>
       /// <param name="renderingContext">RenderingContext</param>
       void ApplyRenderingPass(int renderingPassIndex, RenderingContext renderingContext);

With the first method you tell the DXEngine how many rendering passes this effect required.

The second method is called before DXEngine will call DrawCall to render an object with your effect. It will be called in a loop for each pass and in each iteration renderingPassIndex to the method.

I would advice that you start with a simple custom material and custom effect with one pass - use CustomShaderMaterialSample sample in Customizations folder in the main DXEngine samples project as a template. After you will have a working version of that, add IMultiPassEffect interface to your Effects class. Implement both methods and put breakpoint into the second method to see were in the rendering process you are (you can also put breakpoint into the OnApplyPerFrameSettings and ApplyMaterial methods).

In the future I also plan to provide a sample on how to do that, but currently I do not have time to do that because of vacations.


That sounds great...I will give that a shot.  I already have a custom effect anyways.
#6
I am using MeshNormalEffect.cs and am able to break on ApplyMaterial, however when I implement the interface GetRequiredRenderingPassesCount is never called.


Code:
public class MeshNormalColorEffect : Ab3d.DirectX.Effect, Ab3d.DirectX.IMultiPassEffect
{
...
        public int GetRequiredRenderingPassesCount(IList<ILight> lights, RenderingContext renderingContext)
        {
            throw new NotImplementedException();
        }

        public virtual void ApplyRenderingPass(int renderingPassIndex, RenderingContext renderingContext)
        {
            throw new NotImplementedException();
        }
}



Is there something else I need to call in order to enable passes?
#7
Uh, sorry when I was writing an answer, I did not have time to check if this would work.
I have checked things again and now I see that multipass rendering works only for standard effect – an effect that is registered as standard effect and rendered objects with standard materials (object, that do not have any specific effect specified). In DXEngine this is used to render many lights – one StandardEffect can render 26 lights in one pass so in cases where there is more than 16 lights in the scene, multiple passes are used to render all the lights.
You can easily register an effect as standard effect with the call to SetStandardEffect on EffectManager (for example for CustomShaderMaterialSample you can use the following line of code – put that into line 93):
dxScene.DXDevice.EffectsManager.SetStandardEffect(_wpfMaterialEffect);
 
After that the GetRequiredRenderingPassesCount method will be called. If you return 2, then ApplyRenderingPass method is called before rendering the second pass.
 
Note that to render transparent objects correctly, DXEngine first renders all passes for the the non-transparent objects and then it renders all the passes for the transparent objects.
For example for 2-pass shader the following methods are called on each frame:
GetRequiredRenderingPassesCount
 
// Render non-transparent objects
OnApplyPerFrameSettings
 
// The following two methdos are called for each object with stadard material
ApplyMaterial      // apply settings before rendering 1st pass
ApplyRenderingPass // apply settings before rendering 2nd pass
 
// Render transparent objects
OnApplyPerFrameSettings
// The following two methdos are called for each object with stadard material
ApplyMaterial      // apply settings before rendering 1st pass
ApplyRenderingPass // apply settings before rendering 2nd pass
 
Another way to render 2-passes is to customize the rendering steps (steps that are executed for each frame).
Usually objects are rendered in RenderObjectsRenderingStep class (an instance can be get from MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep). RenderObjectsRenderingStep allows you to provide a filter function to render only selected objects. You can also specify the OverrideEffect – effect that will be used to render all the objects.
This allows you to change the default RenderObjectsRenderingStep and set the OverideEffect to an effect that renders the first pass. Then you add another RenderObjectsRenderingStep instance and set its OverideEffect to an effect to render second pass.
For example:


Code:
var secondPassRenderObjects = new RenderObjectsRenderingStep("SecondPassRenderObjects")
{
    OverrideEffect = ...
    FilterObjectsFunction = ...
};

 
MainDXViewportView.DXScene.RenderingSteps.AddBefore(MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep, secondPassRenderObjects);
 
You can also add additional RenderObjectsRenderingStep and set FilterObjectsFunction so they will render only specified objects.
 
As you see it is possible to render multi-pass effects, but this not yet an easy task. In the future I will improve support for that and also write an sample that will demonstrate how to do that.
Andrej Benedik
  


Forum Jump:


Users browsing this thread:
1 Guest(s)