unity3D实现摄像机抖动特效

本文实例为大家分享了unity3D实现摄像机抖动的具体代码,供大家参考,具体内容如下

摄像机抖动特效 在需要的地方调用CameraShake.Shake()方法就可以

public class CameraShake : MonoBehaviour
 {
 ///
 /// The cameras to shake.
 ///
 public List cameras   = new List();
 ///
 /// The maximum number of shakes to perform.
 ///
 public int numberOfShakes   = 2;
 ///
 /// The amount to shake in each direction.
 ///
 public Vector3 shakeAmount   = Vector3.one;
 ///
 /// The amount to rotate in each direction.
 ///
 public Vector3 rotationAmount   = Vector3.one;
 ///
 /// The initial distance for the first shake.
 ///
 public float distance   = 00.10f;
 ///
 /// The speed multiplier for the shake.
 ///
 public float speed   = 50.00f;
 ///
 /// The decay speed (between 0 and 1). Higher values will stop shaking sooner.
 ///
 public float decay   = 00.20f;
 ///
 /// The modifier applied to speed in order to shake the GUI.
 ///
 public float guiShakeModifier   = 01.00f;
 ///
 /// If true, multiplies the final shake speed by the time scale.
 ///
 public bool multiplyByTimeScale   = true;

 // Shake rect (for GUI)
 private Rect shakeRect;

 // States
 private bool shaking   = false;
 private bool cancelling   = false;

 internal class ShakeState
 {
 internal readonly Vector3 startPosition;
 internal readonly Quaternion startRotation;
 internal readonly Vector2 guiStartPosition;
 internal Vector3 shakePosition;
 internal Quaternion shakeRotation;
 internal Vector2 guiShakePosition;

 internal ShakeState(Vector3 position, Quaternion rotation, Vector2 guiPosition)
 {
 startPosition = position;
 startRotation = rotation;
 guiStartPosition = guiPosition;
 shakePosition = position;
 shakeRotation = rotation;
 guiShakePosition = guiPosition;
 }
 }
 private Dictionary> states = new Dictionary>();
 private Dictionary shakeCount  = new Dictionary();

 // Minimum shake values
 private const bool checkForMinimumValues  = true;
 private const float minShakeValue  = 0.001f;
 private const float minRotationValue  = 0.001f;

 #region Singleton
 ///
 /// The Camera Shake singleton instance.
 ///
 public static CameraShake instance;
 private void OnEnable()
 {
 if (cameras.Count < 1)
 {
 if (camera)
  cameras.Add(camera);
 }

 if (cameras.Count < 1)
 {
 if (Camera.main)
  cameras.Add(Camera.main);
 }

 if (cameras.Count < 1)
 {
 Debug.LogError("Camera Shake: No cameras assigned in the inspector!");
 }
 instance = this;
 }
 #endregion

 #region Static properties
 public static bool isShaking
 {
 get
 {
 return instance.IsShaking();
 }
 }
 public static bool isCancelling
 {
 get
 {
 return instance.IsCancelling();
 }
 }
 #endregion

 #region Static methods
 public static void Shake()
 {
 instance.DoShake();
 }
 public static void Shake(int numberOfShakes, Vector3 shakeAmount, Vector3 rotationAmount, float distance, float speed, float decay, float guiShakeModifier, bool multiplyByTimeScale)
 {
 instance.DoShake(numberOfShakes, shakeAmount, rotationAmount, distance, speed, decay, guiShakeModifier, multiplyByTimeScale);
 }
 public static void Shake(System.Action callback)
 {
 instance.DoShake(callback);
 }
 public static void Shake(int numberOfShakes, Vector3 shakeAmount, Vector3 rotationAmount, float distance, float speed, float decay, float guiShakeModifier, bool multiplyByTimeScale, System.Action callback)
 {
 instance.DoShake(numberOfShakes, shakeAmount, rotationAmount, distance, speed, decay, guiShakeModifier, multiplyByTimeScale, callback);
 }
 public static void CancelShake()
 {
 instance.DoCancelShake();
 }
 public static void CancelShake(float time)
 {
 instance.DoCancelShake(time);
 }

 public static void BeginShakeGUI()
 {
 instance.DoBeginShakeGUI();
 }
 public static void EndShakeGUI()
 {
 instance.DoEndShakeGUI();
 }
 public static void BeginShakeGUILayout()
 {
 instance.DoBeginShakeGUILayout();
 }
 public static void EndShakeGUILayout()
 {
 instance.DoEndShakeGUILayout();
 }
 #endregion

 #region Events
 ///
 /// Occurs when a camera starts shaking.
 ///
 public event System.Action cameraShakeStarted;
 ///
 /// Occurs when a camera has completely stopped shaking and has been reset to its original position.
 ///
 public event System.Action allCameraShakesCompleted;
 #endregion

 #region Public methods
 public bool IsShaking()
 {
 return shaking;
 }
 public bool IsCancelling()
 {
 return cancelling;
 }
 public void DoShake()
 {
 Vector3 seed = Random.insideUnitSphere;

 foreach(Camera cam in cameras)
 {
 StartCoroutine(DoShake_Internal(cam, seed, this.numberOfShakes, this.shakeAmount, this.rotationAmount, this.distance, this.speed, this.decay, this.guiShakeModifier, this.multiplyByTimeScale, null));
 }
 }
 public void DoShake(int numberOfShakes, Vector3 shakeAmount, Vector3 rotationAmount, float distance, float speed, float decay, float guiShakeModifier, bool multiplyByTimeScale)
 {
 Vector3 seed = Random.insideUnitSphere;

 foreach(Camera cam in cameras)
 {
 StartCoroutine(DoShake_Internal(cam, seed, numberOfShakes, shakeAmount, rotationAmount, distance, speed, decay, guiShakeModifier, multiplyByTimeScale, null));
 }
 }
 public void DoShake(System.Action callback)
 {
 Vector3 seed = Random.insideUnitSphere;

 foreach(Camera cam in cameras)
 {
 StartCoroutine(DoShake_Internal(cam, seed, this.numberOfShakes, this.shakeAmount, this.rotationAmount, this.distance, this.speed, this.decay, this.guiShakeModifier, this.multiplyByTimeScale, callback));
 }
 }
 public void DoShake(int numberOfShakes, Vector3 shakeAmount, Vector3 rotationAmount, float distance, float speed, float decay, float guiShakeModifier, bool multiplyByTimeScale, System.Action callback)
 {
 Vector3 seed = Random.insideUnitSphere;

 foreach(Camera cam in cameras)
 {
 StartCoroutine(DoShake_Internal(cam, seed, numberOfShakes, shakeAmount, rotationAmount, distance, speed, decay, guiShakeModifier, multiplyByTimeScale, callback));
 }
 }
 public void DoCancelShake()
 {
 if (shaking && !cancelling)
 {
 shaking = false;
 this.StopAllCoroutines();
 foreach(Camera cam in cameras)
 {
  if (shakeCount.ContainsKey(cam))
  {
  shakeCount[cam] = 0;
  }
  ResetState(cam.transform, cam);
 }
 }
 }
 public void DoCancelShake(float time)
 {
 if (shaking && !cancelling)
 {
 this.StopAllCoroutines();
 this.StartCoroutine(DoResetState(cameras, shakeCount, time));
 }
 }
 public void DoBeginShakeGUI()
 {
 CheckShakeRect();
 GUI.BeginGroup(shakeRect);
 }
 public void DoEndShakeGUI()
 {
 GUI.EndGroup();
 }
 public void DoBeginShakeGUILayout()
 {
 CheckShakeRect();
 GUILayout.BeginArea(shakeRect);
 }
 public void DoEndShakeGUILayout()
 {
 GUILayout.EndArea();
 }
 #endregion

 #region Private methods
 private void OnDrawGizmosSelected()
 {
 foreach(Camera cam in cameras)
 {
 if (!cam)
  continue;

 if (IsShaking())
 {
  Vector3 offset = cam.worldToCameraMatrix.GetColumn(3);
  offset.z *= -1;
  offset = cam.transform.position + cam.transform.TransformPoint(offset);
  Quaternion rot = QuaternionFromMatrix(cam.worldToCameraMatrix.inverse * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1,1,-1)));
  Matrix4x4 matrix = Matrix4x4.TRS(offset, rot, cam.transform.lossyScale);
  Gizmos.matrix = matrix;
 }
 else
 {
  Matrix4x4 matrix = Matrix4x4.TRS(cam.transform.position, cam.transform.rotation, cam.transform.lossyScale);
  Gizmos.matrix = matrix;
 }

 Gizmos.DrawWireCube(Vector3.zero, shakeAmount);

 Gizmos.color = Color.cyan;

 if (cam.isOrthoGraphic)
 {
  Vector3 pos = new Vector3(0, 0, (cam.near + cam.far) / 2f);
  Vector3 size = new Vector3(cam.orthographicSize / cam.aspect, cam.orthographicSize * 2f, cam.far - cam.near);
  Gizmos.DrawWireCube(pos, size);
 }
 else
 {
  Gizmos.DrawFrustum(Vector3.zero, cam.fov, cam.far, cam.near, (.7f / cam.aspect));
 }
 }
 }

 private IEnumerator DoShake_Internal(Camera cam, Vector3 seed, int numberOfShakes, Vector3 shakeAmount, Vector3 rotationAmount, float distance, float speed, float decay, float guiShakeModifier, bool multiplyByTimeScale, System.Action callback)
 {
 // Wait for async cancel operations to complete
 if (cancelling)
 yield return null;

 // Set random values
 var mod1 = seed.x > .5f ? 1 : -1;
 var mod2 = seed.y > .5f ? 1 : -1;
 var mod3 = seed.z > .5f ? 1 : -1;

 // First shake
 if (!shaking)
 {
 shaking = true;

 if (cameraShakeStarted != null)
  cameraShakeStarted();
 }

 if (shakeCount.ContainsKey(cam))
 shakeCount[cam]++;
 else
 shakeCount.Add(cam, 1);

 // Pixel width is always based on the first camera
 float pixelWidth = GetPixelWidth(cameras[0].transform, cameras[0]);

 // Set other values
 Transform cachedTransform = cam.transform;
 Vector3 camOffset = Vector3.zero;
 Quaternion camRot = Quaternion.identity;

 int currentShakes = numberOfShakes;
 float shakeDistance = distance;
 float rotationStrength = 1;

 float startTime = Time.time;
 float scale = multiplyByTimeScale ? Time.timeScale : 1;
 float pixelScale = pixelWidth * guiShakeModifier * scale;
 Vector3 start1 = Vector2.zero;
 Quaternion startR = Quaternion.identity;
 Vector2 start2 = Vector2.zero;

 ShakeState state = new ShakeState(cachedTransform.position, cachedTransform.rotation, new Vector2(shakeRect.x, shakeRect.y));
 List stateList;

 if (states.TryGetValue(cam, out stateList))
 {
 stateList.Add(state);
 }
 else
 {
 stateList = new List();
 stateList.Add(state);
 states.Add(cam, stateList);
 }

 // Main loop
 while (currentShakes > 0)
 {
 if (checkForMinimumValues)
 {
  // Early break when rotation is less than the minimum value.
  if (rotationAmount.sqrMagnitude != 0 && rotationStrength <= minRotationValue)
  break;

  // Early break when shake amount is less than the minimum value.
  if (shakeAmount.sqrMagnitude != 0 && distance != 0 && shakeDistance <= minShakeValue)
  break;
 }

 var timer = (Time.time - startTime) * speed;

 state.shakePosition = start1 + new Vector3(
  mod1 * Mathf.Sin(timer) * (shakeAmount.x * shakeDistance * scale),
  mod2 * Mathf.Cos(timer) * (shakeAmount.y * shakeDistance * scale),
  mod3 * Mathf.Sin(timer) * (shakeAmount.z * shakeDistance * scale));

 state.shakeRotation = startR * Quaternion.Euler(
  mod1 * Mathf.Cos(timer) * (rotationAmount.x * rotationStrength * scale),
  mod2 * Mathf.Sin(timer) * (rotationAmount.y * rotationStrength * scale),
  mod3 * Mathf.Cos(timer) * (rotationAmount.z * rotationStrength * scale));

 state.guiShakePosition = new Vector2(
  start2.x - (mod1 * Mathf.Sin(timer) * (shakeAmount.x * shakeDistance * pixelScale)),
  start2.y - (mod2 * Mathf.Cos(timer) * (shakeAmount.y * shakeDistance * pixelScale)));

 camOffset = GetGeometricAvg(stateList, true);
 camRot = GetAvgRotation(stateList);
 NormalizeQuaternion(ref camRot);

 Matrix4x4 m = Matrix4x4.TRS(camOffset, camRot, new Vector3(1, 1, -1));

 cam.worldToCameraMatrix = m * cachedTransform.worldToLocalMatrix;

 var avg = GetGeometricAvg(stateList, false);

 shakeRect.x = avg.x;
 shakeRect.y = avg.y;

 if (timer > Mathf.PI * 2)
 {
  startTime = Time.time;
  shakeDistance *= (1 - Mathf.Clamp01(decay));
  rotationStrength *= (1 - Mathf.Clamp01(decay));
  currentShakes--;
 }
 yield return null;
 }

 // End conditions

 shakeCount[cam]--;

 // Last shake
 if (shakeCount[cam] == 0)
 {
 shaking = false;
 ResetState(cam.transform, cam);

 if (allCameraShakesCompleted != null)
 {
  allCameraShakesCompleted();
 }
 }
 else
 {
 stateList.Remove(state);
 }

 if (callback != null)
 callback();
 }
 private Vector3 GetGeometricAvg(List states, bool position)
 {
 float x = 0, y = 0, z = 0, l = states.Count;

 foreach(ShakeState state in states)
 {
 if (position)
 {
  x -= state.shakePosition.x;
  y -= state.shakePosition.y;
  z -= state.shakePosition.z;
 }
 else
 {
  x += state.guiShakePosition.x;
  y += state.guiShakePosition.y;
 }
 }

 return new Vector3(x / l, y / l, z / l);
 }
 private Quaternion GetAvgRotation(List states)
 {
 Quaternion avg = new Quaternion(0,0,0,0);

 foreach(ShakeState state in states)
 {
 if (Quaternion.Dot (state.shakeRotation, avg) > 0)
 {
  avg.x += state.shakeRotation.x;
  avg.y += state.shakeRotation.y;
  avg.z += state.shakeRotation.z;
  avg.w += state.shakeRotation.w;
 }
 else
 {
  avg.x += -state.shakeRotation.x;
  avg.y += -state.shakeRotation.y;
  avg.z += -state.shakeRotation.z;
  avg.w += -state.shakeRotation.w;
 }
 }

 var mag = Mathf.Sqrt(avg.x* avg.x + avg.y* avg.y + avg.z * avg.z + avg.w * avg.w);

 if (mag > 0.0001f)
 {
 avg.x /= mag;
 avg.y /= mag;
 avg.z /= mag;
 avg.w /= mag;
 }
 else
 {
 avg = states[0].shakeRotation;
 }

 return avg;
 }
 private void CheckShakeRect()
 {
 if (Screen.width != shakeRect.width || Screen.height != shakeRect.height)
 {

 shakeRect.width = Screen.width;
 shakeRect.height = Screen.height;
 }
 }
 private float GetPixelWidth(Transform cachedTransform, Camera cachedCamera)
 {
 var position = cachedTransform.position;
 var screenPos = cachedCamera.WorldToScreenPoint(position - cachedTransform.forward * .01f);
 var offset = Vector3.zero;

 if (screenPos.x > 0)
 offset = screenPos - Vector3.right;
 else
 offset = screenPos + Vector3.right;

 if (screenPos.y > 0)
 offset = screenPos - Vector3.up;
 else
 offset = screenPos + Vector3.up;

 offset = cachedCamera.ScreenToWorldPoint(offset);

 return 1f / (cachedTransform.InverseTransformPoint(position) - cachedTransform.InverseTransformPoint(offset)).magnitude;
 }
 private void ResetState(Transform cachedTransform, Camera cam)
 {
 cam.ResetWorldToCameraMatrix();

 shakeRect.x = 0;
 shakeRect.y = 0;

 states[cam].Clear();
 }
 private List offsetCache = new List(10);
 private List rotationCache = new List(10);
 private IEnumerator DoResetState(List cameras, Dictionary shakeCount, float time)
 {
 offsetCache.Clear();
 rotationCache.Clear();

 foreach(Camera cam in cameras)
 {
 offsetCache.Add((Vector3)((cam.worldToCameraMatrix * cam.transform.worldToLocalMatrix.inverse).GetColumn(3)));
 rotationCache.Add(QuaternionFromMatrix((cam.worldToCameraMatrix * cam.transform.worldToLocalMatrix.inverse).inverse * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1,1,-1))));

 if (shakeCount.ContainsKey(cam))
 {
  shakeCount[cam] = 0;
 }
 states[cam].Clear();
 }

 float t = 0;
 float x = shakeRect.x, y = shakeRect.y;
 cancelling = true;
 while (t < time)
 {
 int i = 0;
 foreach(Camera cam in cameras)
 {
  Transform cachedTransform = cam.transform;

  shakeRect.x = Mathf.Lerp(x, 0, t / time);
  shakeRect.y = Mathf.Lerp(y, 0, t / time);

  Vector3 pos = Vector3.Lerp(offsetCache[i], Vector3.zero, t / time);
  Quaternion rot = Quaternion.Slerp(rotationCache[i], cachedTransform.rotation, t / time);
  Matrix4x4 m = Matrix4x4.TRS(pos, rot, new Vector3(1, 1, -1));

  cam.worldToCameraMatrix = m * cachedTransform.worldToLocalMatrix;
  i++;
 }
 t += Time.deltaTime;
 yield return null;
 }

 foreach(Camera cam in cameras)
 {
 cam.ResetWorldToCameraMatrix();
 shakeRect.x = 0;
 shakeRect.y = 0;
 }
 this.shaking = false;
 this.cancelling = false;
 }
 #endregion

 #region Quaternion helpers
 private static Quaternion QuaternionFromMatrix(Matrix4x4 m)
 {
 return Quaternion.LookRotation(m.GetColumn(2), m.GetColumn(1));
 }
 private static void NormalizeQuaternion (ref Quaternion q)
 {
 float sum = 0; 

 for (int i = 0; i < 4; ++i)
 sum += q[i] * q[i];

 float magnitudeInverse = 1 / Mathf.Sqrt(sum);

 for (int i = 0; i < 4; ++i)
 q[i] *= magnitudeInverse;
 }
 #endregion
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Unity调用手机摄像机识别二维码

    本文实现Unity调用手机摄像,拍摄,然后识别二维码,显示二维码的内容. 需要导入一个zxing.unity.dll文件,现在这个脚本的识别数据是放在Updata里边扫描的 数据量特别大会卡  要是用的话就自己做一下一秒执行一次.我这里没有弄 下载地址:zxing.unity.dll 代码: using System.Threading; using UnityEngine; using ZXing; public class WebCameraScript : MonoBehaviour {

  • Unity3D实现控制摄像机移动

    本文实例为大家分享了Unity3D实现控制摄像机移动的具体代码,供大家参考,具体内容如下 最近公司的几个项目开发内容基本相同,很多脚本直接复制过来就可以拼接项目.之前一直是代码爱好者,能自己敲的绝对不去复制粘贴.但是开发速度确实是被耽误了,所以接下来打算把开发中常用的脚本都发到博客上.自己需要的时候直接拿来.也希望能帮到你们. unity编辑器中按住鼠标右键,在通过控制键盘的wasdqe键可以自由控制视野. 下面就是实现操作的代码: using System.Collections; using

  • Unity使用摄像机实现望远镜效果

    本文实例为大家分享了Unity使用摄像机实现望远镜效果的具体代码,供大家参考,具体内容如下 听起来挺酷炫,其实超简单,就是控制摄像机的fieldOfView: using UnityEngine; using System.Collections; public class TelesopicView : MonoBehaviour { public float zoomLevel = 2.0f; public float zoomInSpeed = 100.0f; public float z

  • unity3D实现摄像机抖动特效

    本文实例为大家分享了unity3D实现摄像机抖动的具体代码,供大家参考,具体内容如下 摄像机抖动特效 在需要的地方调用CameraShake.Shake()方法就可以 public class CameraShake : MonoBehaviour { /// /// The cameras to shake. /// public List cameras = new List(); /// /// The maximum number of shakes to perform. /// pu

  • JS实现仿QQ聊天窗口抖动特效

    JS实现仿QQ聊天窗口抖动特效 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>JavaScript层抖动效果</title> <style type="text/css"> #body{text-align:center;} #test{w

  • 基于JS简单实现手持弹幕功能+文字抖动特效代码

    前段时间抖音上有个抖动弹幕挺火的,于是决定仿写一个,话不多说,先看效果- 效果展示 GIF图看着有点模糊,但实际效果还是不错的. 第一眼看上去也不知道该咋做,那就先把要实现的功能拆解一下吧. 生成一个铺满全屏的黑色背景,写上文字,然后内容居中 实现无缝滚动 实现文字抖动特效 旋转90度(默认横屏展示) 代码如下 .html <div class="barrage-box"> <div class="text">抖动字幕</div>

  • 实例代码详解javascript实现窗口抖动及qq窗口抖动

    窗口抖动效果在很多地方都有应用,例如网易的登陆窗口就有这样的效果,当登陆失败的时候就会出现抖动效果,这不但有动感,而且让人感觉新颖,下面是一段这样的代码实例,和大家分享一下. 代码如下: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"/> <meta name="author" content="http://www.softwhy.com/&qu

  • Unity3D UGUI特效之Image高斯模糊效果

    这几天研究了下模糊特效,看了很多文章,其原理就是拿取图片或屏幕数据,然后将周围的元素和目标位置的颜色值进行一个融合计算,然后自己写了一个小小的测试程序. 这个模糊也可以分成两种,一个是自身模糊,一个是从屏幕上取值进行模糊.第一个用于一些小的列表展示,比如未解锁时,是模糊的.第二个是凸显弹框效果的,将背景都模糊掉,自己将这个稍微加强了些可以指定模糊一个位置. 针对移动平台,使用高斯模糊,其实效率不是很高,如果要很好的效果,那么速度卡:如果要速度快,那么效果达不到要求.但是还是在这里记录下,兴许以后

  • Unity3D UGUI实现翻书特效

    本文实例为大家分享了Unity3D UGUI翻书展示的具体代码,供大家参考,具体内容如下 参考大佬的,链接找不到了,找到了再加在这. 下边是Shader代码: // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Personal/PageTurning" { Properties { _Color ("Color", Color) = (

  • jQuery实现分章节锚点“回到顶部”动画特效代码

    本文实例讲述了jQuery实现分章节锚点"回到顶部"动画特效.分享给大家供大家参考,具体如下: 这里演示基于jquery实现的分章节动画实现"回到顶部"的效果,可通过 网页顶部的数字序号直接进入网页的章节,当处于第二章节的时候,网页右侧会显示竖排的控制按钮,点击按钮会回到相应章节,其实也就是定义好的锚点,当然也可回到顶部,网页上见到的回顶部大多不是这个样子,所以本款效果还挺新颖. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js

  • JavaScript实现文字跟随鼠标特效

    本文实例讲述了JavaScript如何实现文字跟随鼠标特效.分享给大家供大家参考.具体如下: 运行效果图如下: <HTML> <HEAD> <TITLE>鼠标特效--文本围绕鼠标</TITLE> </HEAD> <BODY> <br><br> <center> <font color="red"><h2>鼠标特效--文本围绕鼠标</h2><

  • jQuery文字轮播特效

    闲谈:离开学校那座象牙塔已经也有大半年的事件了,生活中不再充满了茫然只有忙碌.连续加班加点大半个月,做的活动项目终于算是告一段落了,而今天也将是考验其真正价值的时候,现在将这次开发中遇到的问题做一下总结. 项目背景: 这次的项目主要是做一次全国酒店人气排名的营销活动,主要是基于在微信中传播,预计访问量达到亿级,并发做到2000+/s,且有不少的容错预案,我这次主要负责前端首页方面的展示效果. 功能点: 文字无缝轮播(不要在意为什么在移动端还会有这样的需求) 当一说到文字无缝滚动时,大家最先想到的

随机推荐