



private void OnTriggerEnter(Collider collidedObj)
{
// check that collidedObj is the player & camera
if (collidedObj.gameObject.tag == "MainCamera")
{
// get the world space of the camera (we get this through the collidedObj param)
UnityEngine.Vector3 camRelativePos = collidedObj.transform.eulerAngles;
UnityEngine.Vector3 NPCRelativePos = gameObject.transform.eulerAngles;
// the gameObject to make them look at the camera
// store the value of this rotation needed in NPCRotY
float NPCRotY = 0;
findRotation(camRelativePos.y, NPCRelativePos.y, ref NPCRotY);
// of the bounding box and rotate around that point by the NPCRotY amount
Collider m_Collider = GetComponent<Collider>();
//Fetch the center of the Collider volume
UnityEngine.Vector3 m_Center = m_Collider.bounds.center;
// rotate around that center collider box point
gameObject.transform.RotateAround(m_Center, gameObject.transform.up, NPCRotY);
UnityEngine.Debug.Log("camRelativePos = " + camRelativePos + " NPCRelativePos = " + NPCRelativePos + " NPCRotY = " + NPCRotY);
}
}
// helper function called by Replace()
// replaces an existing GameObject specified by the user with a Prefab specified by the user
// the Prefab will have the same position, rotation and scale as the replaced GameObject.
// We also update our dictionaries to keep track of what GameObject is replaced with what Prefab
// and what GameObject script is replaced with what Prefab script.
// params:
// newPrefab: a GameObject representing the new prefab to be instantiated
// newScript: a ReplacableObjectScript representing the new script to be added as a component to the
// new prefab
// oldScript: a ReplacableObjectScript representing the script component of the GameObject being replaced
// returns:
// none
public void ReplaceObject(GameObject newPrefab, ReplacableObjectScript newScript, ReplacableObjectScript oldScript)
{
// loop through the game objects in the scriptObjList with our custom GetList function
foreach (var oldObj in scriptObjList.GetList())
{
// check that the current gameObject is not null
if (oldObj == null)
{
// if it is null, continue to the next object
continue;
}
// create a new GameObject out of the selected prefab and rename it
newPrefab = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
newPrefab.name = "Prefab_" + oldObj.name;
// set the new prefabs position, rotation, and scale to match the existing gameObject
newPrefab.transform.position = oldObj.transform.position;
newPrefab.transform.rotation = oldObj.transform.rotation;
newPrefab.transform.localScale = oldObj.transform.localScale;
objRefDict.Add(oldObj, newPrefab);
newScript = newPrefab.AddComponent<ReplacableObjectScript>();
newScript.referenceObject = null;
newScript.referenceScript = null;
// we want to store oldObj script as a key with newObj script as the value
oldScript = oldObj.GetComponent<ReplacableObjectScript>();
if (oldScript != null)
{
scriptRefDict.Add(oldScript, newScript);
}
}







The video above shows an animated shader in UE5 made up of three similar, but unique texture samples. The three textures transition rigidly one after another based on the timing of a cosine wave through a custom HLSL node which determines where in the cosine wave we are to determine which texture should be visible. You can see the shader in action on the flat plane.
The video above is a similar shader in UE5, made up of the same three texture samples. However, instead of using a custom HLSL code node to create rigid, defined transitions between textures, this shader uses a series of linear interpolation (LERP) nodes with stepped masked alphas. This creates a similar shader look, but the transitions are smoother and less defined. You can see the shader in action on the flat plane.
The video above shows an animated billboard switching between two advertisements in UE5. The images to the right show the blueprints to create the animated shader - either by nodes or by a custom HLSL node.





