Advertisement
Guest User

Untitled

a guest
Jul 26th, 2016
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.13 KB | None | 0 0
  1.  
  2. --# Notes
  3. --[[
  4. This project shows how to add different types of lighting to 3D scenes (in this case, a cube)
  5.  
  6. --HOW TO USE THIS PROJECT
  7.  
  8. There are a number of tabs at the top. Press on a tab to see its code.
  9.  
  10. Work through the tabs from left to right, to see the project develop
  11.  
  12. You can run the code in any of the project tabs, by
  13. 1. running the program, and
  14. 2. selecting the tab number using the controls at the upper left of the screen
  15.  
  16. The program will remember your selection after that.
  17. This enables you to work with one tab at a time, make changes and see the effects by running the program
  18.  
  19. Each tab has all the code for that demo, so you can copy the code in any tab to your own project and adapt it
  20.  
  21. IMPORTANT NOTES
  22.  
  23. 1. Lighting requires the use of shaders. While you can use this code as a black box, it is
  24. preferable that you understand how it works, so you can make changes or fix problems yourself.
  25.  
  26. 2. It may be difficult to learn how lighting works just from looking at these demos. Ideally, you should
  27. try to learn the basics of diffuse and specular light first.
  28.  
  29. --]]
  30.  
  31.  
  32. --# Ambient
  33. --Ambient light
  34.  
  35. --[[
  36. Ambient light is the general lighting level
  37. You could call it the minimum light that falls on every surface
  38. if it is 0, then anything that is not lit will be pitch black
  39. if it is 1, then everything is fully lit all the time
  40.  
  41. As you might guess, it is pretty simple - you just multiply the light level by the ambient factor
  42. There's just one thing - the ambient light doesn't have to be white, so we specify the light colour
  43. and everything will be tinted by this colour (see the extra parameter provided for this)
  44.  
  45. You are unlikely ever to use just ambient light on its own.
  46. --]]
  47.  
  48. function setup()
  49. block=CreateBlock(1,0.5,0.75,"Platformer Art:Block Brick")
  50. currentModelMatrix=modelMatrix() --this is used for touches, not lighting
  51. SetupShader()
  52. end
  53.  
  54. --All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
  55. function SetupShader() --set up the lighting
  56. --in these demos, you get to change some of the lighting options using parameters
  57. --in your own apps, you will probably just set the lighting values yourself
  58. parameter.number("ambientStrength", 0, 1, 0.3) -- level of ambient light (0=dark, 1=light)
  59. parameter.color("ambientColor", color(255,255,255,255)) --- colour of ambient light
  60. block.shader=shader(AmbientShader.vertexShader,AmbientShader.fragmentShader)
  61. end
  62.  
  63. function UpdateShader() --update the lighting details before drawing
  64. --if you aren't going to be changing ambient colour or strength, you can put this line in setup
  65. block.shader.ambient = ambientColor*ambientStrength
  66. end
  67.  
  68. --this shader has ambient lighting
  69. AmbientShader = {
  70.  
  71. vertexShader = [[
  72. uniform mat4 modelViewProjection;
  73. uniform vec4 ambient; // ambient light
  74. attribute vec4 position;
  75. attribute vec4 color;
  76. attribute vec2 texCoord;
  77. varying lowp vec4 vColor;
  78. varying highp vec2 vTexCoord;
  79.  
  80. void main()
  81. {
  82. vColor = color*ambient; // apply ambient light to object colour and pass to fragment shader
  83. vTexCoord = texCoord;
  84. gl_Position = modelViewProjection * position;
  85. }
  86. ]],
  87.  
  88. fragmentShader = [[
  89. precision highp float;
  90. uniform lowp sampler2D texture;
  91. varying lowp vec4 vColor;
  92. varying highp vec2 vTexCoord;
  93.  
  94. void main()
  95. {
  96. lowp vec4 col = texture2D(texture, vTexCoord) * vColor; //apply ambient light to texture
  97. col.a = 1.0;
  98. gl_FragColor = col;
  99. }
  100. ]]
  101. }
  102.  
  103. --UTILITY CODE - IT WILL NOT CHANGE FROM HERE ON --
  104.  
  105. function draw()
  106. background(0)
  107. perspective()
  108. camera(-1,1,2,0,0,0)
  109. HandleTouches() --allows you to rotate the cube with your fingers
  110. UpdateShader()
  111. block:draw()
  112. end
  113.  
  114. --this code manages touches so you can rotate the cube
  115. function HandleTouches()
  116. modelMatrix(currentModelMatrix) --apply the stored settings
  117. --do rotation for touch
  118. if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
  119. rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
  120. rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
  121. currentModelMatrix = modelMatrix() --store the resulting settings for next time
  122. end
  123. end
  124.  
  125. --this function creates a cube
  126. function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
  127. pos=pos or vec3(0,0,0)
  128. local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
  129. local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
  130. local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
  131. v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
  132. local texCoords
  133. if tex then
  134. local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
  135. texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
  136. t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
  137. end
  138.  
  139. local norm={} --calculate normals
  140. for i=1,#vert,3 do
  141. local n=GetNormal(vert[i],vert[i+1],vert[i+2])
  142. norm[i],norm[i+1],norm[i+2]=n,n,n
  143. end
  144.  
  145. if not ms then ms=mesh() end
  146. if ms.size==0 then
  147. ms.vertices=vert
  148. ms.normals=norm
  149. ms.texture,ms.texCoords=tex,texCoords
  150. else
  151. for i=1,#vert do
  152. table.insert(ms.vertices,vert[i])
  153. table.insert(ms.normals,norm[i])
  154. if tex then table.insert(ms.texCoords,texCoords[i]) end
  155. end
  156. end
  157. ms:setColors(col or color(255))
  158. return ms
  159. end
  160.  
  161. function GetNormal(v1,v2,v3)
  162. return ((v1-v3):cross(v2-v3)):normalize()
  163. end
  164.  
  165. function PrintExplanation()
  166. output.clear()
  167. print("Ambient light is the general background light that shines equally on all sides of an object")
  168. print("Use a finger to rotate the cube")
  169. end
  170.  
  171. --# Diffuse
  172. --Diffuse
  173.  
  174. --[[
  175. The sun is so far away that its light comes from the same direction for every part of your scene, and the
  176. strength of the light is also the same across your scene. This is diffuse light - coming from a single direction
  177. with a constant colour strength.
  178.  
  179. Diffuse light can have any colour, but because it is added to ambient light, the total of the two should not
  180. generally exceed 255. In other words, ambient + diffuse <= color(255)
  181. For example, you might use
  182. ambient = color(255) * 0.3 --dim white light
  183. diffuse = color(255,0,0) * 0.7 --red light
  184. When you add these together, the maximum light is color(255,76,76)
  185.  
  186. Diffuse light is caused by reflection, and is brightest for any object directly facing the light, reducing if the
  187. light hits the object at an angle.
  188.  
  189. Our objects are made from triangles of vertices. These triangles are flat surfaces, and the direction they are
  190. facing is at right angles to that surface. This direction is called a "normal" (based on a latin word meaning 'at right angles'). So if you imagine lying flat on your back on a triangle of vertices, you are looking in the
  191. 'normal' direction - and if that is facing the diffuse light source, the light will be brightest.
  192.  
  193. You need two things to calculate the amount of diffuse light for any triangle
  194. 1. its 'normal' direction
  195. 2. a way of measuring how similar this is to the direction that the diffuse light is coming from
  196.  
  197. This demo provides a function for calculating the normal of any set of three vertices, and Codea meshes have a
  198. normals property, so if you have a mesh m and a table of normals n, you can write
  199. m.normals = n
  200. (see the CreateBlock function below for an example)
  201.  
  202. The dot function is a convenient way of measuring the similarity of two directions, and that is used in the
  203. shader to calculate the amount of reflection.
  204.  
  205. Note that because the normals are the same for all the vertices in each triangle, they will be the same for each
  206. point in that triangle. So we can calculate diffuse light in the vertex shader, rather than the fragment shader,
  207. which is much more efficient.
  208.  
  209. To set the direction the diffuse light is coming from, imagine a line running from (0,0,0) towards the diffuse
  210. light. Take any point on that line, and "normalise" it to give it a length of 1. So if I am facing toward -z as
  211. usual, here are some examples
  212. vec3(-1,0,0) --a light that shines from left to right (no need to normalize, it already has length 1)
  213. vec3(0,1,0) --a light that shines down vertically (again, no need to normalise)
  214. vec3(-1,0.5,1):normalize() --a light that comes from behind me over my left shoulder
  215. The absolute size of the numbers you use for x,y,z doesn't matter, since
  216. vec3(1,2,-3):normalize() = vec3(10,20,-30):normalize()
  217. but of course the relative size (how big x is, relative to y and z, for example) does matter..
  218. --]]
  219.  
  220. function setup()
  221. block=CreateBlock(1,0.5,0.75,"Platformer Art:Block Brick")
  222. currentModelMatrix=modelMatrix() --this is used for touches, not lighting
  223. SetupShader()
  224. end
  225.  
  226. --All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
  227. function SetupShader() --set up the lighting
  228. --in your own apps, you will probably just set these lighting values yourself instead of using parameters
  229. parameter.number("diffuseStrength", 0, 1, 0.7) --brightness of light source -- ***** NEW
  230. parameter.color("lightColor", color(255)) -- ***** NEW
  231. block.shader=shader(DiffuseShader.vertexShader,DiffuseShader.fragmentShader)
  232. block.shader.ambientColor = color(255)*0.3
  233. block.shader.directDirection = vec3(-1,0,1):normalize() -- ****** NEW
  234. end
  235.  
  236. function UpdateShader() --update the lighting details before drawing
  237. --if you aren't going to be changing colours or light strength, you can put the next line in setup
  238. block.shader.directColor=diffuseStrength*lightColor -- ****** NEW
  239. block.shader.mModel=modelMatrix() --this must be updated each time you draw
  240. end
  241.  
  242. --shader follows
  243.  
  244. DiffuseShader = {
  245.  
  246. vertexShader = [[
  247. uniform mat4 modelViewProjection;
  248. uniform vec4 ambientColor;
  249. uniform vec3 directDirection;
  250. uniform vec4 directColor;
  251. uniform mat4 mModel;
  252. attribute vec4 position;
  253. attribute vec4 color;
  254. attribute vec2 texCoord;
  255. attribute vec3 normal;
  256. varying lowp vec4 vColor;
  257. varying highp vec2 vTexCoord;
  258.  
  259. void main()
  260. {
  261. vec4 norm = normalize(mModel * vec4( normal, 0.0 )); //transform normal to world speace
  262. float diffuse = max( 0.0, dot( norm.xyz, directDirection )); //calculate strength of reflection
  263. vColor = ambientColor + diffuse * directColor; //total color
  264. vColor.a = 1.0;
  265. vTexCoord = texCoord;
  266. gl_Position = modelViewProjection * position;
  267. }
  268. ]],
  269.  
  270. fragmentShader = [[
  271. precision highp float;
  272. uniform lowp sampler2D texture;
  273. varying lowp vec4 vColor;
  274. varying highp vec2 vTexCoord;
  275.  
  276. void main()
  277. {
  278. gl_FragColor = texture2D(texture, vTexCoord) * vColor;
  279. }
  280. ]]
  281. }
  282.  
  283.  
  284. --EVERYTHING BELOW IS UNCHANGED --
  285.  
  286. function draw()
  287. background(0)
  288. perspective()
  289. camera(-1,1,2,0,0,0)
  290. HandleTouches()
  291. UpdateShader()
  292. block:draw()
  293. end
  294.  
  295. function HandleTouches()
  296. modelMatrix(currentModelMatrix) --apply the stored settings
  297. --do rotation for touch
  298. if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
  299. rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
  300. rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
  301. currentModelMatrix = modelMatrix() --store the resulting settings for next time
  302. end
  303. end
  304.  
  305. function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
  306. pos=pos or vec3(0,0,0)
  307. local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
  308. local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
  309. local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
  310. v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
  311. local texCoords
  312. if tex then
  313. local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
  314. texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
  315. t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
  316. end
  317.  
  318. local norm={} --calculate normals
  319. for i=1,#vert,3 do
  320. local n=GetNormal(vert[i],vert[i+1],vert[i+2])
  321. norm[i],norm[i+1],norm[i+2]=n,n,n
  322. end
  323.  
  324. if not ms then ms=mesh() end
  325. if ms.size==0 then
  326. ms.vertices=vert
  327. ms.normals=norm
  328. ms.texture,ms.texCoords=tex,texCoords
  329. else
  330. for i=1,#vert do
  331. table.insert(ms.vertices,vert[i])
  332. table.insert(ms.normals,norm[i])
  333. if tex then table.insert(ms.texCoords,texCoords[i]) end
  334. end
  335. end
  336. ms:setColors(col or color(255))
  337. return ms
  338. end
  339.  
  340. function GetNormal(v1,v2,v3)
  341. return ((v1-v3):cross(v2-v3)):normalize()
  342. end
  343.  
  344. function PrintExplanation()
  345. output.clear()
  346. print("Diffuse light comes from a specific direction, so far away that it is in the same direction (and has the same strength) for every part of the object you are lighting.\n\nExample - the sun")
  347. print("The part of the object facing the light direction will be lit the most")
  348. print("Use a finger to rotate the cube")
  349. end
  350.  
  351.  
  352.  
  353. --# Specular
  354. --Specular
  355.  
  356. --[[
  357. Specular light is the reflection from a light source into your eye (the bright spot!)
  358.  
  359. It is too complex to explain fully here, but it needs the camera position
  360.  
  361. The extra shader settings below are
  362. * specularPower = how focussed and concentrated the light is. Use a power of 2, eg 1,2,4,8,16,32,64,...
  363. (the demo has a Focus parameter which is from 1-10. It is converted to powers of 2, so 3 becomes 2^3 = 8)
  364. * shine - how shiny the object is (0 to 1)
  365. * eyePosition - (vec3(x,y,z) position of camera
  366.  
  367. --]]
  368.  
  369. function setup()
  370. block=CreateBlock(1,0.5,0.75,"Platformer Art:Block Brick")
  371. currentModelMatrix=modelMatrix() --this is used for touches, not lighting
  372. camPos=vec3(0,0,2) -- ***** NEW
  373. z,zd=0,-.01 --to move block back and forward
  374. SetupShader()
  375. end
  376.  
  377. --All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
  378. function SetupShader() --set up the lighting
  379. --set position of light source
  380. block.shader=shader(SpecularShader.vertexShader,SpecularShader.fragmentShader)
  381. block.shader.ambientColor = color(255) *0.5
  382. block.shader.directColor=color(255,255,0) *0.7
  383. block.shader.directDirection = vec3(1,0,1):normalize()
  384. block.shader.shine=1 --very shiny -- ***** NEW
  385. --you can play with the size and focus of the spot using this parameter (make sure it is a power of 2)
  386. --convert the user choice to a power of 2
  387. parameter.integer("Focus",1,10,5,function() block.shader.specularPower=2^Focus end)
  388.  
  389. end
  390.  
  391. function UpdateShader() --update the lighting details before drawing
  392. block.shader.mModel=modelMatrix() --this must be updated each time you draw
  393. block.shader.eyePosition=camPos -- ***** NEW
  394. block.shader.mModel=modelMatrix()
  395. end
  396.  
  397. function draw()
  398. background(0)
  399. perspective()
  400. currentModelMatrix[15]=z
  401. camera(camPos.x,camPos.y,camPos.z,0,0,0)
  402. HandleTouches()
  403. UpdateShader()
  404. block:draw()
  405. z=z+zd
  406. if z<-3 or z>0 then zd=-zd end
  407. end
  408.  
  409. --shader follows
  410.  
  411. SpecularShader={
  412. vertexShader=[[
  413.  
  414. uniform mat4 modelViewProjection;
  415. uniform mat4 mModel;
  416. uniform vec4 directColor;
  417. uniform vec3 directDirection;
  418. uniform vec4 ambientColor;
  419.  
  420. attribute vec4 position;
  421. attribute vec2 texCoord;
  422. attribute vec3 normal;
  423.  
  424. varying lowp vec4 vColor;
  425. varying highp vec2 vTexCoord;
  426. varying lowp vec4 vPosition;
  427. varying lowp vec4 vNormal;
  428. varying vec4 vLight;
  429.  
  430. void main()
  431. {
  432. vTexCoord = texCoord;
  433. vPosition = mModel * position;
  434. gl_Position = modelViewProjection * position;
  435. vNormal = mModel * vec4(normal, 0.0); //transform normal to world space
  436. vLight = ambientColor+directColor * max( 0.0, dot(normalize(vNormal.xyz), directDirection));
  437. }
  438.  
  439. ]],
  440.  
  441. fragmentShader=[[
  442.  
  443. precision highp float;
  444. uniform lowp sampler2D texture;
  445. uniform vec4 directColor;
  446. uniform vec3 directDirection;
  447. uniform vec3 eyePosition;
  448. uniform float specularPower;
  449. uniform float shine;
  450.  
  451. varying highp vec2 vTexCoord;
  452. varying lowp vec4 vPosition;
  453. varying lowp vec4 vNormal;
  454. varying vec4 vLight;
  455.  
  456. vec4 norm = normalize(vNormal);
  457. vec4 eye = vec4(eyePosition, 1.0);
  458. vec4 direct = vec4(directDirection, 0.0);
  459.  
  460. void main()
  461. {
  462. //calculate specular light
  463. vec4 cameraDirection = normalize( eye - vPosition );
  464. vec4 halfAngle = normalize( cameraDirection + direct );
  465. float spec = pow( max( 0.0, dot( norm, halfAngle)),specularPower);
  466. vec4 specLight = min(directColor + 0.5, 1.0) * spec * shine;
  467. vec4 totalColor=texture2D(texture, vTexCoord)*(vLight+specLight);
  468. totalColor.a= 1.;
  469. gl_FragColor=totalColor;
  470. }
  471. ]]
  472. }
  473.  
  474. --EVERYTHING BELOW IS UNCHANGED --
  475.  
  476. function HandleTouches()
  477. modelMatrix(currentModelMatrix) --apply the stored settings
  478. --do rotation for touch
  479. if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
  480. rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
  481. rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
  482. currentModelMatrix = modelMatrix() --store the resulting settings for next time
  483. end
  484. end
  485.  
  486. function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
  487. pos=pos or vec3(0,0,0)
  488. local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
  489. local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
  490. local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
  491. v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
  492. local texCoords
  493. if tex then
  494. local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
  495. texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
  496. t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
  497. end
  498.  
  499. local norm={} --calculate normals
  500. for i=1,#vert,3 do
  501. local n=GetNormal(vert[i],vert[i+1],vert[i+2])
  502. norm[i],norm[i+1],norm[i+2]=n,n,n
  503. end
  504.  
  505. if not ms then ms=mesh() end
  506. if ms.size==0 then
  507. ms.vertices=vert
  508. ms.normals=norm
  509. ms.texture,ms.texCoords=tex,texCoords
  510. else
  511. for i=1,#vert do
  512. table.insert(ms.vertices,vert[i])
  513. table.insert(ms.normals,norm[i])
  514. if tex then table.insert(ms.texCoords,texCoords[i]) end
  515. end
  516. end
  517. ms:setColors(col or color(255))
  518. return ms
  519. end
  520.  
  521. function GetNormal(v1,v2,v3)
  522. return ((v1-v3):cross(v2-v3)):normalize()
  523. end
  524.  
  525. function PrintExplanation()
  526. output.clear()
  527. print("Specular light adds a bright spot to the reflection")
  528. print("The brightness depends on how much the light reflects off the surface toward the camera")
  529. print("Play with the focus setting to make the spot larger or smaller")
  530. print("Use a finger to rotate the cube")
  531. end
  532.  
  533. --# Point
  534. --Point
  535.  
  536. --[[
  537. Point light is light from a point in space (rather than from a direction, like diffuse light). The light shines in all directions, like a lightbulb.
  538.  
  539. This means that the light may hit two points on a triangle at different angles, so we can't calculate it
  540. in the vertex shader. Additionally, point lights often have a limited range, so the brightness reduces
  541. with distance.
  542.  
  543. To be clear about the differences with directional light, which we have worked with until now..
  544.  
  545. Directional light (eg the sun)
  546. - light comes from the same direction for every part of the scene
  547. - the strength is constant
  548.  
  549. Point light (eg light bulb)
  550. - the light is (usually) inside the scene, so it hits every part of the scene at different angles
  551. - the light shines in every direction from the position of the light
  552. - the strength of the light may vary with distance
  553.  
  554. The shader in this demo allows you to have both types of light, and the shader variables have a "direct" or "point" prefix to make it clear which type they refer to.
  555.  
  556. You can add more point lights if you want, just
  557. add extra shader variables (you'll note the point light variables all end in 1, so just duplicate all the variables
  558. with 2 on the end, for a second light (and adjust the shader to do the extra calculations)
  559.  
  560. NOTE that directional light (as shown in the previous three demos) is included in this demo, but its light has
  561. been set to nil so that you can see the point light clearly
  562. --]]
  563.  
  564. function setup()
  565. block=CreateBlock(1,0.5,0.75,"Platformer Art:Block Brick")
  566. currentModelMatrix=modelMatrix() --this is used for touches, not lighting
  567. camPos=vec3(0,0,2)
  568. z,zd=0,-.01
  569. SetupShader()
  570. end
  571.  
  572. --All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
  573. function SetupShader() --set up the lighting
  574. --set position of light source
  575. block.shader=shader(PointShader.vertexShader,PointShader.fragmentShader)
  576. block.shader.ambientColor = color(255) *0.2
  577. block.shader.directColor=color(255) * 0 --NOTE-turned off so you can see the point light
  578. block.shader.directDirection = vec3(-1,0,1):normalize()
  579. block.shader.shine=0 --set this to 0 if you don't want specular lighting for your directional light
  580. block.shader.specularPower=32
  581. --point light variables needed by the shader --- ****** NEW
  582. block.shader.point1Position=vec3(2,0,1) --this is an actual position to the right of us
  583. block.shader.point1Color=color(255) --multiply by a factor (eg 0.5) if you want to reduce brightness
  584. block.shader.point1Range=6 --light reduces to nil over this distance
  585. end
  586.  
  587. function UpdateShader() --update the lighting details before drawing
  588. block.shader.mModel=modelMatrix()
  589. block.shader.eyePosition=camPos
  590. end
  591.  
  592. function draw()
  593. background(0)
  594. perspective()
  595. camera(camPos.x,camPos.y,camPos.z,0,0,0)
  596. currentModelMatrix[15]=z
  597. HandleTouches()
  598. UpdateShader()
  599. block:draw()
  600. z=z+zd
  601. if z<-6 or z>0 then zd=-zd end
  602. end
  603.  
  604. --shader follows
  605.  
  606. PointShader={
  607. vertexShader=[[
  608.  
  609. uniform mat4 modelViewProjection;
  610. uniform mat4 mModel;
  611. uniform vec4 directColor;
  612. uniform vec3 directDirection;
  613. uniform vec4 ambientColor;
  614. uniform vec3 point1Position;
  615. uniform vec4 point1Color;
  616.  
  617. attribute vec4 position;
  618. attribute vec2 texCoord;
  619. attribute vec3 normal;
  620.  
  621. varying highp vec2 vTexCoord;
  622. varying lowp vec4 vPosition;
  623. varying lowp vec4 vNormal;
  624. varying vec4 vAmbientDiffuse;
  625. varying vec4 vPoint1Diffuse;
  626.  
  627. void main()
  628. {
  629. vTexCoord = texCoord;
  630. vPosition = mModel * position;
  631. gl_Position = modelViewProjection * position;
  632. vNormal = mModel * vec4(normal, 0.0);
  633. //calculate diffuse directional light
  634. vec3 norm = normalize(vNormal.xyz);
  635. vAmbientDiffuse = ambientColor+directColor*max(0.0, dot(norm, directDirection));
  636. //calculate diffuse point light
  637. vec3 d = normalize( point1Position - vPosition.xyz );
  638. vPoint1Diffuse = point1Color * max(0.0, dot(norm, d));
  639. }
  640.  
  641. ]],
  642.  
  643. fragmentShader=[[
  644.  
  645. precision highp float;
  646. uniform lowp sampler2D texture;
  647. uniform vec4 directColor;
  648. uniform vec3 directDirection;
  649. uniform vec3 eyePosition;
  650. uniform float specularPower;
  651. uniform float shine;
  652.  
  653. uniform vec3 point1Position;
  654. uniform float point1Range;
  655. uniform vec4 point1Color;
  656.  
  657. varying highp vec2 vTexCoord;
  658. varying lowp vec4 vPosition;
  659. varying lowp vec4 vNormal;
  660. varying vec4 vAmbientDiffuse;
  661. varying vec4 vPoint1Diffuse;
  662.  
  663. vec3 norm = normalize(vNormal).xyz;
  664. vec4 specColor = min(directColor + 0.5, 1.0) * shine;
  665.  
  666. void main()
  667. {
  668. vec3 cameraDirection = normalize(eyePosition - vPosition.xyz);
  669. //calculate specular light for directional light
  670. vec3 halfAngle = normalize(cameraDirection + directDirection);
  671. vec4 specDirect = specColor*pow(max(0.0, dot(norm, halfAngle)),specularPower);
  672. //calculate specular light for point light
  673. halfAngle = normalize(cameraDirection + normalize(point1Position - vPosition.xyz));
  674. vec4 specPoint = specColor*pow(max(0.0, dot(norm, halfAngle)),specularPower);
  675. //calculate strength of point light
  676. float point1Strength = max(0.0, 1.0-length(point1Position-vPosition.xyz) / point1Range);
  677. //add it up and apply to texture pixel
  678. vec4 col=texture2D(texture, vTexCoord);
  679. col=col*(vAmbientDiffuse+specDirect+point1Strength * (vPoint1Diffuse+specPoint));
  680. col.a= 1.;
  681. gl_FragColor=col;
  682. }
  683. ]]
  684. }
  685.  
  686. --EVERYTHING BELOW IS UNCHANGED --
  687.  
  688. function HandleTouches()
  689. modelMatrix(currentModelMatrix) --apply the stored settings
  690. --do rotation for touch
  691. if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
  692. rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
  693. rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
  694. currentModelMatrix = modelMatrix() --store the resulting settings for next time
  695. end
  696. end
  697.  
  698. function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
  699. pos=pos or vec3(0,0,0)
  700. local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
  701. local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
  702. local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
  703. v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
  704. local texCoords
  705. if tex then
  706. local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
  707. texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
  708. t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
  709. end
  710. local n={vec3(0,0,1),vec3(1,0,0),vec3(0,0,-1),vec3(-1,0,0),vec3(0,1,0),vec3(0,-1,0)}
  711. local norm={}
  712. for i=1,6 do for j=1,6 do norm[#norm+1]=n[i] end end
  713. if not ms then ms=mesh() end
  714. if ms.size==0 then
  715. ms.vertices=vert
  716. ms.normals=norm
  717. ms.texture,ms.texCoords=tex,texCoords
  718. else
  719. for i=1,#vert do
  720. table.insert(ms.vertices,vert[i])
  721. table.insert(ms.normals,norm[i])
  722. if tex then table.insert(ms.texCoords,texCoords[i]) end
  723. end
  724. end
  725. ms:setColors(col or color(255))
  726. return ms
  727. end
  728.  
  729. function PrintExplanation()
  730. output.clear()
  731. print("A point light is at a specific place in the scene and usually has limited range. \n\nRotate the cube with your finger to see the effect.")
  732. end
  733. --# Spot
  734. --Spot
  735.  
  736. --[[
  737. A spot light is like a point light, except that the light doesn't shine in all directions. A spot light is like - well a spotlight, or torch, with a radius for the beam of light.
  738.  
  739. The shader needs two extra items, the direction in which the light is pointing, and the radius of the beam
  740.  
  741. The demo includes an optional extra, a flicker, which is not part of the shader. Flickering is produced simply
  742. by varying the visibility of the spot light using the noise function (see the UpdateShader function).
  743. --]]
  744.  
  745. function setup()
  746. block=CreateBlock(1,0.5,0.75,"Platformer Art:Block Brick")
  747. currentModelMatrix=modelMatrix() --this is used for touches, not lighting
  748. camPos=vec3(0,0,2)
  749. z,zd=0,-.01
  750. SetupShader()
  751. end
  752.  
  753. --All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
  754. function SetupShader() --set up the lighting
  755. --set position of light source
  756. block.shader=shader(SpotShader.vertexShader,SpotShader.fragmentShader)
  757. block.shader.ambientColor = color(255) *0.1
  758. block.shader.directColor=color(255,255,0) *0
  759. block.shader.directDirection = vec3(-1,0,1):normalize()
  760. block.shader.shine=0 --set this to 0 if you don't want specular lighting for your directional light
  761. block.shader.specularPower=32
  762. --point light variables needed by the shader --- ****** NEW
  763. block.shader.point1Position=vec3(0,0,2) --this is an actual position to the right of us
  764. block.shader.point1Color=color(255) *0.7 --multiply by a factor (eg 0.5) if you want to reduce brightness
  765. block.shader.point1Range=20 --light reduces to nil over this distance
  766. block.shader.point1Direction=vec3(0,0,-1):normalize()
  767. block.shader.spotAngle=5 --width of light beam in degrees
  768. parameter.number("Flicker",0,0.6,0)
  769. end
  770.  
  771. function UpdateShader() --update the lighting details before drawing
  772. block.shader.mModel=modelMatrix()
  773. block.shader.eyePosition=camPos
  774. block.shader.point1Range=20*(1-Flicker+noise(ElapsedTime*5)*Flicker)
  775. end
  776.  
  777. function draw()
  778. background(0)
  779. perspective()
  780. camera(camPos.x,camPos.y,camPos.z,0,0,0)
  781. currentModelMatrix[15]=z
  782. HandleTouches()
  783. UpdateShader()
  784. block:draw()
  785. z=z+zd
  786. if z<-6 or z>0 then zd=-zd end
  787. end
  788.  
  789. --shader follows
  790.  
  791. SpotShader={
  792. vertexShader=[[
  793.  
  794. uniform mat4 modelViewProjection;
  795. uniform mat4 mModel;
  796. uniform vec4 directColor;
  797. uniform vec3 directDirection;
  798. uniform vec4 ambientColor;
  799. uniform vec3 point1Position;
  800. uniform vec4 point1Color;
  801.  
  802. attribute vec4 position;
  803. attribute vec2 texCoord;
  804. attribute vec3 normal;
  805.  
  806. varying highp vec2 vTexCoord;
  807. varying lowp vec4 vPosition;
  808. varying lowp vec4 vNormal;
  809. varying vec4 vAmbientDiffuse;
  810. varying vec4 vPoint1Diffuse;
  811.  
  812. void main()
  813. {
  814. vTexCoord = texCoord;
  815. vPosition = mModel * position;
  816. gl_Position = modelViewProjection * position;
  817. vNormal = mModel * vec4(normal, 0.0);
  818. //calculate diffuse light
  819. vec3 norm = normalize(vNormal.xyz);
  820. vAmbientDiffuse = ambientColor+directColor*max(0.0, dot(norm, directDirection));
  821. vec3 d = normalize(point1Position - vPosition.xyz);
  822. vPoint1Diffuse = point1Color * max(0.0, dot(norm, d));
  823. }
  824.  
  825. ]],
  826.  
  827. fragmentShader=[[
  828.  
  829. precision highp float;
  830. uniform lowp sampler2D texture;
  831. uniform vec4 directColor;
  832. uniform vec3 directDirection;
  833. uniform vec3 eyePosition;
  834. uniform float specularPower;
  835. uniform float shine;
  836.  
  837. uniform vec3 point1Position;
  838. uniform float point1Range;
  839. uniform vec4 point1Color;
  840. uniform vec3 point1Direction;
  841. uniform float spotAngle;
  842.  
  843. varying highp vec2 vTexCoord;
  844. varying lowp vec4 vPosition;
  845. varying lowp vec4 vNormal;
  846. varying vec4 vAmbientDiffuse;
  847. varying vec4 vPoint1Diffuse;
  848.  
  849. vec3 norm = normalize(vNormal).xyz;
  850. vec4 specColor = min(directColor + 0.5, 1.0) * shine;
  851. float radius = cos(radians(spotAngle));
  852.  
  853. void main()
  854. {
  855. vec3 cameraDirection = normalize(eyePosition - vPosition.xyz);
  856. //calculate specular light for directional light
  857. vec3 halfAngle = normalize(cameraDirection + directDirection);
  858. vec4 specDirect = specColor*pow(max(0.0, dot(norm, halfAngle)),specularPower);
  859. //calculate specular light for point light
  860. halfAngle = normalize(cameraDirection + normalize(point1Position - vPosition.xyz));
  861. vec4 specPoint = specColor*pow(max(0.0, dot(norm, halfAngle)),specularPower);
  862. //calculate strength of point light
  863. float point1Strength = max(0.0, 1.0-length(point1Position-vPosition.xyz) / point1Range);
  864. //calculate if pixel is within light radius
  865. float fracSpot;
  866. float cos = dot(point1Direction, normalize(vPosition.xyz - point1Position));
  867. if (cos>=radius && cos<=1.0) fracSpot = max(0.0, 1.0 - (1.0 - cos) / (1.0 - radius));
  868. else fracSpot = 0.0;
  869. //add it up and apply to texture pixel
  870. vec4 col=texture2D(texture, vTexCoord);
  871. col=col*(vAmbientDiffuse+specDirect+point1Strength * fracSpot * (vPoint1Diffuse+specPoint));
  872. col.a= 1.;
  873. gl_FragColor=col;
  874. }
  875. ]]
  876. }
  877.  
  878. --EVERYTHING BELOW IS UNCHANGED --
  879.  
  880. function HandleTouches()
  881. modelMatrix(currentModelMatrix) --apply the stored settings
  882. --do rotation for touch
  883. if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
  884. rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
  885. rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
  886. currentModelMatrix = modelMatrix() --store the resulting settings for next time
  887. end
  888. end
  889.  
  890. function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
  891. pos=pos or vec3(0,0,0)
  892. local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
  893. local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
  894. local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
  895. v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
  896. local texCoords
  897. if tex then
  898. local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
  899. texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
  900. t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
  901. end
  902. local n={vec3(0,0,1),vec3(1,0,0),vec3(0,0,-1),vec3(-1,0,0),vec3(0,1,0),vec3(0,-1,0)}
  903. local norm={}
  904. for i=1,6 do for j=1,6 do norm[#norm+1]=n[i] end end
  905. if not ms then ms=mesh() end
  906. if ms.size==0 then
  907. ms.vertices=vert
  908. ms.normals=norm
  909. ms.texture,ms.texCoords=tex,texCoords
  910. else
  911. for i=1,#vert do
  912. table.insert(ms.vertices,vert[i])
  913. table.insert(ms.normals,norm[i])
  914. if tex then table.insert(ms.texCoords,texCoords[i]) end
  915. end
  916. end
  917. ms:setColors(col or color(255))
  918. return ms
  919. end
  920.  
  921. function PrintExplanation()
  922. output.clear()
  923. print("A spot light is at a specific place in the scene, points in a specific direction, and usually has limited range. \n\nThis demo also shows how to add flicker (vary it with the parameter above).\n\nRotate the cube with your finger to see the effect.")
  924. end
  925.  
  926.  
  927. --# Main
  928. -- MultiStep
  929.  
  930. function setup()
  931. steps = listProjectTabs()
  932. if steps[1]=="Notes" then table.remove(steps,1) end --remove first tab if named Notes
  933. table.remove(steps) --remove the last tab
  934. startStep()
  935. global = "select a step"
  936. end
  937.  
  938. function showList()
  939. output.clear()
  940. for i=1,#steps do print(i,steps[i]) end
  941. end
  942.  
  943. function startStep()
  944. resetMatrix()
  945. if cleanup then cleanup() end
  946. lastStep=Step or readProjectData("lastStep") or 1
  947. lastStep=math.min(lastStep,#steps)
  948. saveProjectData("lastStep",lastStep)
  949. parameter.clear()
  950. parameter.integer("Step", 1, #steps, lastStep,showList)
  951. parameter.action("Run", startStep)
  952. loadstring(readProjectTab(steps[Step]))()
  953. if PrintExplanation then PrintExplanation() end
  954. setup()
  955. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement