Repository: NoxWings/Cable-Component Branch: master Commit: 8415e8c7ce78 Files: 35 Total size: 15.8 KB Directory structure: gitextract_2prq106o/ ├── .gitignore ├── Assets/ │ ├── CableComponent/ │ │ ├── Material/ │ │ │ ├── CableMaterial.mat │ │ │ ├── CableMaterial.mat.meta │ │ │ ├── FloorMaterial.mat │ │ │ └── FloorMaterial.mat.meta │ │ ├── Material.meta │ │ ├── README.md │ │ ├── README.md.meta │ │ ├── Scenes/ │ │ │ ├── TestScene.unity │ │ │ └── TestScene.unity.meta │ │ ├── Scenes.meta │ │ ├── Scripts/ │ │ │ ├── CableComponent.cs │ │ │ ├── CableComponent.cs.meta │ │ │ ├── CableParticle.cs │ │ │ └── CableParticle.cs.meta │ │ └── Scripts.meta │ └── CableComponent.meta ├── ProjectSettings/ │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── Physics2DSettings.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityAdsSettings.asset │ └── UnityConnectSettings.asset └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io/api/unity ### Unity ### /[Ll]ibrary/ /[Tt]emp/ /[Oo]bj/ /[Bb]uild/ /[Bb]uilds/ /Assets/AssetStoreTools* # Autogenerated VS/MD/Consulo solution and project files ExportedObj/ .consulo/ *.csproj *.unityproj *.sln *.suo *.tmp *.user *.userprefs *.pidb *.booproj *.svd # Unity3D generated meta files *.pidb.meta # Unity3D Generated File On Crash Reports sysinfo.txt # Builds *.apk *.unitypackage ================================================ FILE: Assets/CableComponent/Material/CableMaterial.mat ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!21 &2100000 Material: serializedVersion: 6 m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_Name: CableMaterial m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_ShaderKeywords: _EMISSION m_LightmapFlags: 1 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: serializedVersion: 2 m_TexEnvs: - first: name: _BumpMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _DetailAlbedoMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _DetailMask second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _DetailNormalMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _EmissionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _MainTex second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _MetallicGlossMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _OcclusionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _ParallaxMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} m_Floats: - first: name: _BumpScale second: 1 - first: name: _Cutoff second: 0.5 - first: name: _DetailNormalMapScale second: 1 - first: name: _DstBlend second: 0 - first: name: _GlossMapScale second: 1 - first: name: _Glossiness second: 0 - first: name: _GlossyReflections second: 1 - first: name: _Metallic second: 0 - first: name: _Mode second: 0 - first: name: _OcclusionStrength second: 1 - first: name: _Parallax second: 0.02 - first: name: _SmoothnessTextureChannel second: 0 - first: name: _SpecularHighlights second: 1 - first: name: _SrcBlend second: 1 - first: name: _UVSec second: 0 - first: name: _ZWrite second: 1 m_Colors: - first: name: _Color second: {r: 0.20588237, g: 0.20588237, b: 0.20588237, a: 1} - first: name: _EmissionColor second: {r: 0, g: 0, b: 0, a: 1} ================================================ FILE: Assets/CableComponent/Material/CableMaterial.mat.meta ================================================ fileFormatVersion: 2 guid: e20a2186cc0884c4186cd848b087703e timeCreated: 1444228819 licenseType: Free NativeFormatImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Material/FloorMaterial.mat ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!21 &2100000 Material: serializedVersion: 6 m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_Name: FloorMaterial m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_ShaderKeywords: _EMISSION m_LightmapFlags: 1 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: serializedVersion: 2 m_TexEnvs: - first: name: _BumpMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _DetailAlbedoMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _DetailMask second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _DetailNormalMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _EmissionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _MainTex second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _MetallicGlossMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _OcclusionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - first: name: _ParallaxMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} m_Floats: - first: name: _BumpScale second: 1 - first: name: _Cutoff second: 0.5 - first: name: _DetailNormalMapScale second: 1 - first: name: _DstBlend second: 0 - first: name: _GlossMapScale second: 1 - first: name: _Glossiness second: 0 - first: name: _GlossyReflections second: 1 - first: name: _Metallic second: 0 - first: name: _Mode second: 0 - first: name: _OcclusionStrength second: 1 - first: name: _Parallax second: 0.02 - first: name: _SmoothnessTextureChannel second: 0 - first: name: _SpecularHighlights second: 1 - first: name: _SrcBlend second: 1 - first: name: _UVSec second: 0 - first: name: _ZWrite second: 1 m_Colors: - first: name: _Color second: {r: 0.29411763, g: 0.29411763, b: 0.29411763, a: 1} - first: name: _EmissionColor second: {r: 0, g: 0, b: 0, a: 1} ================================================ FILE: Assets/CableComponent/Material/FloorMaterial.mat.meta ================================================ fileFormatVersion: 2 guid: 7a2ff32d7b3cb31498d778f8a3b29e1a timeCreated: 1478455142 licenseType: Free NativeFormatImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Material.meta ================================================ fileFormatVersion: 2 guid: 6d5cbb863b6bf034d94a7b4b35dcd644 folderAsset: yes timeCreated: 1444228621 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/README.md ================================================ # UnityCableComponent "Cable Component" for Unity3D based on verlet integration just like in UE4. ================================================ FILE: Assets/CableComponent/README.md.meta ================================================ fileFormatVersion: 2 guid: 6b0a6c9ca9397e741af71e18838577a3 timeCreated: 1444252217 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Scenes/TestScene.unity.meta ================================================ fileFormatVersion: 2 guid: d01135766194e404088cea9fed636792 timeCreated: 1444229211 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Scenes.meta ================================================ fileFormatVersion: 2 guid: 5dd7385a29188264eb039571608a43e3 folderAsset: yes timeCreated: 1444228613 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Scripts/CableComponent.cs ================================================ using UnityEngine; using System; using System.Collections; public class CableComponent : MonoBehaviour { #region Class members [SerializeField] private Transform endPoint; [SerializeField] private Material cableMaterial; // Cable config [SerializeField] private float cableLength = 0.5f; [SerializeField] private int totalSegments = 5; [SerializeField] private float segmentsPerUnit = 2f; private int segments = 0; [SerializeField] private float cableWidth = 0.1f; // Solver config [SerializeField] private int verletIterations = 1; [SerializeField] private int solverIterations = 1; //[Range(0,3)] [SerializeField] private float stiffness = 1f; private LineRenderer line; private CableParticle[] points; #endregion #region Initial setup void Start() { InitCableParticles(); InitLineRenderer(); } /** * Init cable particles * * Creates the cable particles along the cable length * and binds the start and end tips to their respective game objects. */ void InitCableParticles() { // Calculate segments to use if (totalSegments > 0) segments = totalSegments; else segments = Mathf.CeilToInt (cableLength * segmentsPerUnit); Vector3 cableDirection = (endPoint.position - transform.position).normalized; float initialSegmentLength = cableLength / segments; points = new CableParticle[segments + 1]; // Foreach point for (int pointIdx = 0; pointIdx <= segments; pointIdx++) { // Initial position Vector3 initialPosition = transform.position + (cableDirection * (initialSegmentLength * pointIdx)); points[pointIdx] = new CableParticle(initialPosition); } // Bind start and end particles with their respective gameobjects CableParticle start = points[0]; CableParticle end = points[segments]; start.Bind(this.transform); end.Bind(endPoint.transform); } /** * Initialized the line renderer */ void InitLineRenderer() { line = this.gameObject.AddComponent(); line.SetWidth(cableWidth, cableWidth); line.SetVertexCount(segments + 1); line.material = cableMaterial; line.GetComponent().enabled = true; } #endregion #region Render Pass void Update() { RenderCable(); } /** * Render Cable * * Update every particle position in the line renderer. */ void RenderCable() { for (int pointIdx = 0; pointIdx < segments + 1; pointIdx++) { line.SetPosition(pointIdx, points [pointIdx].Position); } } #endregion #region Verlet integration & solver pass void FixedUpdate() { for (int verletIdx = 0; verletIdx < verletIterations; verletIdx++) { VerletIntegrate(); SolveConstraints(); } } /** * Verler integration pass * * In this step every particle updates its position and speed. */ void VerletIntegrate() { Vector3 gravityDisplacement = Time.fixedDeltaTime * Time.fixedDeltaTime * Physics.gravity; foreach (CableParticle particle in points) { particle.UpdateVerlet(gravityDisplacement); } } /** * Constrains solver pass * * In this step every constraint is addressed in sequence */ void SolveConstraints() { // For each solver iteration.. for (int iterationIdx = 0; iterationIdx < solverIterations; iterationIdx++) { SolveDistanceConstraint(); SolveStiffnessConstraint(); } } #endregion #region Solver Constraints /** * Distance constraint for each segment / pair of particles **/ void SolveDistanceConstraint() { float segmentLength = cableLength / segments; for (int SegIdx = 0; SegIdx < segments; SegIdx++) { CableParticle particleA = points[SegIdx]; CableParticle particleB = points[SegIdx + 1]; // Solve for this pair of particles SolveDistanceConstraint(particleA, particleB, segmentLength); } } /** * Distance Constraint * * This is the main constrains that keeps the cable particles "tied" together. */ void SolveDistanceConstraint(CableParticle particleA, CableParticle particleB, float segmentLength) { // Find current vector between particles Vector3 delta = particleB.Position - particleA.Position; // float currentDistance = delta.magnitude; float errorFactor = (currentDistance - segmentLength) / currentDistance; // Only move free particles to satisfy constraints if (particleA.IsFree() && particleB.IsFree()) { particleA.Position += errorFactor * 0.5f * delta; particleB.Position -= errorFactor * 0.5f * delta; } else if (particleA.IsFree()) { particleA.Position += errorFactor * delta; } else if (particleB.IsFree()) { particleB.Position -= errorFactor * delta; } } /** * Stiffness constraint **/ void SolveStiffnessConstraint() { float distance = (points[0].Position - points[segments].Position).magnitude; if (distance > cableLength) { foreach (CableParticle particle in points) { SolveStiffnessConstraint(particle, distance); } } } /** * TODO: I'll implement this constraint to reinforce cable stiffness * * As the system has more particles, the verlet integration aproach * may get way too loose cable simulation. This constraint is intended * to reinforce the cable stiffness. * // throw new System.NotImplementedException (); **/ void SolveStiffnessConstraint(CableParticle cableParticle, float distance) { } #endregion } ================================================ FILE: Assets/CableComponent/Scripts/CableComponent.cs.meta ================================================ fileFormatVersion: 2 guid: a262c1cd876da934d86e2a8ee0089db2 timeCreated: 1444228668 licenseType: Free MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Scripts/CableParticle.cs ================================================ using UnityEngine; using System.Collections; public class CableParticle { #region Class member variables private Vector3 _position, _oldPosition; private Transform _boundTo = null; private Rigidbody _boundRigid = null; #endregion #region Properties public Vector3 Position { get { return _position; } set { _position = value; } } public Vector3 Velocity { get { return (_position - _oldPosition); } } #endregion #region Constructor public CableParticle(Vector3 newPosition) { _oldPosition = _position = newPosition; } #endregion #region Public functions public void UpdateVerlet(Vector3 gravityDisplacement) { if (this.IsBound()) { if (_boundRigid == null) { this.UpdatePosition(_boundTo.position); } else { switch (_boundRigid.interpolation) { case RigidbodyInterpolation.Interpolate: this.UpdatePosition(_boundRigid.position + (_boundRigid.velocity * Time.fixedDeltaTime) / 2); break; case RigidbodyInterpolation.None: default: this.UpdatePosition(_boundRigid.position + _boundRigid.velocity * Time.fixedDeltaTime); break; } } } else { Vector3 newPosition = this.Position + this.Velocity + gravityDisplacement; this.UpdatePosition(newPosition); } } public void UpdatePosition(Vector3 newPos) { _oldPosition = _position; _position = newPos; } public void Bind(Transform to) { _boundTo = to; _boundRigid = to.GetComponent(); _oldPosition = _position = _boundTo.position; } public void UnBind() { _boundTo = null; _boundRigid = null; } public bool IsFree() { return (_boundTo == null); } public bool IsBound() { return (_boundTo != null); } #endregion } ================================================ FILE: Assets/CableComponent/Scripts/CableParticle.cs.meta ================================================ fileFormatVersion: 2 guid: c434c9bd6de363c46b5fae6ed070f2d2 timeCreated: 1444522184 licenseType: Free MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent/Scripts.meta ================================================ fileFormatVersion: 2 guid: dc842025b760e42469c4ef436fecd3c9 folderAsset: yes timeCreated: 1444228637 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Assets/CableComponent.meta ================================================ fileFormatVersion: 2 guid: 6c878aafa9e93a146a8d53329313ea55 folderAsset: yes timeCreated: 1444228571 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: ProjectSettings/ProjectVersion.txt ================================================ m_EditorVersion: 5.4.0f3 m_StandardAssetsVersion: 0 ================================================ FILE: README.md ================================================ # Cable-Component Unity cable component implementation similar to the Unreal Engine one based on verlet integration. This project is a simple and optimized implementation of cable physics in Unity3D, it uses verlet integration[1] to achieve the physics simulation just like UE4 approach[2]. The rendering part still has some work to be done as it is currently using a simple line renderer. Ideally it should use a procedural cable generation approach but it wasn't main the purpouse of this little experiment. [![Cable Component Video](https://j.gifs.com/GZQ5gQ.gif)](https://www.youtube.com/watch?v=VN21ROvrF2k) [1] https://en.wikipedia.org/wiki/Verlet_integration [2] https://www.unrealengine.com/blog/cable-component-plugin-for-ue4