sp4cemonkey

Grass Codea Simulation

Mar 28th, 2013
239
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Grass
  2.  
  3. -- Use this function to perform your initial setup
  4. function setup()
  5. displayMode(FULLSCREEN)
  6. field = mesh()
  7. --field.shader = shader("Documents:Grass")
  8. field.shader = shader(GrassShader.vertexShader, GrassShader.fragmentShader)
  9. bladeWidth = 0.15
  10. bladeHeight = 1.5
  11. midWeight = 0.2
  12. size = vec2(30,30)
  13. touchScale = 10
  14. numBlades = 10000
  15.  
  16. field.shader.bladeHeight = bladeHeight
  17. createField(field, size,numBlades)
  18. generateTouchMesh(size)
  19. --pressureZones are x,y then radius and finally type (1 = round pushout)
  20. field.shader.pressureZone = vec4(-1000,-1000,0,0)
  21.  
  22. campos = vec2(0,45)
  23.  
  24. imageTouchSurface = image(WIDTH/touchScale,HEIGHT/touchScale)
  25. currentPressurePoint = 1
  26. pressurePoints = {}
  27. pressurePoints[1] = vec4(-1000,-1000,0,0)
  28. end
  29.  
  30. function generateTouchMesh(size)
  31. --make a square the same footprint as our field to read touch against
  32. touchMesh = mesh()
  33. touchMesh:resize(6)
  34. touchMesh.vertices = {
  35. vec3(-size.x/2, 0, -size.y/2),
  36. vec3(-size.x/2, 0, size.y/2),
  37. vec3(size.x/2, 0, -size.y/2),
  38. vec3(-size.x/2, 0, size.y/2),
  39. vec3(size.x/2, 0, size.y/2),
  40. vec3(size.x/2, 0, -size.y/2)
  41. }
  42. touchMesh.texCoords = {
  43. vec2(0,0),
  44. vec2(0,1),
  45. vec2(1,0),
  46. vec2(0,1),
  47. vec2(1,1),
  48. vec2(1,0)
  49. }
  50. touchMesh:setColors(color(255,255,255,255))
  51. --call out for out texture
  52. touchMesh.texture = generateCoordTexture(vec2(100,100))
  53. end
  54.  
  55. function generateCoordTexture(resolution)
  56. tex = image(resolution.x, resolution.y)
  57. for x=1,resolution.x do
  58. for y=1, resolution.y do
  59. tex:set(x,y,x/resolution.x*255,y/resolution.y*255,0)
  60. end
  61. end
  62. return tex
  63. end
  64.  
  65. function createField(field, size, blades)
  66. --data is a vec4 that encode x as weight and y as height from base z and w represent x,y on the field
  67. dataBuffer = field:buffer("data")
  68. for i=1,blades do
  69. pos = vec3(math.random() * size.x - (size.x/2), 0, math.random() * size.y - (size.y/2))
  70. createBlade(field, pos, pos + vec3(0,bladeHeight,0))
  71. end
  72. end
  73.  
  74. function createBlade(field, baseLocation, topLocation)
  75. local firstVertex = field.size + 1
  76. field:resize(firstVertex+11)
  77. local bladeRotation = math.random(360)
  78. --setup our vertex locations
  79. --2d vertex positions
  80. v2d = vec2(bladeWidth/2,0):rotate(math.rad(bladeRotation))
  81. midLocation = (baseLocation + topLocation)/2
  82. --calculate the vertices
  83. --base corners
  84. v1 = vec3(v2d.x+baseLocation.x,baseLocation.y, v2d.y+baseLocation.z)
  85. v2 = vec3(-v2d.x+baseLocation.x, baseLocation.y, -v2d.y+baseLocation.z)
  86. --mid corners
  87. v3 = vec3((v2d.x)+midLocation.x, midLocation.y, (v2d.x)+midLocation.z)
  88. v4 = vec3(-(v2d.x)+midLocation.x, midLocation.y, -(v2d.x)+midLocation.z)
  89. --point
  90. v5 = vec3(v2d.x/2+topLocation.x,topLocation.y, v2d.y/2+topLocation.z)
  91. v6 = vec3(-v2d.x/2+topLocation.x, topLocation.y, -v2d.y/2+topLocation.z)
  92.  
  93. basecol = color(86, 153, 96, 255)
  94. midcol = color(63, 163, 78, 255)
  95. topcol = color(12, 229, 8, 255)
  96. field:vertex(firstVertex, v1)
  97. field:vertex(firstVertex+1, v2)
  98. field:vertex(firstVertex+2, v3)
  99. normal = (v2-v1):normalize():cross((v3-v1):normalize()):normalize()
  100. field:normal(firstVertex, normal)
  101. field:normal(firstVertex+1, normal)
  102. field:normal(firstVertex+2, normal)
  103. field:normal(firstVertex+3, normal)
  104. field:normal(firstVertex+4, normal)
  105. field:normal(firstVertex+5, normal)
  106. field:normal(firstVertex+6, normal)
  107. field:normal(firstVertex+7, normal)
  108. field:normal(firstVertex+8, normal)
  109. field:normal(firstVertex+9, normal)
  110. field:normal(firstVertex+10, normal)
  111. field:normal(firstVertex+11, normal)
  112. field:vertex(firstVertex+3, v3)
  113. field:vertex(firstVertex+4, v4)
  114. field:vertex(firstVertex+5, v2)
  115. field:vertex(firstVertex+6, v3)
  116. field:vertex(firstVertex+7, v4)
  117. field:vertex(firstVertex+8, v5)
  118. field:vertex(firstVertex+9, v4)
  119. field:vertex(firstVertex+10, v5)
  120. field:vertex(firstVertex+11, v6)
  121. field:color(firstVertex, basecol)
  122. field:color(firstVertex+1, basecol)
  123. field:color(firstVertex+2, midcol)
  124. field:color(firstVertex+3, midcol)
  125. field:color(firstVertex+4, midcol)
  126. field:color(firstVertex+5, basecol)
  127. field:color(firstVertex+6, midcol)
  128. field:color(firstVertex+7, midcol)
  129. field:color(firstVertex+8, topcol)
  130. field:color(firstVertex+9, midcol)
  131. field:color(firstVertex+10, topcol)
  132. field:color(firstVertex+11, topcol)
  133. dataBuffer[firstVertex] = vec4(0, 0, baseLocation.x, baseLocation.z)
  134. dataBuffer[firstVertex+1] = vec4(0, 0, baseLocation.x, baseLocation.z)
  135. dataBuffer[firstVertex+2] = vec4(midWeight, midLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  136. dataBuffer[firstVertex+3] = vec4(midWeight, midLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  137. dataBuffer[firstVertex+4] = vec4(midWeight, midLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  138. dataBuffer[firstVertex+5] = vec4(0, 0, baseLocation.x, baseLocation.z)
  139. dataBuffer[firstVertex+6] = vec4(midWeight, midLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  140. dataBuffer[firstVertex+7] = vec4(midWeight, midLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  141. dataBuffer[firstVertex+8] = vec4(1, topLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  142. dataBuffer[firstVertex+9] = vec4(midWeight, midLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  143. dataBuffer[firstVertex+10] = vec4(1, topLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  144. dataBuffer[firstVertex+11] = vec4(1, topLocation.y - baseLocation.y, baseLocation.x, baseLocation.z)
  145. end
  146.  
  147. function touched(touch)
  148. if touch.state == BEGAN or touch.state == MOVING then
  149. r,g,b,a = imageTouchSurface:get(touch.x/touchScale, touch.y/touchScale)
  150. r = r / 255 * size.x - size.x/2
  151. g = g / 255 * size.y - size.y/2
  152. if math.abs(r-pressurePoints[currentPressurePoint].x) + math.abs(g-pressurePoints[currentPressurePoint].y) > 1 then
  153. currentPressurePoint = (currentPressurePoint + 1)%20
  154. pressurePoints[currentPressurePoint] = vec4(r,g,3,ElapsedTime)
  155. if currentPressurePoint == 1 then
  156. field.shader.pressureZone1 = pressurePoints[currentPressurePoint]
  157. elseif currentPressurePoint == 2 then
  158. field.shader.pressureZone2 = pressurePoints[currentPressurePoint]
  159. elseif currentPressurePoint == 3 then
  160. field.shader.pressureZone3 = pressurePoints[currentPressurePoint]
  161. elseif currentPressurePoint == 4 then
  162. field.shader.pressureZone4 = pressurePoints[currentPressurePoint]
  163. elseif currentPressurePoint == 5 then
  164. field.shader.pressureZone5 = pressurePoints[currentPressurePoint]
  165. elseif currentPressurePoint == 6 then
  166. field.shader.pressureZone6 = pressurePoints[currentPressurePoint]
  167. elseif currentPressurePoint == 7 then
  168. field.shader.pressureZone7 = pressurePoints[currentPressurePoint]
  169. elseif currentPressurePoint == 8 then
  170. field.shader.pressureZone8 = pressurePoints[currentPressurePoint]
  171. elseif currentPressurePoint == 9 then
  172. field.shader.pressureZone9 = pressurePoints[currentPressurePoint]
  173. elseif currentPressurePoint == 10 then
  174. field.shader.pressureZone10 = pressurePoints[currentPressurePoint]
  175. elseif currentPressurePoint == 11 then
  176. field.shader.pressureZone11 = pressurePoints[currentPressurePoint]
  177. elseif currentPressurePoint == 12 then
  178. field.shader.pressureZone12 = pressurePoints[currentPressurePoint]
  179. elseif currentPressurePoint == 13 then
  180. field.shader.pressureZone13 = pressurePoints[currentPressurePoint]
  181. elseif currentPressurePoint == 14 then
  182. field.shader.pressureZone14 = pressurePoints[currentPressurePoint]
  183. elseif currentPressurePoint == 15 then
  184. field.shader.pressureZone15 = pressurePoints[currentPressurePoint]
  185. elseif currentPressurePoint == 16 then
  186. field.shader.pressureZone16 = pressurePoints[currentPressurePoint]
  187. elseif currentPressurePoint == 17 then
  188. field.shader.pressureZone17 = pressurePoints[currentPressurePoint]
  189. elseif currentPressurePoint == 18 then
  190. field.shader.pressureZone18 = pressurePoints[currentPressurePoint]
  191. elseif currentPressurePoint == 19 then
  192. field.shader.pressureZone19 = pressurePoints[currentPressurePoint]
  193. elseif currentPressurePoint == 20 then
  194. field.shader.pressureZone20 = pressurePoints[currentPressurePoint]
  195. end
  196. end
  197. end
  198. end
  199.  
  200. -- This function gets called once every frame
  201. function draw()
  202. campos = campos:rotate(math.rad(0.2))
  203. output.clear()
  204. print(1/DeltaTime)
  205. field.shader.time = ElapsedTime
  206.  
  207. setContext(imageTouchSurface)
  208. background(40, 40, 50)
  209. camera(campos.x,30,campos.y, 0,0,0)
  210. perspective()
  211. touchMesh:draw()
  212. setContext()
  213. background(40,40,50)
  214. camera(campos.x,30,campos.y, 0,0,0)
  215. perspective()
  216.  
  217. field.shader.vEyePosition = vec3(campos.x, 20, campos.y)
  218. field.shader.vLightPosition = vec3(10,80,20)
  219. field.shader.mInvModel = modelMatrix():inverse():transpose()
  220.  
  221. field:draw()
  222. end
  223.  
  224. GrassShader = {
  225. vertexShader = [[
  226. //
  227. // A basic vertex shader
  228. //
  229.  
  230. //This is the current model * view * projection matrix
  231. // Codea sets it automatically
  232. uniform mat4 modelViewProjection;
  233.  
  234. uniform vec4 pressureZone1;
  235. uniform vec4 pressureZone2;
  236. uniform vec4 pressureZone3;
  237. uniform vec4 pressureZone4;
  238. uniform vec4 pressureZone5;
  239. uniform vec4 pressureZone6;
  240. uniform vec4 pressureZone7;
  241. uniform vec4 pressureZone8;
  242. uniform vec4 pressureZone9;
  243. uniform vec4 pressureZone10;
  244. uniform vec4 pressureZone11;
  245. uniform vec4 pressureZone12;
  246. uniform vec4 pressureZone13;
  247. uniform vec4 pressureZone14;
  248. uniform vec4 pressureZone15;
  249. uniform vec4 pressureZone16;
  250. uniform vec4 pressureZone17;
  251. uniform vec4 pressureZone18;
  252. uniform vec4 pressureZone19;
  253. uniform vec4 pressureZone20;
  254.  
  255. uniform float time;
  256. uniform highp mat4 mInvModel;
  257. uniform mediump vec3 vEyePosition;
  258. uniform mediump vec3 vLightPosition;
  259.  
  260. //This is the current mesh vertex position, color and tex coord
  261. // Set automatically
  262. attribute vec4 position;
  263. attribute vec4 color;
  264. attribute vec3 normal;
  265. attribute vec4 data;
  266.  
  267. //This is an output variable that will be passed to the fragment shader
  268. varying lowp vec4 vColor;
  269. varying highp vec3 lightDirection;
  270. varying mediump vec3 eyeDirection;
  271. varying mediump vec3 vNormal;
  272.  
  273. /// 2D Noise by Ian McEwan, Ashima Arts.
  274. vec3 mod289(vec3 x) {
  275. return x - floor(x * (1.0 / 289.0)) * 289.0;
  276. }
  277.  
  278. vec2 mod289(vec2 x) {
  279. return x - floor(x * (1.0 / 289.0)) * 289.0;
  280. }
  281.  
  282. vec3 permute(vec3 x) {
  283. return mod289(((x*34.0)+1.0)*x);
  284. }
  285.  
  286. float snoise (vec2 v) {
  287. const vec4 C = vec4(
  288. 0.211324865405187, // (3.0-sqrt(3.0))/6.0
  289. 0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
  290. -0.577350269189626, // -1.0 + 2.0 * C.x
  291. 0.024390243902439); // 1.0 / 41.0
  292. // First corner
  293. vec2 i = floor(v + dot(v, C.yy) );
  294. vec2 x0 = v - i + dot(i, C.xx);
  295. // Other corners
  296. vec2 i1;
  297. i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
  298. vec4 x12 = x0.xyxy + C.xxzz; x12.xy -= i1;
  299. // Permutations
  300. i = mod289(i);
  301. // Avoid truncation effects in permutation
  302. vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + i.x + vec3(0.0, i1.x, 1.0 ));
  303. vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
  304. m = m*m ;
  305. m = m*m ;
  306. // Gradients: 41 points uniformly over a line, mapped onto a diamond.
  307. // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
  308. vec3 x = 2.0 * fract(p * C.www) - 1.0;
  309. vec3 h = abs(x) - 0.5;
  310. vec3 ox = floor(x + 0.5);
  311. vec3 a0 = x - ox;
  312. // Normalise gradients implicitly by scaling m
  313. // Approximation of: m *= inversesqrt( a0*a0 + h*h );
  314. m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
  315. // Compute final noise value at P
  316. vec3 g;
  317. g.x = a0.x * x0.x + h.x * x0.y;
  318. g.yz = a0.yz * x12.xz + h.yz * x12.yw;
  319. return 60.0 * dot(m, g);
  320. }
  321.  
  322. vec2 applyPressure(vec4 pressureZone)
  323. {
  324. float radius = length(pressureZone.xy - data.zw);
  325. if (radius < pressureZone.z) {
  326. float factor;
  327. if (time < pressureZone.w + 2.5) {
  328. if (time < pressureZone.w + 0.5) {
  329. factor = 1.0 - (pressureZone.w + 0.5 - time)/0.5;
  330. }
  331. else {
  332. factor = 1.0 - (time - pressureZone.w - 0.5)/2.0;
  333. }
  334. return (normalize(data.zw - pressureZone.xy) *
  335. (1.0 - radius/pressureZone.z)) * factor * 2.0;
  336. }
  337. }
  338. return vec2(0,0);
  339. }
  340.  
  341. void main()
  342. {
  343. //convert the positions of the eye and light from world space to object space and then make a vector from position for ADS lighting
  344. lightDirection = ((vec4(vLightPosition,1) * mInvModel) - position).xyz;
  345. eyeDirection = ((vec4(vEyePosition,1) * mInvModel) - position).xyz;
  346.  
  347. //Pass the mesh color to the fragment shader
  348. vColor = color;
  349.  
  350. //apply force by weight
  351. vec2 deformation = vec2(snoise(vec2(data.z/15.0+time/2.0,data.w/15.0+time/2.0)),
  352. snoise(vec2(data.z/15.0+time/2.0+5000.0,data.w/15.0+time/2.0+5000.0)));
  353.  
  354. //apply pressureZone
  355.  
  356. deformation = deformation + applyPressure(pressureZone1);
  357. deformation = deformation + applyPressure(pressureZone2);
  358. deformation = deformation + applyPressure(pressureZone3);
  359. deformation = deformation + applyPressure(pressureZone4);
  360. deformation = deformation + applyPressure(pressureZone5);
  361. deformation = deformation + applyPressure(pressureZone6);
  362. deformation = deformation + applyPressure(pressureZone7);
  363. deformation = deformation + applyPressure(pressureZone8);
  364. deformation = deformation + applyPressure(pressureZone9);
  365. deformation = deformation + applyPressure(pressureZone10);
  366. deformation = deformation + applyPressure(pressureZone11);
  367. deformation = deformation + applyPressure(pressureZone12);
  368. deformation = deformation + applyPressure(pressureZone13);
  369. deformation = deformation + applyPressure(pressureZone14);
  370. deformation = deformation + applyPressure(pressureZone15);
  371. deformation = deformation + applyPressure(pressureZone16);
  372. deformation = deformation + applyPressure(pressureZone17);
  373. deformation = deformation + applyPressure(pressureZone18);
  374. deformation = deformation + applyPressure(pressureZone19);
  375. deformation = deformation + applyPressure(pressureZone20);
  376. deformation = deformation * data.x;
  377. //limit the force length max to length from root
  378. if (length(deformation) > (data.y*0.99)) {
  379. deformation = normalize(deformation)*(data.y*0.99);
  380. }
  381. //calculate the vertical adjustment to retain length with deformation
  382. float heightReduction = -(data.y-sqrt(pow(data.y,2.0) - pow(length(deformation),2.0)));
  383.  
  384. vec4 positionModification = vec4(deformation.x,
  385. heightReduction, deformation.y,0);
  386.  
  387. //adjust the normal by the deformation for lighting
  388. float defHorLength = length(deformation);
  389. vec2 defHorDirection = normalize(deformation);
  390.  
  391. //normal and color to fragment
  392. //normals should be adjusted for pressure...
  393. vNormal = normal;
  394. if (data.y > 0.1) {
  395. vNormal = normalize(normal + vec3(-defHorDirection.x*heightReduction/data.y,
  396. defHorLength/data.y,
  397. -defHorDirection.y*heightReduction/data.y));
  398. }
  399. //Multiply the vertex position by our combined transform
  400. gl_Position = modelViewProjection * (position + positionModification);
  401. }
  402. ]],
  403. fragmentShader = [[
  404. precision lowp float;
  405.  
  406. uniform lowp sampler2D texture;
  407. //uniform lowp sampler2D bumpMap;
  408.  
  409. varying lowp vec4 vColor;
  410. varying mediump vec3 lightDirection;
  411. varying mediump vec3 eyeDirection;
  412. varying mediump vec3 vNormal;
  413.  
  414. const float c_zero = 0.0;
  415. const float c_one = 1.0;
  416. const float c_two = 2.0;
  417.  
  418. void main()
  419. {
  420. //if (!gl_FrontFacing) discard;
  421.  
  422. vec3 curNormal = normalize(vNormal);
  423.  
  424. lowp vec4 curCol = vColor;
  425.  
  426. vec3 vLightDirection = normalize(normalize(lightDirection));
  427. vec3 vCameraDirection = normalize(eyeDirection);
  428.  
  429.  
  430. lowp vec4 vAmbientColor = curCol * 0.2;
  431.  
  432. // Calculate Diffuse intensity
  433. float fDiffuseIntensity = max(max( c_zero, dot( curNormal, vLightDirection )), dot(-curNormal, vLightDirection));
  434.  
  435. lowp vec4 vDiffuseColor = curCol * fDiffuseIntensity;
  436.  
  437. vAmbientColor.a = c_one;
  438. vDiffuseColor.a = c_one;
  439. //Set the output color to the texture color
  440. gl_FragColor = vAmbientColor + vDiffuseColor;
  441. //gl_FragColor = curCol;
  442. }
  443.  
  444. ]]
  445. }
RAW Paste Data