Unity Terrain Tri-Planar Texturing

I’ve worked up some shaders for Unity’s Terrain system that allows for tri-planar texturing. Adds normal/spec/gloss, too.

Download the package with example scene here;

http://www.farfarer.com/temp/triPlanarTexture.unitypackage

Here’s a shot of it in action with a procedurally generated terrain by Derek Traver;
Unity Terrain with Tri-Planar Texturing

Posted in Unity | Comments Off

Dynamic Ambient Lighting in Unity

Dynamic Ambient Lighting

I’ve been working on getting dynamic ambient lighting working within Unity. Based off Valve’s 6-colour pre-baked ambient lighting (detailed here, pg 5, ch 8.4.1), but it grabs the 6 colours dynamically.

There’s probably lots more you could do to optimise it further (e.g. use replacement shaders when rendering the cubemap that do simpler lighting calcs). But you could do that yourself as required.

I’d also advise against using it on anything other than your main character, as it’s likely too expensive to run on multiple objects.

Cubemap Camera Script

Create a new camera and turn off the GUI, Flare and Audio components.

Set up it’s Culling Layers to not render non-essential things like particles or incidental detail. Also move your character to it’s own layer and set the camera not to render it (we don’t want bits of the character rendered into the cubemap).

Attach this javascript to it and set the target to be your character and set up the offset from your character’s position so that it’s in the centre of your character (i.e. a 2m tall character wants to be offset 0, 1, 0 so that the camera renders from the characters centre.

@script ExecuteInEditMode

public var target : Transform;
public var cubemapSize : int = 128;
public var oneFacePerFrame : boolean = true;
public var offset : Vector3 = Vector3.zero;
private var cam : Camera;
private var rtex : RenderTexture;

function Start () {
	cam = camera;
	cam.enabled = false;
	// render all six faces at startup
	UpdateCubemap( 63 );
	transform.rotation = Quaternion.identity;
}

function LateUpdate () {
    if ( oneFacePerFrame ) {
        var faceToRender = Time.frameCount % 6;
        var faceMask = 1 << faceToRender;
        UpdateCubemap ( faceMask );
    } else {
        UpdateCubemap ( 63 ); // all six faces
    }
}

function UpdateCubemap ( faceMask : int ) {
	if ( !rtex ) {
		rtex = new RenderTexture ( cubemapSize, cubemapSize, 16 );
		rtex.isPowerOfTwo = true;
		rtex.isCubemap = true;
		rtex.useMipMap = true;
		rtex.hideFlags = HideFlags.HideAndDontSave;
		rtex.SetGlobalShaderProperty ( "_WorldCube" );
	}

	transform.position = target.position + offset;

	cam.RenderToCubemap ( rtex, faceMask );
}

function OnDisable () {
	DestroyImmediate ( rtex );
}

Dynamic Ambient Shader

This is the shader that generates and applies the ambient lighting from the cubemap rendered by the camera above.

Create a new shader, paste this code into it and save it. We’ll integrate it into our shaders next.

Shader "DynamicAmbient" {
	Properties {
		_MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "white" {}
		_BumpMap ("Normal (Normal)", 2D) = "bump" {}
	}

	SubShader{
		Pass {
			Name "DynamicAmbient"
			Tags {"LightMode" = "Always"}

			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma fragmentoption ARB_precision_hint_fastest

				#include "UnityCG.cginc"

				struct v2f
				{
					float4	pos : SV_POSITION;
					float2	uv : TEXCOORD0;
					float3	normal : TEXCOORD2;
					float3	tangent : TEXCOORD3;
					float3	binormal : TEXCOORD4;
				}; 

				v2f vert (appdata_tan v)
				{
					v2f o;
					o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
					o.uv = v.texcoord.xy;
					o.normal = mul(_Object2World, float4(v.normal, 0)).xyz;
					o.tangent = v.tangent.xyz;
					o.binormal = cross(o.normal, o.tangent) * v.tangent.w;
					return o;
				}

				sampler2D _MainTex;
				sampler2D _BumpMap;
				samplerCUBE _WorldCube;

				float4 frag(v2f i) : COLOR
				{
					fixed4 albedo = tex2D(_MainTex, i.uv);
					float3 normal = UnpackNormal(tex2D(_BumpMap, i.uv));

					float3 worldNormal = normalize((i.tangent * normal.x) + (i.binormal * normal.y) + (i.normal * normal.z));

					float3 nSquared = worldNormal * worldNormal;
					fixed3 linearColor;
					linearColor = nSquared.x * texCUBEbias(_WorldCube, float4(worldNormal.x, 0.00001, 0.00001, 999)).rgb; // For unknown reasons, giving an absolute vector ignores the mips....
					linearColor += nSquared.y * texCUBEbias(_WorldCube, float4(0.00001, worldNormal.y, 0.00001, 999)).rgb; // ...so unused components must have a tiny, non-zero value in.
					linearColor += nSquared.z * texCUBEbias(_WorldCube, float4(0.00001, 0.00001, worldNormal.z, 999)).rgb;

					float4 c;
					c.rgb = linearColor * albedo.rgb;
					c.a = albedo.a;
					return c;
				}
			ENDCG
		}
	}
	FallBack Off
}

Integrating the Ambient Shader into Surface Shaders

Now, we can use the above shader wherever we want it via the UsePass command, and blending everything else on top.

The key here is to ensure your surface shader’s blend mode is set to additive (One One) otherwise it’ll just write clean over the lovely ambient light that’s been applied.
So, before your surface shader’s CGPROGRAM block, add the lines;

UsePass "DynamicAmbient/DYNAMICAMBIENT"
Blend One One

We’ve also got to ensure that our surface shader doesn’t use the ambient light value that’s set in the editor, otherwise it’ll add the two together and defeat the purpose. So when you define the surface shader to use, ensure you add the noambient argument. e.g;

#pragma surf BlinnPhong noambient

Your new surface shader with dynamic ambient lighting should look something like this;

Shader "Bumped Specular" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
		_Shininess ("Shininess", Range (0.03, 1)) = 0.078125
		_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
		_BumpMap ("Normalmap", 2D) = "bump" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 400

	UsePass "DynamicAmbient/DYNAMICAMBIENT"
	Blend One One
	CGPROGRAM
		#pragma surface surf BlinnPhong noambient

		sampler2D _MainTex;
		sampler2D _BumpMap;
		fixed4 _Color;
		half _Shininess;

		struct Input {
			float2 uv_MainTex;
			float2 uv_BumpMap;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
			o.Albedo = tex.rgb * _Color.rgb;
			o.Gloss = tex.a;
			o.Alpha = tex.a * _Color.a;
			o.Specular = _Shininess;
			o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
		}
	ENDCG
	}
	FallBack "Specular"
}

Now apply your new shader to your character’s material and we’re done :)

Posted in Tutorial, Unity | Comments Off

Team Fortress 2 & Anisotropic Highlight Unity Shaders

Just a note that I’ve put up a couple of Unity Surface Shaders onto the Unify Community Wiki.

Team Fortress 2

This replicates the toon ramp shader that Valve’s Team Fortress 2 uses. With a toon ramp and rim lighting.

Code and usage instructions here.

Anisotropic Highlights

This replicates the anisotropic highlights you find on surfaces like brushed metal and long hair.

Code and usage instructions here.

Posted in Unity | Comments Off

Unity Skeletal Ragdoll / Jiggle Bones Tutorial

This is a tutorial on getting bones that are part of an animated skeleton to be controlled by Unity’s physics system rather than animation, i.e. ragdoll or jiggle bones. It took me a while to figure out the specifics of getting it working.

This method will also work with 3DS Max Bipeds Twist bones, which rely on the animation being fully baked.

Click on any of the images for a larger version.

Setting Up In 3DS Max

Set up and skin your rig as you usually would. Include any bones you would like to be jiggle bones and attach them into the skeleton’s hierarchy as normal.

In my case, I have some dangling belt attachments and my characters ponytail intended to be jiggle bones.

 The Key to Jiggle Bones

The important thing to note is that, while all of my regular bones are keyframed into the T-Pose, the jiggle bones do not have keyframes. They are positioned correctly but they are not keyframed into position.

It is imperative that the jiggle bones remain unkeyframed throughout your T-Pose and all of your animations. One keyframe anywhere in there and the animation system takes control over the physics and you’ve just got regular skeletal animation again.

Exporting the T-Pose

When exporting the t-pose, select your mesh(es) and your bones, including your twist bones and including the bones that you want to be jiggle bones.

Go to Export > Export Selected and choose FBX as the format.

Ensure that you do not export animation at this point – we only want the model, it’s bones and the skinning information. Chosing animation export here will mean that it gives keyframed positions to our jiggle bones, which stops them being jiggle bones.

 Exporting Animations

When using Bipeds Twist bones, they are not keyframed directly and so have to have the animation fully baked out.

The problem arises here, because baking the animation also means that any jiggle bones get keyframes assigned. Disaster!

What do we do? Simple – don’t export the jiggle bones at all when exporting animation.

This is where Export Selected comes into play again. We simply select everything we did in the T-Pose export except the jiggle bones. Unity will simply find that the jiggle bones aren’t in the exported animation and won’t attempt to apply the animation to our jiggle bones.

To this end, I find it easier to keep the jiggle bones in their own layer that I keep frozen. Which stops me accidentally moving, selecting or keyframing them.

So, once you have selected everything you want exported (except the jiggle bones, of course), go once again to Export > Export Selected and choose FBX as the format.

This time the filename’s the Unity animation  standard of [modelName]@[animationName].fbx.

Ensure you tick the box marked Bake, or your twist bones won’t be exported.

Setting Up in Unity

Now the jiggle bones are in and unkeyframed, hooking them up to the physics engine is the same process as you would set up any ragdolled joint, but I’ll run through the process anyway.

The Parent Bone

The parent bone should be whichever bone your jiggle bone is attached to. First up, drag your model into the scene then find and select the parent bone in the project hierarchy.

Apply a rigidbody to your parent bone. Set it to be Kinematic and uncheck Apply Gravity.

Apply a collider to your parent bone and set up it’s scale and alignment so that it fits the mass of the vertices the bone has influence over.

The Jiggle Bone

Jump down the hierarchy in the project pane and select the bone you want to be a jiggle bone.

Again, apply a rigidbody but this time ensure Kinematic is unchecked and Apply Gravity is checked. Set the mass and drag to fit the material and size of whatever your jiggle bone is.

Apply a collider and set it’s scale and alignment to fit your jiggle bone.

Now apply a physics joint. Any kind will work but in this instance I’m using a Character Joint. Set the Connected Body to be the same Rigidbody component you just applied to the parent bone. Set up the constraints of your physics joint to be what you like.

Other Bones

In some cases, you will want other parts of your model to collide with your jiggle bone. In my case, I want both of my characters thighs to be able to knock the belt attachments around as she runs.

For each of these bones, repeat the process we used in the parent bone of attaching a kinematic rigidbody and collider.

Final Touches

So, now we should have rigidbodied bones that succumb to gravity and collide with other bones as they move via skeletal animation.

But you’ll notice that as your character moves around the world, they don’t get affected by momentum, they just sit there hanging down.

There are two possible solutions to this;

1) In your models Animation component in the inspector, there’s a tickbox for “Animate Physics”, which may work for you but I found this gives very jittery, erratic results. So, as a solution…

2) Use a little script to get the movement of the parent bone and apply it as a force to the rigidbody. Create a new Java Script and copy this code into it then apply it to each of your jiggle bones;

#pragma strict

private var thisParent : Transform;
private var thisRigidbody : Rigidbody;

private var parentPosLastFrame : Vector3 = Vector3.zero;

function Awake () {
	thisParent = transform.parent;
	thisRigidbody = transform.GetComponent.< Rigidbody > ();
}

function Update () {
	thisRigidbody.AddForce ( ( parentPosLastFrame - thisParent.position ) * 100 );
	parentPosLastFrame = thisParent.position;
}

Finished!

Thanks for reading, and I hope some of you found this helpful.

Posted in Tutorial, Unity | Comments Off

Unity Baby Steps

It’s a few weeks on and I’ve gotten most of my planned game mechanics in and working (in some state or another) now. What remains is mostly polish (tighten controls, lots of particles and sounds) then onto building an interface and some actual levels to progress through.

First big progress is being able to shoot. Took me a good while to get it working properly, but it’s all good now… bar some Xbox360 pad trigger ball-ache. I’ve even got animation blending working so that Lou’s arm points in the correct direction.

The second biggest milestone is that I now have moonlight that shines into the level from above. It’s still kinda hacky but without a Pro liscence I’m a bit stuck as to how I’m supposed to fix it. When Lou’s in the moonlight, he has full access to his super-powers. Currently that’s just wall-sliding, wall-jumping and double-jumping.

You can now shoot out the platforms to let the moonlight shine through the hole. I’ve also added in some reinforced platforms, that’ll let light through but not anything else.

More soon. I’ll get a web-playable build up as soon as there’s something more to it than a testbed.

Posted in Games Prototyping, Unity | Comments Off

Beginning Unity

So, I’ve started my blog that will document my forays into the Unity engine and the progress in the games I make in it.

These will mostly be about games created for my university course, BSc Game Design at Leeds Metropolitan University.  I’ve got two to create – a simple platformer for Games Prototyping, and a more complex full game for my Final Year Project. First up is Games Prototyping.

I’ve been at it for a couple of weeks now, still learning the basics. So far I’ve dabbled in character controlling, shaders and some physics triggers.

Shader-wise, I’ve ported over my 3-Layer Toon Shader from the Lou Garoux project – who will be the main character of the game. It’s been quite a challenge to get this working, trying to inject CGFX code into the Unity shader system in a way that I can access all the values I need access to, but after a few lunchtimes of trial-and-error and hacking apart other shaders, I finally figured it out.

With my physics triggers, I’ve got platforms that can be destroyed by falling objects. Later they’ll only be destroyable by Lou shooting at them with his trusty Hole Maker gun.

Character control has been my main focus so far, I’ve got my character in and partially animated. He can run, jump, double jump and (almost) wall jump – at the minute he just slides down walls more slowly than falling. In the end, Lou will only be able to perform the advanced actions (wall sliding, wall jumping and double jumping) whilst under the full glare of the moon above, which he’ll have to let shine into the areas he needs by making holes in the platforms above him. And, if I get far enough, by redirecting with mirrors into hard to reach places.

So, that’s where I’m at after 2 weeks of lunch times and a few evenings.

My next move with the game will be to get wall-jumping in and get him able to shoot things – which will require some more animations. I’ll also try and document things like the shader creation a little further.

Posted in Games Prototyping, Unity | Comments Off