Created
July 26, 2017 02:07
-
-
Save cabbibo/6101abe1c30788c940913f25c4221180 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class Cloak : MonoBehaviour { | |
//public HumanBuffer humanBuffer; | |
// | |
//public GameObject hand1; | |
//public GameObject hand2; | |
public float Radius; | |
public float StartTime; | |
public Color color; | |
public float gravity; | |
public float attractToHand; | |
public float repelFromHand; | |
// How the donut looks | |
public Shader shader; | |
public Shader debugShader; | |
// How the donut feels | |
public ComputeShader constraintPass; | |
public ComputeShader normalPass; | |
public ComputeShader forcePass; | |
public Texture2D normalMap; | |
public Cubemap cubeMap; | |
public float clothSize = 1; | |
public float startingHeight = 1; | |
private Vector3 v1; | |
private Vector3 v2; | |
private Vector3 bodyPos; | |
public ComputeBuffer _vertBuffer; | |
public ComputeBuffer _transformBuffer; | |
private ComputeBuffer _upLinkBuffer; | |
private ComputeBuffer _rightLinkBuffer; | |
private ComputeBuffer _diagonalDownLinkBuffer; | |
private ComputeBuffer _diagonalUpLinkBuffer; | |
public Material material; | |
private Material debugMaterial; | |
private const int threadX = 4; | |
private const int threadY = 4; | |
private const int threadZ = 4; | |
private const int strideX = 4; | |
private const int strideY = 4; | |
private const int strideZ = 4; | |
private int gridX { get { return threadX * strideX; } } | |
private int gridY { get { return threadY * strideY; } } | |
private int gridZ { get { return threadZ * strideZ; } } | |
private int vertexCount { get { return gridX * gridY * gridZ; } } | |
public int ribbonWidth = 64; | |
public int ribbonLength { get { return (int)Mathf.Floor( (float)vertexCount / ribbonWidth ); } } | |
private int _kernelforce; | |
private int _kernelconstraint; | |
private int _kernelnormal; | |
private float[] inValues; | |
private float[] transformValues; | |
private float oTime = 0; | |
struct Vert{ | |
public Vector3 pos; | |
public Vector3 oPos; | |
public Vector3 ogPos; | |
public Vector3 norm; | |
public Vector2 uv; | |
public float mass; | |
public float[] ids; | |
public Vector3 debug; | |
}; | |
struct Link{ | |
public float id1; | |
public float id2; | |
public float distance; | |
public float stiffness; | |
} | |
private int VertStructSize = 3 + 3 + 3 + 3 + 2 + 1 + 8 + 3; | |
private int LinkStructSize = 1 + 1 + 1 + 1; | |
// private float oTime; | |
// Use this for initialization | |
void Start () { | |
//HumanBuffer = GameObject.Find("HumanBuffer"); | |
//EventManager.OnTriggerDown += OnTriggerDown; | |
oTime = Time.time; | |
transformValues = new float[ 16 ]; | |
createBuffers(); | |
createMaterial(); | |
_kernelforce = forcePass.FindKernel("CSMain"); | |
_kernelnormal = normalPass.FindKernel("CSMain"); | |
_kernelconstraint = constraintPass.FindKernel("CSMain"); | |
forcePass.SetInt( "_Reset" , 0 ); | |
forcePass.SetInt( "_Ended" , 0 ); | |
// Dispatch(); | |
OnTriggerDown(gameObject); | |
Camera.onPostRender += Render; | |
} | |
public void OnTriggerDown( GameObject g ){ | |
forcePass.SetInt( "_Reset" , 1 ); | |
Dispatch(); | |
//Dispatch(); | |
//Dispatch(); | |
forcePass.SetInt( "_Reset" , 0); | |
} | |
public void FixedUpdate(){ | |
Dispatch(); | |
} | |
//When this GameObject is disabled we must release the buffers or else Unity complains. | |
private void OnDisable(){ | |
Camera.onPostRender -= Render; | |
ReleaseBuffer(); | |
} | |
//For some reason I made this method to create a material from the attached shader. | |
private void createMaterial(){ | |
material = new Material( shader ); | |
debugMaterial = new Material( debugShader ); | |
} | |
//Remember to release buffers and destroy the material when play has been stopped. | |
void ReleaseBuffer(){ | |
_vertBuffer.Release(); | |
_transformBuffer.Release(); | |
_upLinkBuffer.Release(); | |
_rightLinkBuffer.Release(); | |
_diagonalUpLinkBuffer.Release(); | |
_diagonalDownLinkBuffer.Release(); | |
DestroyImmediate( material ); | |
DestroyImmediate( debugMaterial ); | |
} | |
//After all rendering is complete we dispatch the compute shader and then set the material before drawing with DrawProcedural | |
//this just draws the "mesh" as a set of points | |
public void Render(Camera camera) { | |
int numVertsTotal = (ribbonWidth) * 3 * 2 * (ribbonLength-1); | |
material.SetPass(0); | |
material.SetInt("_Large" , 0 ); | |
material.SetBuffer("buf_Points", _vertBuffer); | |
material.SetColor("_Color", color); | |
//material.SetBuffer("shapeBuffer", PF.pillows._shapeBuffer); | |
// | |
//material.SetInt( "_NumberHands" , PF.handBufferInfo.GetComponent<HandBuffer>().numberHands ); | |
//material.SetBuffer( "handBuffer" , PF.handBufferInfo.GetComponent<HandBuffer>()._handBuffer ); | |
//material.SetFloat( "_FullEnd" , PF.fullEnd ); | |
//material.SetFloat("_ClothDown" , PF.clothDown ); | |
material.SetInt( "_RibbonWidth" , ribbonWidth ); | |
material.SetInt( "_RibbonLength" , ribbonLength ); | |
material.SetInt( "_TotalVerts" , vertexCount ); | |
//material.SetInt( "_NumShapes" , PF.pillows.Shapes.Length ); | |
//material.SetFloat("_Height" , PF.pillows.tallestPoint ); | |
//material.SetFloat("_Width" , PF.pillows.widestPoint ); | |
//material.SetFloat("_Special" , PF.special ); | |
material.SetTexture( "_NormalMap" , normalMap); | |
material.SetTexture( "_CubeMap" , cubeMap ); | |
material.SetMatrix("worldMat", transform.localToWorldMatrix); | |
material.SetMatrix("invWorldMat", transform.worldToLocalMatrix); | |
Graphics.DrawProcedural(MeshTopology.Triangles, numVertsTotal); | |
} | |
private Vector3 getVertPosition( float col , float row ){ | |
float uvX = col / ribbonWidth; | |
float uvY = row / ribbonLength; | |
float angle = uvX * 2 * Mathf.PI; | |
float radius = (Mathf.Pow( uvY , .5f )+.2f) * Radius; | |
float x = Mathf.Cos( angle ) * radius; | |
float y = Mathf.Sin( angle ) * radius; | |
return new Vector3( x * clothSize , 0 , y * clothSize ); | |
} | |
private void createBuffers() { | |
_transformBuffer = new ComputeBuffer( 1 , 16* sizeof(float)); | |
_vertBuffer = new ComputeBuffer( vertexCount , VertStructSize * sizeof(float)); | |
_upLinkBuffer = new ComputeBuffer( vertexCount / 2 , LinkStructSize * sizeof(float)); | |
_rightLinkBuffer = new ComputeBuffer( vertexCount / 2 , LinkStructSize * sizeof(float)); | |
_diagonalDownLinkBuffer = new ComputeBuffer( vertexCount / 2 , LinkStructSize * sizeof(float)); | |
_diagonalUpLinkBuffer = new ComputeBuffer( vertexCount / 2 , LinkStructSize * sizeof(float)); | |
float lRight = clothSize / (float)ribbonWidth; | |
float lUp = clothSize / (float)ribbonLength; | |
Vector2 n = new Vector2( lRight , lUp ); | |
float lDia = n.magnitude; | |
inValues = new float[ VertStructSize * vertexCount]; | |
float[] upLinkValues = new float[ LinkStructSize * vertexCount / 2 ]; | |
float[] rightLinkValues = new float[ LinkStructSize * vertexCount / 2 ]; | |
float[] diagonalDownLinkValues = new float[ LinkStructSize * vertexCount / 2 ]; | |
float[] diagonalUpLinkValues = new float[ LinkStructSize * vertexCount / 2 ]; | |
// Used for assigning to our buffer; | |
int index = 0; | |
int indexOG = 0; | |
int li1= 0; | |
int li2= 0; | |
int li3= 0; | |
int li4= 0; | |
/* // second rite up here | |
u dU x . r | |
. . // third rite down here | |
x . r x . r | |
. | |
dD | |
*/ | |
for (int z = 0; z < gridZ; z++) { | |
for (int y = 0; y < gridY; y++) { | |
for (int x = 0; x < gridX; x++) { | |
int id = x + y * gridX + z * gridX * gridY; | |
float col = (float)(id % ribbonWidth ); | |
float row = Mathf.Floor( ((float)id +0.01f) / ribbonWidth); | |
float uvX = col / ribbonWidth; | |
float uvY = row / ribbonLength; | |
float stiffness = uvY; | |
Vector3 fVec = getVertPosition( col , row ); | |
if( row % 2 == 0 ){ | |
Vector3 pos1; Vector3 pos2; | |
pos1 = fVec; | |
pos2 = getVertPosition( col + 0 , row +1 ); | |
stiffness = (row + .5f ) / ribbonLength; | |
upLinkValues[li1++] = id; | |
upLinkValues[li1++] = convertToID( col + 0 , row + 1 ); | |
upLinkValues[li1++] = ( pos1 - pos2 ).magnitude; | |
upLinkValues[li1++] = stiffness; | |
// Because of the way the right links | |
// are made, we need to alternate them, | |
// and flip flop them back and forth | |
// so they are not writing to the same | |
// positions during the same path! | |
float id1 , id2; | |
float fDist; | |
if( col % 2 == 0 ){ | |
id1 = id; | |
id2 = convertToID( col + 1 , row + 0 ); | |
pos1 = fVec; | |
pos2 = getVertPosition( col + 1 , row +0 ); | |
stiffness = (row + 0 ) / ribbonLength; | |
}else{ | |
id1 = convertToID( col + 0 , row + 1 ); | |
id2 = convertToID( col + 1 , row + 1 ); | |
pos1 = getVertPosition( col + 0 , row +1 ); | |
pos2 = getVertPosition( col + 1 , row +1 ); | |
stiffness = (row+1 ) / ribbonLength; | |
} | |
rightLinkValues[li2++] = id1; | |
rightLinkValues[li2++] = id2; | |
rightLinkValues[li2++] = ( pos1 - pos2 ).magnitude; | |
rightLinkValues[li2++] = stiffness; | |
pos1 = fVec; | |
pos2 = getVertPosition( col -1 , row -1 ); | |
stiffness = (row-.5f) / ribbonLength; | |
diagonalDownLinkValues[li3++] = id; | |
diagonalDownLinkValues[li3++] = convertToID( col - 1 , row - 1 ); | |
diagonalDownLinkValues[li3++] = ( pos1 - pos2 ).magnitude; | |
diagonalDownLinkValues[li3++] = stiffness; | |
pos1 = fVec; | |
pos2 = getVertPosition( col +1 , row +1 ); | |
stiffness = (row+.5f) / ribbonLength; | |
diagonalUpLinkValues[li4++] = id; | |
diagonalUpLinkValues[li4++] = convertToID( col + 1 , row + 1 ); | |
diagonalUpLinkValues[li4++] = ( pos1 - pos2 ).magnitude; | |
diagonalUpLinkValues[li4++] = stiffness; | |
} | |
Vert vert = new Vert(); | |
float stuck = 0; | |
if( fVec.magnitude < .2f ){ | |
stuck = 1; | |
fVec += new Vector3( 0, .2f - fVec.magnitude , 0 ); | |
fVec = fVec.normalized * .2f; | |
//print( fVec ); | |
} | |
vert.pos = fVec * 1.000001f; | |
vert.oPos = fVec- new Vector3( 0 , 0 , 0 ); | |
vert.ogPos = fVec ; | |
vert.norm = new Vector3( 0 , 1 , 0 ); | |
vert.uv = new Vector2( uvX , uvY ); | |
vert.mass = 0.3f; | |
if( col == 0 || col == ribbonWidth || row == 0 || row == ribbonLength ){ | |
vert.mass = 2.0f; | |
} | |
vert.ids = new float[8]; | |
vert.ids[0] = convertToID( col + 1 , row + 0 ); | |
vert.ids[1] = convertToID( col + 1 , row - 1 ); | |
vert.ids[2] = convertToID( col + 0 , row - 1 ); | |
vert.ids[3] = convertToID( col - 1 , row - 1 ); | |
vert.ids[4] = convertToID( col - 1 , row - 0 ); | |
vert.ids[5] = convertToID( col - 1 , row + 1 ); | |
vert.ids[6] = convertToID( col - 0 , row + 1 ); | |
vert.ids[7] = convertToID( col + 1 , row + 1 ); | |
vert.debug = new Vector3(stuck,1,0); | |
//Vector2 d = new Vector2(vert.uv.x-.5f,vert.uv.y-.5f); | |
// | |
//if(d.magnitude < .02 ){ | |
// vert.debug= new Vector3(1,1,0); | |
//} | |
inValues[index++] = vert.pos.x; | |
inValues[index++] = vert.pos.y; | |
inValues[index++] = vert.pos.z; | |
inValues[index++] = vert.oPos.x; | |
inValues[index++] = vert.oPos.y; | |
inValues[index++] = vert.oPos.z; | |
inValues[index++] = vert.ogPos.x; | |
inValues[index++] = vert.ogPos.y; | |
inValues[index++] = vert.ogPos.z; | |
inValues[index++] = vert.norm.x; | |
inValues[index++] = vert.norm.y; | |
inValues[index++] = vert.norm.z; | |
inValues[index++] = vert.uv.x; | |
inValues[index++] = vert.uv.y; | |
inValues[index++] = 0; | |
inValues[index++] = vert.ids[0]; | |
inValues[index++] = vert.ids[1]; | |
inValues[index++] = vert.ids[2]; | |
inValues[index++] = vert.ids[3]; | |
inValues[index++] = vert.ids[4]; | |
inValues[index++] = vert.ids[5]; | |
inValues[index++] = vert.ids[6]; | |
inValues[index++] = vert.ids[7]; | |
inValues[index++] = vert.debug.x; | |
inValues[index++] = vert.debug.y; | |
inValues[index++] = vert.debug.z; | |
} | |
} | |
} | |
_vertBuffer.SetData(inValues); | |
_upLinkBuffer.SetData(upLinkValues); | |
_rightLinkBuffer.SetData(rightLinkValues); | |
_diagonalUpLinkBuffer.SetData(diagonalUpLinkValues); | |
_diagonalDownLinkBuffer.SetData(diagonalDownLinkValues); | |
} | |
public float convertToID( float col , float row ){ | |
float id; | |
if( col >= ribbonWidth ){ col -= ribbonWidth;} | |
if( col < 0 ){ col += ribbonWidth; } | |
// Instead of returning negative numbers, | |
// we are going to connect to other side of cloth | |
// to make it a tube! | |
if( row >= ribbonLength ){ return -10; } | |
if( row < 0 ){ return -20; } | |
id = row * ribbonWidth + col; | |
return id; | |
} | |
private void doConstraint( float v , int offset , ComputeBuffer b ){ | |
// Which link in compute are we doing | |
constraintPass.SetInt("_Offset" , offset ); | |
constraintPass.SetFloat("_Multiplier" , v ); | |
constraintPass.SetBuffer( _kernelconstraint , "linkBuffer" , b ); | |
//TODO: only need to dispatch for 1/9th of the buffer size! | |
constraintPass.Dispatch( _kernelconstraint , strideX / 2 , strideY , strideZ ); | |
} | |
private void assignTransform(){ | |
Matrix4x4 m = transform.localToWorldMatrix; | |
float[] matrixFloats = new float[] | |
{ | |
m[0,0], m[1, 0], m[2, 0], m[3, 0], | |
m[0,1], m[1, 1], m[2, 1], m[3, 1], | |
m[0,2], m[1, 2], m[2, 2], m[3, 2], | |
m[0,3], m[1, 3], m[2, 3], m[3, 3] | |
}; | |
forcePass.SetFloats("transform", matrixFloats); | |
} | |
private void Dispatch() { | |
v1 = transform.TransformPoint(new Vector3( 0 , -.1f , -.2f )); | |
v2 = new Vector3( 0 , v1.y * .15f , 0 ); | |
v1 = v1 - v2; | |
bodyPos = v1;//transform.TransformPoint( v1 ); | |
assignTransform(); | |
forcePass.SetFloat( "_DeltaTime" , Time.time - oTime ); | |
forcePass.SetFloat( "_Time" , Time.time + StartTime ); | |
//forcePass.SetFloat( "_Reset" , ); | |
//forcePass.SetVector( "_ChestPosition" , bodyPos ); | |
//forcePass.SetVector( "_Hand1" , hand1.transform.position ); | |
//forcePass.SetVector( "_Hand2" , hand2.transform.position ); | |
forcePass.SetFloat("_AttractToHand", attractToHand); | |
forcePass.SetFloat("_RepelFromHand", repelFromHand); | |
forcePass.SetFloat("_Gravity", gravity); | |
///oTime = Time.time; | |
forcePass.SetInt( "_RibbonWidth" , ribbonWidth ); | |
forcePass.SetInt( "_RibbonLength" , ribbonLength ); | |
// print( PF.pillows); | |
//forcePass.SetInt( "_NumShapes" , PF.pillows.Shapes.Length ); | |
//forcePass.SetInt( "_NumberHands" , PF.handBufferInfo.GetComponent<HandBuffer>().numberHands ); | |
//print( HumanBuffer.GetComponent<HumanBuffer>().numberHumans ); | |
//forcePass.SetInt( "_NumberHumans" , humanBuffer.numberHumans ); | |
//forcePass.SetBuffer( _kernelforce , "humanBuffer" , humanBuffer._buffer ); | |
forcePass.SetBuffer( _kernelforce , "vertBuffer" , _vertBuffer ); | |
forcePass.SetBuffer( _kernelforce , "transformBuffer" , _transformBuffer ); | |
//if( PF.pillows._shapeBuffer != null ){ | |
// forcePass.SetBuffer( _kernelforce , "shapeBuffer" , PF.pillows._shapeBuffer ); | |
//} | |
//forcePass.SetBuffer( _kernelforce , "handBuffer" , PF.handBufferInfo.GetComponent<HandBuffer>()._handBuffer ); | |
forcePass.Dispatch( _kernelforce , strideX , strideY , strideZ ); | |
constraintPass.SetInt( "_RibbonWidth" , ribbonWidth ); | |
constraintPass.SetInt( "_RibbonLength" , ribbonLength ); | |
constraintPass.SetBuffer( _kernelconstraint , "vertBuffer" , _vertBuffer ); | |
doConstraint( 1 , 1 , _upLinkBuffer ); | |
doConstraint( 1 , 1 , _rightLinkBuffer ); | |
doConstraint( 1 , 1 , _diagonalDownLinkBuffer ); | |
doConstraint( 1 , 1 , _diagonalUpLinkBuffer ); | |
doConstraint( 1 , 0 , _upLinkBuffer ); | |
doConstraint( 1 , 0 , _rightLinkBuffer ); | |
doConstraint( 1 , 0 , _diagonalDownLinkBuffer ); | |
doConstraint( 1 , 0 , _diagonalUpLinkBuffer ); | |
//calculate our normals | |
normalPass.SetBuffer( _kernelnormal , "vertBuffer" , _vertBuffer ); | |
normalPass.Dispatch( _kernelnormal , strideX , strideY , strideZ ); | |
oTime = Time.time; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment