Lighting 11
--# 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.reflec=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 reflec; //--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 * reflec * (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.reflec=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 reflec; | |
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 * reflec * 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.reflec=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 reflec; | |
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 * reflec * 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