1617a3babSopenharmony_ci/*
2617a3babSopenharmony_ciThe MIT License (MIT)
3617a3babSopenharmony_ci
4617a3babSopenharmony_ciCopyright (c) 2022 Google LLC
5617a3babSopenharmony_ciCopyright (c) 2022 Sascha Willems
6617a3babSopenharmony_ci
7617a3babSopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a copy
8617a3babSopenharmony_ciof this software and associated documentation files (the "Software"), to deal
9617a3babSopenharmony_ciin the Software without restriction, including without limitation the rights
10617a3babSopenharmony_cito use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11617a3babSopenharmony_cicopies of the Software, and to permit persons to whom the Software is
12617a3babSopenharmony_cifurnished to do so, subject to the following conditions:
13617a3babSopenharmony_ci
14617a3babSopenharmony_ciThe above copyright notice and this permission notice shall be included in all
15617a3babSopenharmony_cicopies or substantial portions of the Software.
16617a3babSopenharmony_ci
17617a3babSopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18617a3babSopenharmony_ciIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19617a3babSopenharmony_ciFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20617a3babSopenharmony_ciAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21617a3babSopenharmony_ciLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22617a3babSopenharmony_ciOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23617a3babSopenharmony_ciSOFTWARE.
24617a3babSopenharmony_ci*/
25617a3babSopenharmony_ci
26617a3babSopenharmony_cistruct Particle {
27617a3babSopenharmony_ci	float4 pos;
28617a3babSopenharmony_ci	float4 vel;
29617a3babSopenharmony_ci	float4 uv;
30617a3babSopenharmony_ci	float4 normal;
31617a3babSopenharmony_ci	float pinned;
32617a3babSopenharmony_ci};
33617a3babSopenharmony_ci
34617a3babSopenharmony_ci[[vk::binding(0)]]
35617a3babSopenharmony_ciStructuredBuffer<Particle> particleIn;
36617a3babSopenharmony_ci[[vk::binding(1)]]
37617a3babSopenharmony_ciRWStructuredBuffer<Particle> particleOut;
38617a3babSopenharmony_ci
39617a3babSopenharmony_cistruct UBO
40617a3babSopenharmony_ci{
41617a3babSopenharmony_ci	float deltaT;
42617a3babSopenharmony_ci	float particleMass;
43617a3babSopenharmony_ci	float springStiffness;
44617a3babSopenharmony_ci	float damping;
45617a3babSopenharmony_ci	float restDistH;
46617a3babSopenharmony_ci	float restDistV;
47617a3babSopenharmony_ci	float restDistD;
48617a3babSopenharmony_ci	float sphereRadius;
49617a3babSopenharmony_ci	float4 spherePos;
50617a3babSopenharmony_ci	float4 gravity;
51617a3babSopenharmony_ci	int2 particleCount;
52617a3babSopenharmony_ci};
53617a3babSopenharmony_ci
54617a3babSopenharmony_cicbuffer ubo : register(b2)
55617a3babSopenharmony_ci{
56617a3babSopenharmony_ci	UBO params;
57617a3babSopenharmony_ci};
58617a3babSopenharmony_ci
59617a3babSopenharmony_ci#ifdef GLSLANG
60617a3babSopenharmony_cilayout ( push_constant ) cbuffer PushConstants
61617a3babSopenharmony_ci{
62617a3babSopenharmony_ci	uint calculateNormals;
63617a3babSopenharmony_ci} pushConstants;
64617a3babSopenharmony_ci#else
65617a3babSopenharmony_cistruct PushConstants
66617a3babSopenharmony_ci{
67617a3babSopenharmony_ci	uint calculateNormals;
68617a3babSopenharmony_ci};
69617a3babSopenharmony_ci
70617a3babSopenharmony_ci[[vk::push_constant]]
71617a3babSopenharmony_ciPushConstants pushConstants;
72617a3babSopenharmony_ci#endif
73617a3babSopenharmony_ci
74617a3babSopenharmony_cifloat3 springForce(float3 p0, float3 p1, float restDist)
75617a3babSopenharmony_ci{
76617a3babSopenharmony_ci	float3 dist = p0 - p1;
77617a3babSopenharmony_ci	return normalize(dist) * params.springStiffness * (length(dist) - restDist);
78617a3babSopenharmony_ci}
79617a3babSopenharmony_ci
80617a3babSopenharmony_ci[numthreads(10, 10, 1)]
81617a3babSopenharmony_civoid main(uint3 id : SV_DispatchThreadID)
82617a3babSopenharmony_ci{
83617a3babSopenharmony_ci	uint index = id.y * params.particleCount.x + id.x;
84617a3babSopenharmony_ci	if (index > params.particleCount.x * params.particleCount.y)
85617a3babSopenharmony_ci		return;
86617a3babSopenharmony_ci
87617a3babSopenharmony_ci	// Pinned?
88617a3babSopenharmony_ci	if (particleIn[index].pinned == 1.0) {
89617a3babSopenharmony_ci		particleOut[index].pos = particleOut[index].pos;
90617a3babSopenharmony_ci		particleOut[index].vel = float4(0, 0, 0, 0);
91617a3babSopenharmony_ci		return;
92617a3babSopenharmony_ci	}
93617a3babSopenharmony_ci
94617a3babSopenharmony_ci	// Initial force from gravity
95617a3babSopenharmony_ci	float3 force = params.gravity.xyz * params.particleMass;
96617a3babSopenharmony_ci
97617a3babSopenharmony_ci	float3 pos = particleIn[index].pos.xyz;
98617a3babSopenharmony_ci	float3 vel = particleIn[index].vel.xyz;
99617a3babSopenharmony_ci
100617a3babSopenharmony_ci	// Spring forces from neighboring particles
101617a3babSopenharmony_ci	// left
102617a3babSopenharmony_ci	if (id.x > 0) {
103617a3babSopenharmony_ci		force += springForce(particleIn[index-1].pos.xyz, pos, params.restDistH);
104617a3babSopenharmony_ci	}
105617a3babSopenharmony_ci	// right
106617a3babSopenharmony_ci	if (id.x < params.particleCount.x - 1) {
107617a3babSopenharmony_ci		force += springForce(particleIn[index + 1].pos.xyz, pos, params.restDistH);
108617a3babSopenharmony_ci	}
109617a3babSopenharmony_ci	// upper
110617a3babSopenharmony_ci	if (id.y < params.particleCount.y - 1) {
111617a3babSopenharmony_ci		force += springForce(particleIn[index + params.particleCount.x].pos.xyz, pos, params.restDistV);
112617a3babSopenharmony_ci	}
113617a3babSopenharmony_ci	// lower
114617a3babSopenharmony_ci	if (id.y > 0) {
115617a3babSopenharmony_ci		force += springForce(particleIn[index - params.particleCount.x].pos.xyz, pos, params.restDistV);
116617a3babSopenharmony_ci	}
117617a3babSopenharmony_ci	// upper-left
118617a3babSopenharmony_ci	if ((id.x > 0) && (id.y < params.particleCount.y - 1)) {
119617a3babSopenharmony_ci		force += springForce(particleIn[index + params.particleCount.x - 1].pos.xyz, pos, params.restDistD);
120617a3babSopenharmony_ci	}
121617a3babSopenharmony_ci	// lower-left
122617a3babSopenharmony_ci	if ((id.x > 0) && (id.y > 0)) {
123617a3babSopenharmony_ci		force += springForce(particleIn[index - params.particleCount.x - 1].pos.xyz, pos, params.restDistD);
124617a3babSopenharmony_ci	}
125617a3babSopenharmony_ci	// upper-right
126617a3babSopenharmony_ci	if ((id.x < params.particleCount.x - 1) && (id.y < params.particleCount.y - 1)) {
127617a3babSopenharmony_ci		force += springForce(particleIn[index + params.particleCount.x + 1].pos.xyz, pos, params.restDistD);
128617a3babSopenharmony_ci	}
129617a3babSopenharmony_ci	// lower-right
130617a3babSopenharmony_ci	if ((id.x < params.particleCount.x - 1) && (id.y > 0)) {
131617a3babSopenharmony_ci		force += springForce(particleIn[index - params.particleCount.x + 1].pos.xyz, pos, params.restDistD);
132617a3babSopenharmony_ci	}
133617a3babSopenharmony_ci
134617a3babSopenharmony_ci	force += (-params.damping * vel);
135617a3babSopenharmony_ci
136617a3babSopenharmony_ci	// Integrate
137617a3babSopenharmony_ci	float3 f = force * (1.0 / params.particleMass);
138617a3babSopenharmony_ci	particleOut[index].pos = float4(pos + vel * params.deltaT + 0.5 * f * params.deltaT * params.deltaT, 1.0);
139617a3babSopenharmony_ci	particleOut[index].vel = float4(vel + f * params.deltaT, 0.0);
140617a3babSopenharmony_ci
141617a3babSopenharmony_ci	// Sphere collision
142617a3babSopenharmony_ci	float3 sphereDist = particleOut[index].pos.xyz - params.spherePos.xyz;
143617a3babSopenharmony_ci	if (length(sphereDist) < params.sphereRadius + 0.01) {
144617a3babSopenharmony_ci		// If the particle is inside the sphere, push it to the outer radius
145617a3babSopenharmony_ci		particleOut[index].pos.xyz = params.spherePos.xyz + normalize(sphereDist) * (params.sphereRadius + 0.01);
146617a3babSopenharmony_ci		// Cancel out velocity
147617a3babSopenharmony_ci		particleOut[index].vel = float4(0, 0, 0, 0);
148617a3babSopenharmony_ci	}
149617a3babSopenharmony_ci
150617a3babSopenharmony_ci	// Normals
151617a3babSopenharmony_ci	if (pushConstants.calculateNormals == 1) {
152617a3babSopenharmony_ci		float3 normal = float3(0, 0, 0);
153617a3babSopenharmony_ci		float3 a, b, c;
154617a3babSopenharmony_ci		if (id.y > 0) {
155617a3babSopenharmony_ci			if (id.x > 0) {
156617a3babSopenharmony_ci				a = particleIn[index - 1].pos.xyz - pos;
157617a3babSopenharmony_ci				b = particleIn[index - params.particleCount.x - 1].pos.xyz - pos;
158617a3babSopenharmony_ci				c = particleIn[index - params.particleCount.x].pos.xyz - pos;
159617a3babSopenharmony_ci				normal += cross(a,b) + cross(b,c);
160617a3babSopenharmony_ci			}
161617a3babSopenharmony_ci			if (id.x < params.particleCount.x - 1) {
162617a3babSopenharmony_ci				a = particleIn[index - params.particleCount.x].pos.xyz - pos;
163617a3babSopenharmony_ci				b = particleIn[index - params.particleCount.x + 1].pos.xyz - pos;
164617a3babSopenharmony_ci				c = particleIn[index + 1].pos.xyz - pos;
165617a3babSopenharmony_ci				normal += cross(a,b) + cross(b,c);
166617a3babSopenharmony_ci			}
167617a3babSopenharmony_ci		}
168617a3babSopenharmony_ci		if (id.y < params.particleCount.y - 1) {
169617a3babSopenharmony_ci			if (id.x > 0) {
170617a3babSopenharmony_ci				a = particleIn[index + params.particleCount.x].pos.xyz - pos;
171617a3babSopenharmony_ci				b = particleIn[index + params.particleCount.x - 1].pos.xyz - pos;
172617a3babSopenharmony_ci				c = particleIn[index - 1].pos.xyz - pos;
173617a3babSopenharmony_ci				normal += cross(a,b) + cross(b,c);
174617a3babSopenharmony_ci			}
175617a3babSopenharmony_ci			if (id.x < params.particleCount.x - 1) {
176617a3babSopenharmony_ci				a = particleIn[index + 1].pos.xyz - pos;
177617a3babSopenharmony_ci				b = particleIn[index + params.particleCount.x + 1].pos.xyz - pos;
178617a3babSopenharmony_ci				c = particleIn[index + params.particleCount.x].pos.xyz - pos;
179617a3babSopenharmony_ci				normal += cross(a,b) + cross(b,c);
180617a3babSopenharmony_ci			}
181617a3babSopenharmony_ci		}
182617a3babSopenharmony_ci		particleOut[index].normal = float4(normalize(normal), 0.0f);
183617a3babSopenharmony_ci	}
184617a3babSopenharmony_ci}
185