DX Material, would it be feasible ?

 
 
 
Posted by:psaii
Data created:17 September 2010

Hi there,

Last thing I wanted to check on Max.Net was the possibility to create a custom directX material, that is hardcoding a specific .fx file, specific technique, specific textures & other parameters (later on, this material would actually communicate with another app to get these parameters).

Do you think it would be possible ? any pointers how ? IIDX9VertexShader & IIDX9PixelShader seems to be part of the equation but I'm not too sure how it's supposed to work. The material should hold of vertex shader and one pixel shader interface derived objects, and return them in the GetInterface() method, I guess, but to do that I have to implement quite a few abstract members from these interface, and don't feel like doing it if it's not the right solution ;)

If you have any idea, I would appreciate :)

Thanks,

Psaii

Hi Psaii,

Interesting thought. I've never had to make a DX9 shader in Max so I'm unfamiliar with the process. If it is, like you say, as simple as implementing a material and exposing the IIDX9VertexShader and IIDX9PixelShader through GetInterface(...) then it should be possible, alas, not with the current build.

I need to think over how to expose specific interfaces for the next build to allow that to happen. Meanwhile please let me know if I am missing something about the process of DX9 shader writing (I haven't really found much info about that in the docs, I guess samples would be a better place to look).

Marsel

Marsel Khadiyev (Software Developer, EPHERE Inc.)

It's possible to create ShaderMaterials and wire parameters to it. I wrote a User interface plugin to handle generic fx files and create max shader materials with it.

the main problem is to loop to the paramblock2 to grab and hook to the right params and the values.

to create a directx shader material

IMtl NewShaderMaterial = (IMtl)SceneManager.MaxCore.CreateInstance(SClass_ID.Material, MaxGlobal.Class_ID.Create(0xed995e4, 0x6133daf2));

here are some snippets to access the shader params. if you found a valid param you can manipulate them and change them directly.

int num_pblock2 = a_mtlMaterial.NumParamBlocks;

                if (num_pblock2 > 0)
                {
                    dxCurrentMaterial.Name = a_mtlMaterial.Name;

                    for (int ipbIdx = 0; ipbIdx < num_pblock2; ipbIdx++)
                    {
                        IIParamBlock2 pb2 = a_mtlMaterial.GetParamBlock(ipbIdx);
                        IParamBlockDesc2 pb2dc = pb2.Desc;

                        Task<MaterialDxMatParam>[] taGetDxMatParams = new Task<MaterialDxMatParam>[pb2dc.Count];

                        for (int i = 0; i < taGetDxMatParams.Length; i++)
                        {
                            short CurrentParamBlock2Index = (short)ipbIdx;
                            short CurrentParamBlock2SubIndex = (short)i;

                            taGetDxMatParams[i] = Task.Factory.StartNew<MaterialDxMatParam>(() => this.GetDxMatParam(CurrentParamBlock2Index, CurrentParamBlock2SubIndex, pb2, pb2dc));
                        }

                        Task.WaitAll(taGetDxMatParams);

                        for (int i = 0; i < taGetDxMatParams.Length; i++)
                        {
                            if (taGetDxMatParams[i].Result != null)
                            {
                                dxCurrentMaterial.Childs.Add(taGetDxMatParams[i].Result);
                            }

                            taGetDxMatParams[i].Dispose();
                        }
                    }

                    dxCurrentMaterial.RebuildParamsDictionary();
                }

private MaterialDxMatParam GetDxMatParam(short iParamBlockIndexArg, short iParamBlockSubIndexArg, IIParamBlock2 IIParamBlock2Arg, IParamBlockDesc2 IParamBlockDesc2Arg)
        {
            IParamDef pD = IParamBlockDesc2Arg.GetParamDef(iParamBlockSubIndexArg);

            MaterialDxMatParam dxCurrentParam;

            if (this.ValidParam(pD, out dxCurrentParam))
            {
                dxCurrentParam.pbIdx = iParamBlockIndexArg;
                dxCurrentParam.Idx = iParamBlockSubIndexArg;
                dxCurrentParam.IntName = pD.IntName;

                dxCurrentParam.Value = IIParamBlock2Arg.GetPB2Value(iParamBlockSubIndexArg, 0);
                dxCurrentParam.Type = pD.Type;

                switch (pD.Type)
                {
                    case ParamType2.Float:
                        {
                            dxCurrentParam.IncrementValue = pD.Scale;
                            dxCurrentParam.RangeHigh = pD.RangeHigh.F;
                            dxCurrentParam.RangeLow = pD.RangeLow.F;
                            break;
                        }
                    case ParamType2.Int:
                        {
                            dxCurrentParam.IncrementValue = pD.Scale;
                            dxCurrentParam.RangeHigh = pD.RangeHigh.I;
                            dxCurrentParam.RangeLow = pD.RangeLow.I;
                            break;
                        }
                    case ParamType2.Filename:
                        {
                            dxCurrentParam.StringValue = IIParamBlock2Arg.GetStr(iParamBlockSubIndexArg, 0, 0);
                            break;
                        }
                    case ParamType2.String:
                        {
                            break;
                        }
                }

                return dxCurrentParam;
            }

            return null;
        }

public class MaterialDxMatParam
    {
        public short pbIdx { get; set; }
        public short Idx { get; set; }
        public string IntName { get; set; }
        public eDxGuiParams GuiParamType { get; set; }
        public string StringValue { get; set; }
        public IPB2Value Value { get; set; }
        public ParamType2 Type { get; set; }
        public float IncrementValue { get; set; }
        public float RangeHigh { get; set; }
        public float RangeLow { get; set; }
    }

to change the shader

public bool WriteEffectFileToParam(MaterialDxMatParam a_mdxMaterialParam, IMtl a_mtlMaterial, string strEffectFilePath)
        {
            IIParamBlock2 pb2 = a_mtlMaterial.GetParamBlock(a_mdxMaterialParam.pbIdx);
            return pb2.SetValue(a_mdxMaterialParam.Idx, 0, strEffectFilePath, 0);
        }

 

to reload the shader if the effect file or bitmaps are changed

public void ReloadShaderMaterial(IMtl a_mtlMaterial)
        {
            Log.AddMessage(eLogType.Info, 0, 0, "DxMaterialInterface.ReloadShaderMaterial", string.Empty, string.Empty, string.Format("Reloading DXShader for Material {0}", a_mtlMaterial.Name));

            IIDxMaterial Dx1Material = a_mtlMaterial.GetDxInterface1();

            if (Dx1Material != null)
                Dx1Material.ReloadDXEffect();
        }

GetDxInterface1() is a new method i have implemented inside the max net wrapper itself. the native method was broken so i added new working methods

GetDxInterface1(), GetDxInterface2() and GetDxInterface3()

if someone is interesed on those wrapper changes i can post the changes in the c++ files of the wrapper

 

 


Mario Röske
Technical Artist
Piranha-Bytes