Last active
June 23, 2019 08:45
-
-
Save dermotbalson/7706821 to your computer and use it in GitHub Desktop.
Lighting library v2
This file contains 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
--# Main | |
--Main | |
--This code manages which Code tab is run | |
--it remembers your last choice, and if you select a different one, it runs that instead | |
--This has nothing to do with 3D lighting and you can ignore it completely | |
local tabs = {} | |
local fnames = {"setup","draw","touched","collide","orientationChanged","close","restart","keyboard","cleanup"} | |
local fns = {} | |
local tabDesc={} | |
function setup() | |
for k,v in ipairs(fnames) do --store addresses of key event functions | |
fns[v] = _G[v] | |
end | |
LastCode=readProjectData("Code") or 1 --load stored tab number | |
parameter.integer("Choose_a_tab",1,#tabs,LastCode,ShowList) --tab selector | |
RunCode() | |
end | |
function ShowList() | |
output.clear() | |
for i=1,#tabs do | |
print(i,tabDesc[i]) | |
end | |
end | |
--these two functions do all the tab switching magic (thanks to Andrew_Stacey) | |
function localise(n,d) | |
if d then tabDesc[n]=d end | |
local t= {} | |
setmetatable(t,{__index = _G}) | |
setfenv(2,t) | |
tabs[n] = t | |
end | |
--change tabs | |
function RunCode() | |
output.clear() | |
saveProjectData("Code",Choose_a_tab) | |
LastCode=Choose_a_tab | |
cleanup() | |
local t = tabs[Choose_a_tab] | |
for k,v in ipairs(fnames) do | |
if t[v] then _G[v] = t[v] else _G[v] = fns[v] end -- overwrite with the new code | |
end | |
setup() | |
end | |
--default empty function to avoid errors for tabs that don't have it | |
function cleanup() | |
parameter.clear() | |
parameter.integer("Choose_a_tab",1,#tabs,LastCode,ShowList) --tab selector | |
parameter.action("Run selected tab", RunCode) | |
end | |
--# Ambient | |
--Ambient | |
if localise then localise(1,"Ambient") end | |
function setup() | |
m=mesh() --Define a test mesh | |
m:addRect(0, 0, 2,3) | |
m.shader=shader(ambientShader.vertexShader,ambientShader.fragmentShader) | |
rot={a=0} --tween to rotate rectangle | |
tween(5, rot, {a=180}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
parameter.color("SurfaceColour",color(255,255,0)) | |
parameter.color("AmbientColour",color(255,0,0)) | |
parameter.number("Strength",0,1,0.5) | |
end | |
function draw() | |
background(0) | |
perspective() | |
camera(0, 0, 0, 0, 0, -10) | |
pushMatrix() | |
translate(0, 0, -7) | |
rotate(rot.a, 0, 1, 0) | |
m:setColors(SurfaceColour) | |
--now combine the ambient colour and strength to reduce work for the shader | |
--I'm setting the ambient colour here, because you can change it with parameters | |
--I'll move it up into setup when I take those parameters away and the ambient settings become fixed | |
m.shader.ambientLight = color(AmbientColour.r*Strength,AmbientColour.g*Strength,AmbientColour.b*Strength) | |
m:draw() | |
popMatrix() | |
end | |
ambientShader = { | |
vertexShader = [[ //-- This is a standard vertex shader, nothing added | |
uniform mat4 modelViewProjection; | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
void main() | |
{ | |
vColor = color; | |
vTexCoord = texCoord; | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ | |
precision highp float; | |
uniform vec4 ambientLight; // --ambient light colour | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
void main() | |
{ | |
vec4 pixel = vColor; //--get colour of this pixel | |
//--note - we are ignoring textures for now | |
//--but when we do include them, we will set pixel based on texture lookup instead | |
gl_FragColor= pixel * ambientLight; //--apply ambient light | |
} | |
]] | |
} | |
--# Diffuse | |
--Diffuse | |
--look for the lines marked NEW | |
if localise then localise(2,"Diffuse") end | |
function setup() | |
--mesh and shader | |
m=CreateCube() --NEW cube shows light better than a rectangle | |
m.shader=shader(diffuseShader.vertexShader,diffuseShader.fragmentShader) | |
m.normals=CalculateNormals(m.vertices) --NEW calculate normals, send to shader | |
--visual effects | |
rot={x=0,y=0,z=0} --rotation of cube | |
tween(15, rot, {x=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(7, rot, {y=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(17, rot, {z=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
--user parameters and fixed light settings | |
SurfaceColour=color(255) | |
AmbientColour=color(255,255,0) | |
AmbientStrength=0.2 | |
m:setColors(SurfaceColour) | |
m.shader.ambientLight = color(AmbientColour.r*AmbientStrength,AmbientColour.g*AmbientStrength, | |
AmbientColour.b*AmbientStrength) | |
parameter.color("DirectColour",color(255,0,0)) --NEW two new parameters, the colour and strength | |
parameter.number("DirectStrength",0,1,0.5) -- of the directional light | |
end | |
function draw() | |
background(0) | |
perspective() | |
camera(0, 0, 0, 0, 0, -10) | |
pushMatrix() | |
--move and draw cube | |
translate(0, 0, -3) | |
rotate(rot.x, 1, 0, 0) rotate(rot.y,0,1,0) rotate(rot.z,0,0,1) | |
--NEW now combine the directional colour and strength to reduce work for the shader | |
m.shader.directColor=color(DirectColour.r*DirectStrength,DirectColour.g*DirectStrength, | |
DirectColour.b*DirectStrength) | |
m.shader.directDirection=vec4(-1, 0, 1,0):normalize() | |
m.shader.mModel = modelMatrix() --NEW see ebook | |
m:draw() | |
popMatrix() | |
end | |
function CalculateNormals(vertices) --NEW | |
--this assumes flat surfaces, and hard edges between triangles | |
local norm = {} | |
for i=1, #vertices,3 do --calculate normal for each set of 3 vertices | |
local n = ((vertices[i+1] - vertices[i]):cross(vertices[i+2] - vertices[i])):normalize() | |
norm[i] = n --then apply it to all 3 | |
norm[i+1] = n | |
norm[i+2] = n | |
end | |
return norm | |
end | |
diffuseShader = { | |
vertexShader = [[ | |
uniform mat4 modelViewProjection; | |
uniform mat4 mModel; //--matrix to convert from object to world space | |
uniform vec4 directColor; //--NEW directional light colour | |
uniform vec4 directDirection; //--NEW directional light direction | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; //--NEW diffuse reflection, send to fragment shader | |
void main() | |
{ | |
vColor = color; | |
vTexCoord = texCoord; | |
vec4 norm = normalize(mModel * vec4( normal, 0.0 )); //--NEW convert normal to eye space | |
//--NEW diffuse light is based on angle between light direction and normal direction | |
vDirectDiffuse = directColor * max( 0.0, dot( norm, directDirection )); | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ | |
precision highp float; | |
uniform vec4 ambientLight; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; // --NEW diffuse light | |
void main() | |
{ | |
vec4 pixel = vColor; | |
vec4 ambient = pixel * ambientLight; | |
vec4 diffuse = pixel * vDirectDiffuse; //-- NEW | |
vec4 totalColor = clamp(ambient + diffuse,0.,1.); //--NEW add ambient and diffuse,can't exceed 1 | |
totalColor.a=1.; //--NEW set alpha to 1, ie opaque | |
gl_FragColor=totalColor; | |
} | |
]] | |
} | |
function CreateCube() --NEW | |
local m = mesh() | |
--vertices for the corners of the cube (stolen from 3d lab) | |
local vertices = { | |
vec3(-0.5, -0.5, 0.5), -- Left bottom front | |
vec3( 0.5, -0.5, 0.5), -- Right bottom front | |
vec3( 0.5, 0.5, 0.5), -- Right top front | |
vec3(-0.5, 0.5, 0.5), -- Left top front | |
vec3(-0.5, -0.5, -0.5), -- Left bottom back | |
vec3( 0.5, -0.5, -0.5), -- Right bottom back | |
vec3( 0.5, 0.5, -0.5), -- Right top back | |
vec3(-0.5, 0.5, -0.5), -- Left top back | |
} | |
-- now construct a cube out of the vertices above | |
m.vertices = { | |
-- Front | |
vertices[1], vertices[2], vertices[3], | |
vertices[1], vertices[3], vertices[4], | |
-- Right | |
vertices[2], vertices[6], vertices[7], | |
vertices[2], vertices[7], vertices[3], | |
-- Back | |
vertices[6], vertices[5], vertices[8], | |
vertices[6], vertices[8], vertices[7], | |
-- Left | |
vertices[5], vertices[1], vertices[4], | |
vertices[5], vertices[4], vertices[8], | |
-- Top | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[8], | |
-- Bottom | |
vertices[5], vertices[6], vertices[2], | |
vertices[5], vertices[2], vertices[1], | |
} | |
--now texture it | |
-- all the unique texture positions needed | |
local q=.03 | |
local texvertices = { vec2(q,q), | |
vec2(1-q,q), | |
vec2(q,1-q), | |
vec2(1-q,1-q) } | |
-- apply the texture coordinates to each triangle | |
m.texCoords = { | |
-- Front | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Right | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Back | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Left | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Top | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Bottom | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
} | |
return m | |
end | |
--# Specular | |
--Specular | |
--look for the lines marked NEW | |
if localise then localise(3,"Specular") end | |
function setup() | |
--mesh and shader | |
m=CreateCube() | |
m.shader=shader(specularShader.vertexShader,specularShader.fragmentShader) | |
m.normals=CalculateNormals(m.vertices) | |
--visual effects | |
rot={x=0,y=0,z=0} --rotation of cube | |
tween(15, rot, {x=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(7, rot, {y=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(17, rot, {z=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
--user parameters and fixed light settings | |
SurfaceColour=color(255) | |
AmbientColour=color(255,255,0) | |
AmbientStrength=0.2 | |
m:setColors(SurfaceColour) | |
m.shader.ambientLight = color(AmbientColour.r*AmbientStrength,AmbientColour.g*AmbientStrength, | |
AmbientColour.b*AmbientStrength) | |
DirectColour=color(255,0,0) | |
DirectStrength=0.8 | |
m.shader.directColor=color(DirectColour.r*DirectStrength,DirectColour.g*DirectStrength, | |
DirectColour.b*DirectStrength) | |
m.shader.directDirection=vec4(-1, 0, 1,0):normalize() | |
m.shader.specularColor=color(255) --NEW specular setting | |
m.shader.reflect=1 --NEW applies to all reflections, set for full reflection | |
m.shader.shiny=0.6 --NEW, applies only to specular, mostly shiny | |
camPos=vec3(0, 0, 0) | |
m.shader.eyePosition=vec4(camPos.x, camPos.y, camPos.z,1) | |
end | |
function draw() | |
background(0) | |
perspective() | |
camera(camPos.x, camPos.y, camPos.z, 0, 0, -10) | |
pushMatrix() | |
--move and draw cube | |
translate(0, 0, -3) | |
rotate(rot.x, 1, 0, 0) rotate(rot.y,0,1,0) rotate(rot.z,0,0,1) | |
m.shader.mModel = modelMatrix() | |
m:draw() | |
popMatrix() | |
end | |
function CalculateNormals(vertices) | |
local norm = {} | |
for i=1, #vertices,3 do | |
local n = ((vertices[i+1] - vertices[i]):cross(vertices[i+2] - vertices[i])):normalize() | |
norm[i] = n | |
norm[i+1] = n | |
norm[i+2] = n | |
end | |
return norm | |
end | |
specularShader = { | |
vertexShader = [[ | |
uniform mat4 modelViewProjection; | |
uniform mat4 mModel; | |
uniform vec4 directColor; | |
uniform vec4 directDirection; | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; | |
varying lowp vec4 vPosition; //--NEW (x,y,z) position of vertex in eye space | |
varying lowp vec4 vNormal; //--NEW normal of vertex in eye space | |
void main() | |
{ | |
vColor = color; | |
vTexCoord = texCoord; | |
vPosition = mModel * position; | |
vNormal = mModel * vec4( normal, 0.0 ); | |
vec4 norm = normalize(vNormal); | |
vDirectDiffuse = directColor * max( 0.0, dot( norm, directDirection )); | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ //--NEW almost all the changes are in here | |
precision highp float; | |
uniform vec4 ambientLight; | |
uniform vec4 directDirection; | |
uniform float reflect; //--NEW | |
uniform float shiny; //--NEW | |
uniform vec4 specularColor; //--NEW | |
uniform vec4 eyePosition; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; | |
varying lowp vec4 vPosition; | |
varying lowp vec4 vNormal; | |
vec4 normalizedNormal = normalize(vNormal); | |
// --NEW specular light, uses Blinn-Phong half vector approach, faster than Phong | |
vec4 GetSpecularColor(vec4 lightPosition) | |
{ | |
vec4 cameraDirection = normalize( eyePosition - vPosition ); | |
vec4 halfAngle = normalize( cameraDirection + lightPosition ); | |
vec4 specularColor = min(specularColor + 0.5, 1.0); | |
float spec = pow( max( 0.0, dot( normalizedNormal, halfAngle)), 32.0 ); | |
return specularColor * spec; | |
} | |
void main() | |
{ | |
vec4 pixel = vColor; | |
vec4 ambient = ambientLight; | |
vec4 diffuse = vDirectDiffuse; | |
vec4 specular = GetSpecularColor( directDirection ); //--NEW | |
vec4 totalColor = clamp(pixel * reflect * (ambient + diffuse + specular * shiny),0.,1.); | |
totalColor.a=1.; | |
gl_FragColor=totalColor; | |
} | |
]] | |
} | |
function CreateCube() | |
local m = mesh() | |
--vertices for the corners of the cube (stolen from 3d lab) | |
local vertices = { | |
vec3(-0.5, -0.5, 0.5), -- Left bottom front | |
vec3( 0.5, -0.5, 0.5), -- Right bottom front | |
vec3( 0.5, 0.5, 0.5), -- Right top front | |
vec3(-0.5, 0.5, 0.5), -- Left top front | |
vec3(-0.5, -0.5, -0.5), -- Left bottom back | |
vec3( 0.5, -0.5, -0.5), -- Right bottom back | |
vec3( 0.5, 0.5, -0.5), -- Right top back | |
vec3(-0.5, 0.5, -0.5), -- Left top back | |
} | |
-- now construct a cube out of the vertices above | |
m.vertices = { | |
-- Front | |
vertices[1], vertices[2], vertices[3], | |
vertices[1], vertices[3], vertices[4], | |
-- Right | |
vertices[2], vertices[6], vertices[7], | |
vertices[2], vertices[7], vertices[3], | |
-- Back | |
vertices[6], vertices[5], vertices[8], | |
vertices[6], vertices[8], vertices[7], | |
-- Left | |
vertices[5], vertices[1], vertices[4], | |
vertices[5], vertices[4], vertices[8], | |
-- Top | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[8], | |
-- Bottom | |
vertices[5], vertices[6], vertices[2], | |
vertices[5], vertices[2], vertices[1], | |
} | |
--now texture it | |
-- all the unique texture positions needed | |
local q=.03 | |
local texvertices = { vec2(q,q), | |
vec2(1-q,q), | |
vec2(q,1-q), | |
vec2(1-q,1-q) } | |
-- apply the texture coordinates to each triangle | |
m.texCoords = { | |
-- Front | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Right | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Back | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Left | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Top | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Bottom | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
} | |
return m | |
end | |
--# Point | |
--Point | |
--look for the lines marked NEW | |
if localise then localise(4,"Point") end | |
function setup() | |
--mesh and shader | |
m=CreateCube() | |
m.shader=shader(pointShader.vertexShader,pointShader.fragmentShader) | |
m.normals=CalculateNormals(m.vertices) | |
--visual effects | |
rot={x=0,y=0,z=0} --rotation of cube | |
tween(15, rot, {x=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(7, rot, {y=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(17, rot, {z=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
--move cube back and forwards | |
cubePos={x=0,y=0,z=-10} | |
tween(9, cubePos, {z=-2}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
--user parameters and fixed light settings | |
SurfaceColour=color(255) | |
AmbientColour=color(255,255,0) | |
AmbientStrength=0.2 | |
m:setColors(SurfaceColour) | |
m.shader.ambientLight = color(AmbientColour.r*AmbientStrength,AmbientColour.g*AmbientStrength, | |
AmbientColour.b*AmbientStrength) | |
DirectColour=color(255,0,0) | |
DirectStrength=0.8 | |
m.shader.directColor=color(DirectColour.r*DirectStrength,DirectColour.g*DirectStrength, | |
DirectColour.b*DirectStrength) | |
m.shader.directDirection=vec4(-1, 0, 1, 1) | |
m.shader.specularColor=color(255) | |
m.shader.reflect=1 | |
m.shader.shiny=0.6 | |
camPos=vec3(0, 0, 0) | |
m.shader.eyePosition=vec4(camPos.x, camPos.y, camPos.z,1) | |
parameter.integer("Point_Range",0,20,10) --NEW set range of the light | |
end | |
function draw() | |
background(0) | |
perspective() | |
camera(camPos.x, camPos.y, camPos.z, 0, 0, -10) | |
pushMatrix() | |
--move and draw cube | |
translate(cubePos.x, cubePos.y, cubePos.z) | |
rotate(rot.x, 1, 0, 0) rotate(rot.y,0,1,0) rotate(rot.z,0,0,1) | |
m.shader.mModel = modelMatrix() | |
m.shader.pointRange=Point_Range --NEW | |
m:draw() | |
popMatrix() | |
end | |
function CalculateNormals(vertices) | |
local norm = {} | |
for i=1, #vertices,3 do | |
local n = ((vertices[i+1] - vertices[i]):cross(vertices[i+2] - vertices[i])):normalize() | |
norm[i] = n | |
norm[i+1] = n | |
norm[i+2] = n | |
end | |
return norm | |
end | |
pointShader = { | |
vertexShader = [[ | |
uniform mat4 modelViewProjection; | |
uniform mat4 mModel; //matrix to convert from object to world space | |
uniform vec4 directColor; | |
uniform vec4 directDirection; | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; | |
varying lowp vec4 vPosition; | |
varying lowp vec4 vNormal; | |
void main() | |
{ | |
vColor = color; | |
vTexCoord = texCoord; | |
vPosition = mModel * position; | |
vNormal = mModel * vec4( normal, 0.0 ); | |
vec4 norm = normalize(vNormal); | |
vec4 d = normalize( directDirection - vPosition ); | |
vDirectDiffuse = directColor * max( 0.0, dot( norm, d )); | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ | |
precision highp float; | |
uniform vec4 ambientLight; | |
uniform vec4 directDirection; | |
uniform float pointRange; //--NEW | |
uniform float reflect; | |
uniform float shiny; | |
uniform vec4 specularColor; | |
uniform vec4 eyePosition; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; | |
varying lowp vec4 vPosition; | |
varying lowp vec4 vNormal; | |
vec4 normalizedNormal = normalize(vNormal); | |
vec4 GetSpecularColor(vec4 lightPosition) | |
{ | |
vec4 lightDirection = normalize( lightPosition - vPosition ); | |
vec4 cameraDirection = normalize( eyePosition - vPosition ); | |
vec4 halfAngle = normalize( cameraDirection + lightDirection ); | |
vec4 specularColor = min(specularColor + 0.5, 1.0); | |
float spec = pow( max( 0.0, dot( normalizedNormal, halfAngle)), 32.0 ); | |
return specularColor * spec; | |
} | |
void main() | |
{ | |
vec4 pixel = vColor; | |
vec4 ambient = ambientLight; | |
vec4 diffuse = vDirectDiffuse; | |
vec4 specular = GetSpecularColor( directDirection ); | |
//--NEW now calculate attenuation | |
float attenuation = max( 0.0, 1.0 - length( directDirection - vPosition ) / pointRange ); | |
vec4 totalColor = clamp(pixel * reflect * attenuation * (ambient + diffuse + specular * shiny),0.,1.); | |
totalColor.a=1.; | |
gl_FragColor=totalColor; | |
} | |
]] | |
} | |
function CreateCube() | |
local m = mesh() | |
--vertices for the corners of the cube (stolen from 3d lab) | |
local vertices = { | |
vec3(-0.5, -0.5, 0.5), -- Left bottom front | |
vec3( 0.5, -0.5, 0.5), -- Right bottom front | |
vec3( 0.5, 0.5, 0.5), -- Right top front | |
vec3(-0.5, 0.5, 0.5), -- Left top front | |
vec3(-0.5, -0.5, -0.5), -- Left bottom back | |
vec3( 0.5, -0.5, -0.5), -- Right bottom back | |
vec3( 0.5, 0.5, -0.5), -- Right top back | |
vec3(-0.5, 0.5, -0.5), -- Left top back | |
} | |
-- now construct a cube out of the vertices above | |
m.vertices = { | |
-- Front | |
vertices[1], vertices[2], vertices[3], | |
vertices[1], vertices[3], vertices[4], | |
-- Right | |
vertices[2], vertices[6], vertices[7], | |
vertices[2], vertices[7], vertices[3], | |
-- Back | |
vertices[6], vertices[5], vertices[8], | |
vertices[6], vertices[8], vertices[7], | |
-- Left | |
vertices[5], vertices[1], vertices[4], | |
vertices[5], vertices[4], vertices[8], | |
-- Top | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[8], | |
-- Bottom | |
vertices[5], vertices[6], vertices[2], | |
vertices[5], vertices[2], vertices[1], | |
} | |
--now texture it | |
-- all the unique texture positions needed | |
local q=.03 | |
local texvertices = { vec2(q,q), | |
vec2(1-q,q), | |
vec2(q,1-q), | |
vec2(1-q,1-q) } | |
-- apply the texture coordinates to each triangle | |
m.texCoords = { | |
-- Front | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Right | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Back | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Left | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Top | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Bottom | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
} | |
return m | |
end | |
--# Spot | |
--Point | |
--look for the lines marked NEW | |
if localise then localise(5,"Spot") end | |
function setup() | |
--mesh and shader | |
m=CreateCube() | |
m.shader=shader(spotShader.vertexShader,spotShader.fragmentShader) | |
m.normals=CalculateNormals(m.vertices) | |
--visual effects | |
rot={x=0,y=0,z=0} --rotation of cube | |
tween(15, rot, {x=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(7, rot, {y=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
tween(17, rot, {z=360}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
--move cube back and forwards | |
cubePos={x=0,y=0,z=-10} | |
tween(9, cubePos, {z=-2}, { easing = tween.easing.linear, loop = tween.loop.pingpong }) | |
--user parameters and fixed light settings | |
SurfaceColour=color(255) | |
AmbientColour=color(255,255,0) | |
AmbientStrength=0.2 | |
m:setColors(SurfaceColour) | |
m.shader.ambientLight = color(AmbientColour.r*AmbientStrength,AmbientColour.g*AmbientStrength, | |
AmbientColour.b*AmbientStrength) | |
DirectColour=color(255,0,0) | |
DirectStrength=0.8 | |
m.shader.directColor=color(DirectColour.r*DirectStrength,DirectColour.g*DirectStrength, | |
DirectColour.b*DirectStrength) | |
m.shader.directDirection=vec4(-1, 0, 1, 1) | |
m.shader.specularColor=color(255) | |
m.shader.reflect=1 | |
m.shader.shiny=0.6 | |
camPos=vec3(0, 0, 0) | |
m.shader.eyePosition=vec4(camPos.x, camPos.y, camPos.z,1) | |
m.shader.spotDirection=vec4(0.5,0,-2,0):normalize() --NEW a spotlight points in a certain direction | |
parameter.integer("Point_Range",0,20,10) --NEW a spotlight has a range | |
parameter.integer("Spot_Radius",0,40,5) --NEW and its light beam has a radius | |
end | |
function draw() | |
background(0) | |
perspective() | |
camera(camPos.x, camPos.y, camPos.z, 0, 0, -10) | |
pushMatrix() | |
--move and draw cube | |
translate(cubePos.x, cubePos.y, cubePos.z) | |
rotate(rot.x, 1, 0, 0) rotate(rot.y,0,1,0) rotate(rot.z,0,0,1) | |
m.shader.mModel = modelMatrix() | |
m.shader.pointRange=Point_Range --NEW | |
--calculate the cos value which tells us if a pixel is within the light beam | |
m.shader.pointCos=math.cos(math.rad(Spot_Radius)) --NEW | |
m:draw() | |
popMatrix() | |
end | |
function CalculateNormals(vertices) | |
local norm = {} | |
for i=1, #vertices,3 do | |
local n = ((vertices[i+1] - vertices[i]):cross(vertices[i+2] - vertices[i])):normalize() | |
norm[i] = n | |
norm[i+1] = n | |
norm[i+2] = n | |
end | |
return norm | |
end | |
spotShader = { | |
vertexShader = [[ | |
uniform mat4 modelViewProjection; | |
uniform mat4 mModel; | |
uniform vec4 directColor; | |
uniform vec4 directDirection; | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; | |
varying lowp vec4 vPosition; | |
varying lowp vec4 vNormal; | |
void main() | |
{ | |
vColor = color; | |
vTexCoord = texCoord; | |
vPosition = mModel * position; | |
vNormal = mModel * vec4( normal, 0.0 ); | |
vec4 norm = normalize(vNormal); | |
vec4 d = normalize( directDirection - vPosition ); | |
vDirectDiffuse = directColor * max( 0.0, dot( norm, d )); | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ | |
precision highp float; | |
uniform vec4 ambientLight; | |
uniform vec4 directDirection; | |
uniform vec4 spotDirection; | |
uniform float pointRange; | |
uniform float pointCos; | |
uniform float reflect; | |
uniform float shiny; | |
uniform vec4 specularColor; | |
uniform vec4 eyePosition; | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
varying vec4 vDirectDiffuse; | |
varying lowp vec4 vPosition; | |
varying lowp vec4 vNormal; | |
vec4 normalizedNormal = normalize(vNormal); | |
vec4 GetSpecularColor(vec4 lightPosition) | |
{ | |
vec4 lightDirection = normalize( lightPosition - vPosition ); | |
vec4 cameraDirection = normalize( eyePosition - vPosition ); | |
vec4 halfAngle = normalize( cameraDirection + lightDirection ); | |
vec4 specularColor = min(specularColor + 0.5, 1.0); | |
float spec = pow( max( 0.0, dot( normalizedNormal, halfAngle)), 32.0 ); | |
return specularColor * spec; | |
} | |
lowp float GetSpotValue() //--NEW | |
{ | |
//--get vector from light to current pixel | |
vec4 lightToPixel = normalize( vPosition - directDirection ); | |
//--calculate cos of angle | |
float cos = dot( spotDirection, lightToPixel ); | |
//---compare with max cos of spotlight, interpolate if within its beam | |
if ( cos >= pointCos && cos <= 1.0 ) { | |
return max( 0.0, 1.0 - ( 1.0 - cos ) / ( 1.0 - pointCos )); | |
} | |
else return 0.0; | |
} | |
void main() | |
{ | |
vec4 pixel = vColor; | |
vec4 ambient = ambientLight; | |
vec4 diffuse = vDirectDiffuse; | |
vec4 specular = GetSpecularColor( directDirection ); | |
float attenuation = max( 0.0, 1.0 - length( directDirection.xyz - vPosition.xyz ) / pointRange ); | |
vec4 totalColor = clamp(pixel * reflect * attenuation * | |
GetSpotValue() * (ambient + diffuse + specular * shiny),0.,1.); | |
totalColor.a=1.; | |
gl_FragColor=totalColor; | |
} | |
]] | |
} | |
function CreateCube() | |
local m = mesh() | |
--vertices for the corners of the cube (stolen from 3d lab) | |
local vertices = { | |
vec3(-0.5, -0.5, 0.5), -- Left bottom front | |
vec3( 0.5, -0.5, 0.5), -- Right bottom front | |
vec3( 0.5, 0.5, 0.5), -- Right top front | |
vec3(-0.5, 0.5, 0.5), -- Left top front | |
vec3(-0.5, -0.5, -0.5), -- Left bottom back | |
vec3( 0.5, -0.5, -0.5), -- Right bottom back | |
vec3( 0.5, 0.5, -0.5), -- Right top back | |
vec3(-0.5, 0.5, -0.5), -- Left top back | |
} | |
-- now construct a cube out of the vertices above | |
m.vertices = { | |
-- Front | |
vertices[1], vertices[2], vertices[3], | |
vertices[1], vertices[3], vertices[4], | |
-- Right | |
vertices[2], vertices[6], vertices[7], | |
vertices[2], vertices[7], vertices[3], | |
-- Back | |
vertices[6], vertices[5], vertices[8], | |
vertices[6], vertices[8], vertices[7], | |
-- Left | |
vertices[5], vertices[1], vertices[4], | |
vertices[5], vertices[4], vertices[8], | |
-- Top | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[8], | |
-- Bottom | |
vertices[5], vertices[6], vertices[2], | |
vertices[5], vertices[2], vertices[1], | |
} | |
--now texture it | |
-- all the unique texture positions needed | |
local q=.03 | |
local texvertices = { vec2(q,q), | |
vec2(1-q,q), | |
vec2(q,1-q), | |
vec2(1-q,1-q) } | |
-- apply the texture coordinates to each triangle | |
m.texCoords = { | |
-- Front | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Right | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Back | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Left | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Top | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
-- Bottom | |
texvertices[1], texvertices[2], texvertices[4], | |
texvertices[1], texvertices[4], texvertices[3], | |
} | |
return m | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code does not run in the current version of Codea. Setfenv is not supported in Lua 5.2+.