Any way to access pre-skinned vertex positions in a material?

Title.

I’m trying to replicate the Left 4 Dead 2 style wound system here: http://www.valvesoftware.com/publications/2010/gdc2010_vlachos_l4d2wounds.pdf

Part of the code takes the pre-skinned vertex position



// Subtract off ellipsoid center
float3 vLocalPosition = ( vPreSkinnedPosition.xyz - vEllipsoidCenter.xyz );


Any way to get at that pre-skinned vertex in UE4 materials?

Heya, I think its possible by editing Engine/Shaders/GpuSkinVertexFactory.usf – this is where input vertex position gets skinned and changed to the new position. Function CalcWorldPosition() does that by calling SkinPosition().

You’d need to extend struct FMaterialVertexParameters to include this new value (pre-skinned vertex position, say call it PreSkinnedPosition) and relevant parts of the code to propagate non-skinned values.

After that you’ll be able to access it in VertexShader (not in pixel shader, without further changes), via custom node, and reference to Parameter.PreSkinnedPosition. So only nodes plugging into CustomizedUV0…6 or WorldPositionOffset will be able to access it, but you can use CustomizedUV’s to transfer positions and access them in PixelShader.
(Eg save X and Y of PreSkinnedPosition as CustomizedUV1 X and Y, and save Z into CustomizedUV2’s X).

A bit involving but possible.

Note that editing these shaders usually kicks off full recompilation of all shaders each time you restart engine, and it will crash it if you make errors that prevent compilation of core materials.

See Shader Development | Unreal Engine Documentation

@xulture - thanks for pointing me in the right direction, that sounds like exactly what I need.

Sounds kinda tricky to do it in a clean, gameplay-friendly way, unfortunately, but thems the breaks I guess.

Thanks again!

So I went through and took a look at GpuSkinVertexFactory.usf.

Here are the changes I’ve made.

In FVertexFactoryIntermediates (line 179 unmodified), I added the PreSkinPosition as a float 3, after the UnpackedPosition parameter.

In CalcWorldPosition, line 494, I added this line:


Intermediates.PreSkinnedPosition = Intermediates.UnpackedPosition;

Then in VertexFactoryGetInterpolantsVSToPS (line 555 unmodified), I added this:



if NUM_MATERIAL_TEXCOORDS > 2
	TexCoords[1].x = Intermediates.PreSkinnedPosition.x; 
	TexCoords[1].y = Intermediates.PreSkinnedPosition.y;
	TexCoords[2].x = Intermediates.PreSkinnedPosition.z; 
#endif


From what I understand of how this works, this should end up passing the pre-skin vertex positions through the Customized UVs 1 and 2.


The main downside to this from what I can tell is that if some materials use UVs 1 and 2 and are skinned, it will cause it to screw up the UVs.

Edit:

Derp, I just realized I implemented this in a hackier way than it really needs to be. The way you mention seems to be a lot better than what I did above.

Using your method, I’d want to add PreSkinPosition to FMaterialVertexParamaters, reference that from the material via the custom node as you mention, then plug that into CusotmizedUVs 1 and 2, then us the UV coord node to utilize the results.

I think I have that right, at least.

Yepp thats it – since you need this to work for your game, then ‘hacky’ solution is fine. If you need to support other users of the solution, you may want to make it more friendly. Up to you really…

Thanks for sharing your solution!! I was too lazy to do this myself, but was looking into it because we wanted to make ‘auto flat uv unwrapping’ based on world position. It works fine for static meshes, but I didn’t have pre-skinned vertex position – exactly what you just added :slight_smile:

It ended up being a bit simpler than I thought it would, after I looked at the shader :smiley:

Just to go over the final design and changes to do:

I looked around and found that the FMaterialVertexParameters struct is in MaterialTemplate.usf.

I’m going to try adding the pre-skin position in there, along with a change to stick the value of Input.UnpackedPosition into Input.PreSkinnedPosition (wherever that gets filled, or in CalcWorldPosition if not). Then it should be available via the Custom node as you mentioned and can be plugged into the Custom UV 1 and 2 and then used via the UV1 and UV2 nodes.

BTW, this worked great @xulture, thanks for all your help :).

What I ended up doing was to add PreSkinPosition to FMaterialVertexParameters as you mentioned (in MaterialTemplate.usf), then in GpuSkinVertexFactory.usf where it builds the class-specific vertex inputs, I do


Result.PreSkinPosition = Input.Position.xyz;

In the material, this can be accessed by


Parameter**s**.PreSkinPosition

(notice the s, I was confused why it wasn’t working until I changed Parameter to Parameters)

Does anyone here know if this technique has been superseded by the new **PreSkinnedPosition **node in BP? Seems like it should but I’ve been trying to get that working but so far I’m missing something. If anyone can help I would be forever grateful.

[USER=“1213130”]Len White[/USER] - Yes your assumption is correct, it’s the same thing. You still need to feed it through to the pixel shader via a custom UV coordinate though (easy enough, just set UV coords to 3, fill the 2nd and 3rd ones with the vertex pos and then reconstruct it into a vector later).