• Unity
  • Looking for a full example of using a skin as a normal map.

Related Discussions
...

New to Spine. New to using Unity for 2d. Competent in Unity for 3d. Just doing simple tests in Unity to learn how to use the Spine API.

Trying to wrap my head around how to apply a skin serving as a normal map onto my skeleton. I clearly have some holes in my knowledge, but am willing to learn. I have read a lot of forum posts on here concerning this topic, and the closest I have come so far in finding what I need is the Mix and Match with Skins thread...

http://esotericsoftware.com/forum/Mix-and-Match-with-Skins-12850?p=57147&hilit=normal+map#p57147

Currently I am just playing around with a very simple skeleton that consists of a single square with some color on it as a diffuse/albedo map. I have a separate skin that holds the normal map. Both images are the same size and at the same position in Spine.

Spine setup:
I used export to get into Unity. Both skins are in the same atlas.

In the example I linked to, the code says:

Skin repackedSkin = prevSkin.GetRepackedSkin("Repacked skin", ...

I can only assume that prevSkin is referring to a previously defined skin to use as a normal map, but is never mentioned in the "mixAndMatchSkin" example or any other that I have found.

That said, here is the code I am using which is based off all the examples I have found so far and the error I am receiving. There is a little extraneous code in there, but that is just leftovers from me playing around to learn the API.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Spine.Unity;
using Spine.Unity.AttachmentTools;

public class NormalMappingTest : MonoBehaviour
{
    SkeletonAnimation skeletonAnimation;
    Spine.AnimationState animationState;
    Spine.Skeleton skeleton;

Material runtimeMaterial;
Texture2D runtimeAtlas;
Texture2D[] additionalOutputTextures = null;

void Start()
{
    skeletonAnimation = GetComponent<SkeletonAnimation>();
    animationState = skeletonAnimation.AnimationState;
    skeleton = skeletonAnimation.Skeleton;

    var skeletonData = skeleton.Data;

    Spine.Skin diffuseSkin = new Spine.Skin("diffuseSkin");
    diffuseSkin.AddSkin(skeletonData.FindSkin("diffuse"));

    Spine.Skin normalSkin = new Spine.Skin("normalSkin");
    normalSkin.AddSkin(skeletonData.FindSkin("normal"));

    int[] additionalTexturePropertyIDsToCopy = new int[] { Shader.PropertyToID("_BumpMap") };
    Spine.Skin finishedSkin = normalSkin.GetRepackedSkin("finishedSkin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas, additionalTexturePropertyIDsToCopy: additionalTexturePropertyIDsToCopy, additionalOutputTextures: additionalOutputTextures);

    skeleton.SetSkin(finishedSkin);
    skeleton.SetSlotsToSetupPose();
    animationState.Apply(skeleton);
}
}

And the null reference error from the GetRepackedSkin() method...

Help is appreciated. Also, seeing a simple, non-convoluted example that goes from start to finish would also be really helpful.

Thanks!

Hello and welcome to Spine!

Sorry that the normalmap packing code is not intuitive enough. Thanks for the feedback, we will create an example scene for it, it is listed under this issue ticked here:
[unity] Improve example scenes, description and structure · #1628

The basic problem here is that you are creating two separate skins for normal and albedo textures in your code with one material each - it should rather be organized as multiple skins (e.g. one skin for bluejeans and one skin for redshirt) each with the complete texture set of an albedo and a normal map assigned at the same material.

The proper approach in your setup is to change the Material of your main (albedo) skin to use a shader that accepts an albedo texture and additional maps such as a normalmap. You can use the Spine/Sprite/Vertex Lit and Pixel Lit shaders to assign a normalmap at the material, as shown in the Spine Examples/Other Examples/Sprite Shaders example scene.

So the basic workflow is to first have all your Skeleton's materials setup properly with the right shader and a normalmap assigned (as in the Sprite Shaders example scene). Then you can repack multiple skins (which each reference e.g. one material with a set of 1 albedo texture and 1 normalmap) into a single repacked combined atlas texture set of 1 albedo texture and 1 normalmap. Sorry that the wording can be a bit confusing here.

Sorry that the wording can be a bit confusing here.

No worries. I'm patient.

It's possible I am overthinking things. Is the code below only applicable when using mix-and-match and you want to mix-and-match the normal map as well?

int[] additionalTexturePropertyIDsToCopy = new int[] { Shader.PropertyToID("_BumpMap") };
Spine.Skin finishedSkin = normalSkin.GetRepackedSkin("finishedSkin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas, additionalTexturePropertyIDsToCopy: additionalTexturePropertyIDsToCopy, additionalOutputTextures: additionalOutputTextures);

On a side note, my simple skeleton works fine when I use the texture packer to export both skins as separate images (much like Stretchyman) and drag and drop them to the appropriate slots on the shader.

rad-daddy ha scritto

It's possible I am overthinking things. Is the code below only applicable when using mix-and-match and you want to mix-and-match the normal map as well?

I'm afraid I don't completely understand your question. The code that you posted applies when you are repacking one combined final skin that has been composed of multiple skins, each having a material with a normalmap ("_BumpMap" is the name of the normalmap parameter in the shader here). So if you have combined skins that all have a shader with both an albedo and a normal map, then it shall work using these two lines of code. Or did you mean something else?

You might not have completely understood it, but I think you did answer it.

Am I correct in assuming that a "combined skin" is a skin created using mix-and-match? Or is it referring to something else?

rad-daddy ha scritto

Am I correct in assuming that a "combined skin" is a skin created using mix-and-match? Or is it referring to something else?

You are correct. I used the term "combined skin" to distinguish between something like "unchanged original skins". The "unchanged original skin" would be the one that you have created in Spine and imported, before changing any attachments or calling skin.AddSkin(skin1); skin.AddSkin(skin2);). The "combined skin" is the one where repacking to a new atlas makes sense, since it was created at runtime as a combination of (different parts of) other skins.

These are no official terms however, and they are just skins (no special subclass or anything like that).