Mental Mill .fx export to Virtools notes

This document is in progress. Some notes may change as new discoveries are made.



CAMERA SPACE <> WORLD SPACE
The MentalMill shader is defined in camera space. It needs to be converted to world space.
Change the following code:  

float4x4 __object_to_camera : WorldView
<
string UIWidget = "none";
>;
float4x4 __object_to_raster : WorldViewProjection
<
string UIWidget = "none";
>;
float4x4 __camera_to_object : WorldViewInverse
<
string UIWidget = "none";
>;

to this:

float4x4 __object_to_camera : World
<
string UIWidget = "none";
>;
float4x4 __object_to_raster : WorldViewProjection
<
string UIWidget = "none";
>;
float4x4 __camera_to_object : WorldInverse
<
string UIWidget = "none";
>;

The introduction of an Environment Map adds a new line to the view matrix coordinates statements. Change:

float4x4 __camera_to_world : ViewInverse

to:

float4x4 __camera_to_world : WorldInverse

 


LIGHT POSITION
One or more lights had to be defined in MentalMill before exporting. Find the following line that defines the light position:

float3 __light0_position : POSITION
<
string Object = "PointLight0";
string Space = "View";
string UIName = "Light0 Light_position";
> = float3(0.000000, 0.000000, 0.000000);


Remove the colon and the POSITION semantic. Recompile the shader.
If not already done, assign the shader to an object's material in the material's setup window. You will now see the XYZ position as an exposed manual parameter in the Shader Params dialog. Change the values to see the light position change. The default value is set by the last line of code above, so you could edit that if desired.

To use the position of a light (or any object) that exists in the scene, replace all the above lines to this:

float3 __light0_position<string type="entity3D";>;

Recompile and now the position parameter is replaced by a popup selection for objects in the scene.

Alternatively, you could use Virtool's NEARESTLIGHT semantic:

float3 __light0_position : NEARESTLIGHT;


SPECULAR COMPONENT relative to LIGHT POSITION and CAMERA POSITION
If the shader has specularity, it will not be calculated in the correct place after the above changes.

Find this code:

float4 fragment_main(
Vert2frag fs_in) : COLOR
{
State state;
state.position = fs_in.position;
state.normal = normalize(fs_in.normal);
state.direction = normalize(state.position);
state.light_position = 0;
state.light_to_surface = 0;
state.light_distance = 0;
state.light_dotnl = 0;
return Math_color_add_1_eval(state);
}


Add this line before the above code:

float3 camPos : EYEPOS;

Change the state.direction line above to read like this:

state.direction = normalize(state.position -camPos);

The specular highlight should now be correct. EYEPOS is the Virtools semantic for the currently active camera position.


TEXTURE MAPS
MentalMill may flip the UVs on the texture placement. If so, look for this function and remove the red part that flips the UVs. (You could remove all calls to this function elsewhere in the code instead, but making this one change to disable the function might be easier.)

float4 __tex2D_flip_v(sampler2D samp, float2 uv)
{
return tex2D(samp, float2(uv.x, 1.0-uv.y));
}


NORMAL MAPS
Virtools uses the second two coordinates channels for tangents and binormals (v.3.5+). Change this section of code:


struct App2vert
{
float4 position : POSITION;
float3 normal : NORMAL;
float4 tex_coord0 : TEXCOORD0;
float4 tex_coord1 : TEXCOORD1;
float4 tex_coord2 : TEXCOORD2;
float4 tex_coord3 : TEXCOORD3;
float3 tex_tangent : TANGENT;
float3 tex_binormal : BINORMAL;
};

Keep it the same except change the last two lines to:

float3 tex_tangent : TEXCOORD1;
float3 tex_binormal : TEXCOORD2;

The function for calculating the normals needs to be changed:

void Normals_make_normal_main(
float4 color,
float amount,
State state,
out float3 result)
{
{
float3 n = (color.xyz - 0.5) * 2.0;
n.xy *= amount;
result = (normalize((mul((state.tangent_space)[0], n))));
}
}

Change this line:
n.xy *= amount;
To these:
n.x *= -amount;
n.y *= amount;


REFLECTION MAPS
The Spherical Environment map imports with the North and South poles along the Z axis instead of Y. Find the section of code for the Environment map and these lines:

gamma = (asin(v.z));
theta = (atan2(v.x, v.y));

Change to this:

gamma = (asin(v.y));
theta = (atan2(v.x, v.z));

The Cube Map environment seems to translate just fine.


TRANSPARENCY

technique T0
{
pass P0
{
ZEnable = true;
ZWriteEnable = true;
CullMode = none;
VertexShader = compile vs_3_0 vertex_main();
PixelShader = compile ps_3_0 fragment_main();
}
}

technique T0
{
pass P0
{
ZEnable = true;
ZWriteEnable = true;
CullMode = ccw;
AlphaBlendEnable = True;
SrcBlend = SrcAlpha ;
DestBlend = InvSrcAlpha;

VertexShader = compile vs_3_0 vertex_main();
PixelShader = compile ps_3_0 fragment_main();
}
}


 

MATERIAL PARAMETERS PASSED TO SHADER PARAMETERS
These are not necessary to make things work, but just a method for convenience.
Using Virtools semantics for material parameters will allow you to use the common color pickers in the material setup window and the shader will inherit these values.

Find the main procedure for your shader color (in this case, "Component_phong_main()"). Add the lines that are in RED before the procedure and near the end of it.

float4 _ambient : AMBIENT;
float4 _specular : SPECULAR;
float4 _diffuse : DIFFUSE;
float4 _emissive : EMISSIVE;

void Component_phong_main(
float specular_shininess,
State state,
out float4 diffuse,
out float4 specular)
{
{
diffuse = (float4(0, 0, 0, 0)) ;
specular = (float4(0, 0, 0, 0));
float3 vdir = state.direction;
Light_iterator light;
{
{
Light_point_1_main(__light0_color, __light0_intensity, __light0_distance_falloff_exponent, __light0_distance_falloff_start, __light0_distance_falloff_limit, __light0_distance_scale, __light0_position, (state), light);
float d = saturate(light.dot_nl);
diffuse += (d * light.contribution) ; //; *_diffuse;
float s = mi_phong_specular(light.direction, vdir, (state.normal), specular_shininess);
if (d > 0.0)
{
specular += (s * light.contribution);
}
}
}
diffuse += _ambient;
diffuse *= _diffuse;
diffuse += _emissive;
specular *= _specular;

diffuse.a = 1.0;
specular.a = 1.0;
}
}

This works pretty well, but there may be better way to do it.

PASSING THE SPECULAR POWER PARAMETER

float Component_phong_1_specular_shininess : SPECULARPOWER;

The 0-100 range of Virtools specular power slider might be more effective by changing the following line in include the red text:

float s = mi_phong_specular(light.direction, vdir, (state.normal), specular_shininess * 10 );