Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created September 30, 2015 02:04
Show Gist options
  • Save dermotbalson/07e5632074ddbf105d6c to your computer and use it in GitHub Desktop.
Save dermotbalson/07e5632074ddbf105d6c to your computer and use it in GitHub Desktop.
SBS Lighting v1
--# Notes
--[[
This project shows how to add different types of lighting to 3D scenes (in this case, a cube)
--HOW TO USE THIS PROJECT
There are a number of tabs at the top. Press on a tab to see its code.
Work through the tabs from left to right, to see the project develop
You can run the code in any of the project tabs, by
1. running the program, and
2. selecting the tab number using the controls at the upper left of the screen
The program will remember your selection after that.
This enables you to work with one tab at a time, make changes and see the effects by running the program
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
IMPORTANT NOTES
1. Lighting requires the use of shaders. While you can use this code as a black box, it is
preferable that you understand how it works, so you can make changes or fix problems yourself.
2. It may be difficult to learn how lighting works just from looking at these demos. Ideally, you should
try to learn the basics of diffuse and specular light first.
--]]
--# Ambient
--Ambient light
--[[
Ambient light is the general lighting level
You could call it the minimum light that falls on every surface
if it is 0, then anything that is not lit will be pitch black
if it is 1, then everything is fully lit all the time
As you might guess, it is pretty simple - you just multiply the light level by the ambient factor
There's just one thing - the ambient light doesn't have to be white, so we specify the light colour
and everything will be tinted by this colour (see the extra parameter provided for this)
You are unlikely ever to use just ambient light on its own.
--]]
function setup()
block=CreateBlock(1,0.5,0.75,"Cargo Bot:Starry Background")
currentModelMatrix=modelMatrix() --this is used for touches, not lighting
SetupShader()
end
--All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
function SetupShader() --set up the lighting
--in these demos, you get to change some of the lighting options using parameters
--in your own apps, you will probably just set the lighting values yourself
parameter.number("ambientStrength", 0, 1, 0.6) -- level of ambient light (0=dark, 1=light)
parameter.color("ambientColor", color(255,255,255,255)) --- colour of ambient light
block.shader=shader(AmbientShader.vertexShader,AmbientShader.fragmentShader)
end
function UpdateShader() --update the lighting details before drawing
--if you aren't going to be changing ambient colour or strength, you can put this line in setup
block.shader.ambient = ambientColor*ambientStrength
end
--this shader has ambient lighting
AmbientShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
uniform vec4 ambient; // ambient light
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
vColor = color*ambient; // apply ambient light to object colour and pass to fragment shader
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
lowp vec4 col = texture2D( texture, vTexCoord) * vColor; //apply ambient light to texture
col.a = 1.0;
gl_FragColor = col;
}
]]
}
--UTILITY CODE - IT WILL NOT CHANGE FROM HERE ON --
function draw()
background(220)
perspective()
camera(-1,1,2,0,0,0)
HandleTouches() --allows you to rotate the cube with your fingers
UpdateShader()
block:draw()
end
--this code manages touches so you can rotate the cube
function HandleTouches()
modelMatrix(currentModelMatrix) --apply the stored settings
--do rotation for touch
if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
currentModelMatrix = modelMatrix() --store the resulting settings for next time
end
end
--this function creates a cube
function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
pos=pos or vec3(0,0,0)
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
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)}
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],
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]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
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],
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]}
end
local norm={} --calculate normals
for i=1,#vert,3 do
local n=GetNormal(vert[i],vert[i+1],vert[i+2])
norm[i],norm[i+1],norm[i+2]=n,n,n
end
if not ms then ms=mesh() end
if ms.size==0 then
ms.vertices=vert
ms.normals=norm
ms.texture,ms.texCoords=tex,texCoords
else
for i=1,#vert do
table.insert(ms.vertices,vert[i])
table.insert(ms.normals,norm[i])
if tex then table.insert(ms.texCoords,texCoords[i]) end
end
end
ms:setColors(col or color(255))
return ms
end
function GetNormal(v1,v2,v3)
return ((v1-v3):cross(v2-v3)):normalize()
end
function PrintExplanation()
output.clear()
print("Ambient light is the general background light that shines equally on all sides of an object")
print("Use a finger to rotate the cube")
end
--# Diffuse
--Diffuse
--[[
The sun is so far away that its light comes from the same direction for every part of your scene, and the
strength of the light is also the same across your scene. This is diffuse light - coming from a single direction
with a constant colour strength.
Diffuse light can have any colour, but because it is added to ambient light, the total of the two should not
generally exceed 255. In other words, ambient + diffuse <= color(255)
For example, you might use
ambient = color(255) * 0.3 --dim white light
diffuse = color(255,0,0) * 0.7 --red light
When you add these together, the maximum light is color(255,76,76)
Diffuse light is caused by reflection, and is brightest for any object directly facing the light, reducing if the
light hits the object at an angle.
Our objects are made from triangles of vertices. These triangles are flat surfaces, and the direction they are
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
'normal' direction - and if that is facing the diffuse light source, the light will be brightest.
You need two things to calculate the amount of diffuse light for any triangle
1. its 'normal' direction
2. a way of measuring how similar this is to the direction that the diffuse light is coming from
This demo provides a function for calculating the normal of any set of three vertices, and Codea meshes have a
normals property, so if you have a mesh m and a table of normals n, you can write
m.normals = n
(see the CreateBlock function below for an example)
The dot function is a convenient way of measuring the similarity of two directions, and that is used in the
shader to calculate the amount of reflection.
Note that because the normals are the same for all the vertices in each triangle, they will be the same for each
point in that triangle. So we can calculate diffuse light in the vertex shader, rather than the fragment shader,
which is much more efficient.
To set the direction the diffuse light is coming from, imagine a line running from (0,0,0) towards the diffuse
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
usual, here are some examples
vec3(-1,0,0) --a light that shines from left to right (no need to normalize, it already has length 1)
vec3(0,1,0) --a light that shines down vertically (again, no need to normalise)
vec3(-1,0.5,1):normalize() --a light that comes from behind me over my left shoulder
The absolute size of the numbers you use for x,y,z doesn't matter, since
vec3(1,2,-3):normalize() = vec3(10,20,-30):normalize()
but of course the relative size (how big x is, relative to y and z, for example) does matter..
--]]
function setup()
block=CreateBlock(1,0.5,0.75,"Cargo Bot:Starry Background")
currentModelMatrix=modelMatrix()
SetupShader()
end
--All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
function SetupShader() --set up the lighting
--in your own apps, you will probably just set these lighting values yourself instead of using parameters
parameter.number("diffuseStrength", 0, 1, 0.7) --brightness of light source -- ***** NEW
parameter.color("lightColor", color(255)) -- ***** NEW
block.shader=shader(DiffuseShader.vertexShader,DiffuseShader.fragmentShader)
block.shader.ambientColor = color(255)*0.5
block.shader.directDirection = vec3(-1,0,1):normalize() -- ****** NEW
end
function UpdateShader() --update the lighting details before drawing
--if you aren't going to be changing colours or light strength, you can put the next line in setup
block.shader.directColor=diffuseStrength*lightColor -- ****** NEW
block.shader.mModel=modelMatrix() --this must be updated each time you draw
end
--shader follows
DiffuseShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
uniform vec4 ambientColor;
uniform vec3 directDirection; // ****** NEW
uniform vec4 directColor; // ****** NEW
uniform mat4 mModel; // ****** NEW
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal; // **** NEW
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
vec4 norm = normalize(mModel * vec4( normal, 0.0 )); // ****** NEW
float diffuse = max( 0.0, dot( norm.xyz, directDirection )); // ****** NEW
vColor = ambientColor + diffuse * directColor; // ****** NEW
vColor.a = 1.0;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
gl_FragColor = texture2D( texture, vTexCoord) * vColor;
}
]]
}
--EVERYTHING BELOW IS UNCHANGED --
function draw()
background(220)
perspective()
camera(-1,1,2,0,0,0)
HandleTouches()
UpdateShader()
block:draw()
end
function HandleTouches()
modelMatrix(currentModelMatrix) --apply the stored settings
--do rotation for touch
if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
currentModelMatrix = modelMatrix() --store the resulting settings for next time
end
end
function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
pos=pos or vec3(0,0,0)
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
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)}
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],
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]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
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],
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]}
end
local norm={} --calculate normals
for i=1,#vert,3 do
local n=GetNormal(vert[i],vert[i+1],vert[i+2])
norm[i],norm[i+1],norm[i+2]=n,n,n
end
if not ms then ms=mesh() end
if ms.size==0 then
ms.vertices=vert
ms.normals=norm
ms.texture,ms.texCoords=tex,texCoords
else
for i=1,#vert do
table.insert(ms.vertices,vert[i])
table.insert(ms.normals,norm[i])
if tex then table.insert(ms.texCoords,texCoords[i]) end
end
end
ms:setColors(col or color(255))
return ms
end
function GetNormal(v1,v2,v3)
return ((v1-v3):cross(v2-v3)):normalize()
end
function PrintExplanation()
output.clear()
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")
print("The part of the object facing the light direction will be lit the most")
print("Use a finger to rotate the cube")
end
--# Specular
--Specular
--[[
Specular light is the reflection from a light source into your eye (the bright spot!)
It is too complex to explain fully here, but it needs the camera position
The extra shader settings below are
* specularPower = how focussed and concentrated the light is. Use a power of 2, eg 1,2,4,8,16,32,64,...
* shine - how shiny the object is (0 to 1)
* eyePosition - (vec3(x,y,z) position of camera
--]]
function setup()
block=CreateBlock(1,0.5,0.75,"Cargo Bot:Starry Background")
currentModelMatrix=modelMatrix()
camPos=vec3(0,0,2) -- ***** NEW
z,zd=0,-.01 --to move block back and forward
SetupShader()
end
--All the lighting code is kept in these two functions to make it easier for you to see it and use it yourself
function SetupShader() --set up the lighting
--in your own apps, you will probably just set the specular power yourself instead of using parameters
parameter.integer("Focus",1,10,5) --this will be a power of 2, eg we will convert 3 to 2^3 = 8
--set position of light source
block.shader=shader(SpecularShader.vertexShader,SpecularShader.fragmentShader)
block.shader.ambientColor = color(255) *0.5
block.shader.directColor=color(255) *0.7
block.shader.directDirection = vec3(1,0,1):normalize()
block.shader.shine=1 -- ***** NEW
end
function UpdateShader() --update the lighting details before drawing
block.shader.specularPower=2^Focus -- ***** NEW
block.shader.mModel=modelMatrix() --this must be updated each time you draw
block.shader.eyePosition=camPos -- ***** NEW
block.shader.mModel=modelMatrix()
end
function draw()
background(220)
perspective()
currentModelMatrix[15]=z
camera(camPos.x,camPos.y,camPos.z,0,0,0)
HandleTouches()
UpdateShader()
block:draw()
z=z+zd
if z<-3 or z>0 then zd=-zd end
end
--shader follows
SpecularShader={
vertexShader=[[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec4 directColor;
uniform vec3 directDirection;
uniform vec4 ambientColor;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vPosition;
varying lowp vec4 vNormal;
varying vec4 vLight;
void main()
{
vColor = color;
vTexCoord = texCoord;
vPosition = mModel * position;
gl_Position = modelViewProjection * position;
vNormal = mModel * vec4( normal, 0.0 );
vLight = ambientColor+directColor * max( 0.0, dot( normalize(vNormal.xyz), directDirection ));
}
]],
fragmentShader=[[
precision highp float;
uniform lowp sampler2D texture;
uniform vec4 directColor;
uniform vec3 directDirection;
uniform vec3 eyePosition;
uniform float specularPower;
uniform float shine;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vPosition;
varying lowp vec4 vNormal;
varying vec4 vLight;
vec4 norm = normalize(vNormal);
vec4 eye = vec4(eyePosition, 1.0);
vec4 direct = vec4(directDirection, 0.0);
void main()
{
vec4 cameraDirection = normalize( eye - vPosition );
vec4 halfAngle = normalize( cameraDirection + direct );
float spec = pow( max( 0.0, dot( norm, halfAngle)),specularPower);
vec4 totalColor=texture2D(texture, vTexCoord)*(vLight+min(directColor + 0.5, 1.0) * spec * shine );
totalColor.a= 1.;
gl_FragColor=totalColor;
}
]]
}
--EVERYTHING BELOW IS UNCHANGED --
function HandleTouches()
modelMatrix(currentModelMatrix) --apply the stored settings
--do rotation for touch
if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
currentModelMatrix = modelMatrix() --store the resulting settings for next time
end
end
function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
pos=pos or vec3(0,0,0)
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
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)}
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],
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]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
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],
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]}
end
local norm={} --calculate normals
for i=1,#vert,3 do
local n=GetNormal(vert[i],vert[i+1],vert[i+2])
norm[i],norm[i+1],norm[i+2]=n,n,n
end
if not ms then ms=mesh() end
if ms.size==0 then
ms.vertices=vert
ms.normals=norm
ms.texture,ms.texCoords=tex,texCoords
else
for i=1,#vert do
table.insert(ms.vertices,vert[i])
table.insert(ms.normals,norm[i])
if tex then table.insert(ms.texCoords,texCoords[i]) end
end
end
ms:setColors(col or color(255))
return ms
end
function GetNormal(v1,v2,v3)
return ((v1-v3):cross(v2-v3)):normalize()
end
function PrintExplanation()
output.clear()
print("Specular light adds a bright spot to the reflection")
print("The brightness depends on how much the light reflects off the surface toward the camera")
print("Use a finger to rotate the cube")
end
--# Point
--Point
--Point light is light from a point in space (rather than from a direction, like diffuse light)
function setup()
block=CreateBlock(1,0.5,0.75,"Cargo Bot:Starry Background")
block.shader=shader(ADSLighting.vertexShader,ADSLighting.fragmentShader)
--set position of light source
parameter.number("ambientStrength", 0, 1, 0.3)
parameter.color("ambientColor", color(255,255,255,255))
parameter.number("diffuseStrength", 0, 1, 0.7) --brightness of light source
parameter.color("lightColor", color(255,255,255,255))
block.shader.eyePosition = vec4(0,0,3,1) --- **** NEW
currentModelMatrix=modelMatrix()
camPos=vec3(0,0,2)
z,zd=0,-.01
end
function draw()
background(0)
perspective()
camera(camPos.x,camPos.y,camPos.z,0,0,0)
currentModelMatrix[15]=z --=currentModelMatrix:translate(0,0,zd)
HandleTouches()
block.shader.mModel=modelMatrix()
block.shader.directColor=diffuseStrength*lightColor*0
block.shader.directDirection = vec4(0,0,1,0):normalize()
block.shader.ambientColor = ambientStrength*ambientColor --- ****** NEW
block.shader.point1Position=vec4(1,1,1,1):normalize()
block.shader.point1Color=color(255)
block.shader.eyePosition=camPos
block.shader.shine=0
block.shader.point1Range=3
block.shader.point1Strength=1
block:draw()
z=z+zd
if z<-3 or z>0 then zd=-zd end
end
--shader follows
ADSLighting={
vertexShader=[[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec4 directColor;
uniform vec4 directDirection;
uniform vec4 ambientColor;
uniform vec4 point1Position;
uniform vec4 point1Color;
uniform float point1Strength;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vPosition;
varying lowp vec4 vNormal;
varying vec4 vLight;
varying vec4 vPoint1Diffuse;
void main()
{
vColor = color;
vTexCoord = texCoord;
vPosition = mModel * position;
gl_Position = modelViewProjection * position;
vNormal = mModel * vec4( normal, 0.0 );
vec4 norm = normalize(vNormal);
vLight = ambientColor+directColor * max( 0.0, dot( norm, directDirection ));
vec4 d = normalize( point1Position - vPosition );
vPoint1Diffuse = point1Color * point1Strength * max( 0.0, dot( norm, d ));
}
]],
fragmentShader=[[
precision highp float;
uniform lowp sampler2D texture;
uniform vec4 directColor;
uniform vec4 directDirection;
uniform vec4 eyePosition;
uniform float shine;
uniform vec4 point1Position;
uniform float point1Range;
uniform vec4 point1Color;
uniform float point1Strength;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vPosition;
varying lowp vec4 vNormal;
varying vec4 vLight;
varying vec4 vPoint1Diffuse;
vec4 normalizedNormal = normalize(vNormal);
vec4 GetSpecularColor(vec4 lightPosition, vec4 lightColor, bool IsDirectional)
{
vec4 lightDirection;
if (IsDirectional) lightDirection = lightPosition;
else lightDirection = vec4( normalize( lightPosition - vPosition ));
vec4 cameraDirection = normalize( eyePosition - vPosition );
vec4 halfAngle = normalize( cameraDirection + lightDirection );
vec4 specularColor = min(lightColor + 0.5, 1.0);
float spec = pow( max( 0.0, dot( normalizedNormal, halfAngle)), 32.0 );
return specularColor * spec * shine;
}
void main()
{
lowp vec4 specular=GetSpecularColor(directDirection, directColor, true);
float point1Attenuation = max( 0.0, 1.0 - length( point1Position.xyz - vPosition.xyz ) / point1Range );
lowp vec4 point = point1Strength * point1Attenuation * GetSpecularColor(point1Position, point1Color, false);
vec4 col = texture2D(texture, vTexCoord) * (vLight + point1Attenuation * vPoint1Diffuse + specular + point);
col.a=1.;
gl_FragColor=col;
}
]]
}
--EVERYTHING BELOW IS UNCHANGED --
function HandleTouches()
modelMatrix(currentModelMatrix) --apply the stored settings
--do rotation for touch
if CurrentTouch.state == MOVING then --only rotate while fingers are moving on the screen
rotate(CurrentTouch.deltaX,0,1,0) --rotate by the x change, on the y axis (see note below)
rotate(CurrentTouch.deltaY,1,0,0) --and by the y change, on the x axis (see note below)
currentModelMatrix = modelMatrix() --store the resulting settings for next time
end
end
function CreateBlock(w,h,d,tex,col,pos,ms) --width,height,depth,texture,colour,position,mesh (if existing already)
pos=pos or vec3(0,0,0)
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
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)}
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],
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]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
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],
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]}
end
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)}
local norm={}
for i=1,6 do for j=1,6 do norm[#norm+1]=n[i] end end
if not ms then ms=mesh() end
if ms.size==0 then
ms.vertices=vert
ms.normals=norm
ms.texture,ms.texCoords=tex,texCoords
else
for i=1,#vert do
table.insert(ms.vertices,vert[i])
table.insert(ms.normals,norm[i])
if tex then table.insert(ms.texCoords,texCoords[i]) end
end
end
ms:setColors(col or color(255))
return ms
end
ADSLighting33={
vertexShader=[[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec4 directColor;
uniform vec4 directDirection;
uniform vec4 point1Position;
uniform vec4 point1Color;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vPosition;
varying lowp vec4 vNormal;
varying vec4 vDirectDiffuse;
varying vec4 vPoint1Diffuse;
void main()
{
vColor = color;
gl_Position = modelViewProjection * position;
vTexCoord = texCoord;
vNormal = mModel * vec4( normal, 0.0 );
vec4 norm = normalize(vNormal);
vPosition = mModel * position;
vDirectDiffuse = directColor * max( 0.0, dot( norm, directDirection ));
vec4 d = normalize( point1Position - vPosition );
vPoint1Diffuse = point1Color * max( 0.0, dot( norm, d ));
}
]],
fragmentShader=[[
precision highp float;
uniform vec4 ambientColor;
uniform lowp sampler2D texture;
uniform float reflec;
uniform vec4 directColor;
uniform float directStrength;
uniform vec4 directDirection;
uniform vec4 eyePosition;
uniform vec4 specularColor;
uniform float specularPower;
uniform float shine;
uniform vec4 point1Position;
uniform float point1Range;
uniform vec4 point1Color;
uniform float point1Strength;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp vec4 vPosition;
varying lowp vec4 vNormal;
varying vec4 vDirectDiffuse;
varying vec4 vPoint1Diffuse;
vec4 normalizedNormal = normalize(vNormal);
vec4 GetSpecularColor(vec4 lightPosition, vec4 lightColor, bool IsDirectional)
{
vec4 lightDirection;
if (IsDirectional) lightDirection = lightPosition;
else lightDirection = vec4( normalize( lightPosition - vPosition ));
vec4 cameraDirection = normalize( eyePosition - vPosition );
vec4 halfAngle = normalize( cameraDirection + lightDirection );
vec4 specularColor = min(lightColor + 0.5, 1.0);
float spec = pow( max( 0.0, dot( normalizedNormal, halfAngle)), specularPower );
return specularColor * spec * shine;
}
void main()
{
lowp vec4 ambient=vec4(0.,0.,0.,0.);
lowp vec4 diffuse=vec4(0.,0.,0.,0.);
lowp vec4 specular=vec4(0.,0.,0.,0.);
lowp vec4 pixel = texture2D( texture, vTexCoord);
ambient = pixel * ambientColor;
diffuse = diffuse + pixel * vDirectDiffuse;
specular=specular + pixel * directStrength * GetSpecularColor(directDirection, specularColor, true);
float r = point1Range;
float point1Attenuation = max( 0.0, 1.0 - length( point1Position.xyz - vPosition.xyz ) / r );
float fracSpot=1.0;
diffuse = diffuse + pixel * fracSpot * point1Attenuation * vPoint1Diffuse;
specular=specular + pixel * fracSpot * point1Attenuation * point1Strength *
GetSpecularColor(point1Position, specularColor, false);
vec4 totalColor = clamp( reflec * (ambient + diffuse + specular),0.,1.);
totalColor.a=1.;
gl_FragColor=totalColor;
}
]]
}
--# Spot
--# Main
-- MultiStep
function setup()
steps = listProjectTabs()
if steps[1]=="Notes" then table.remove(steps,1) end --remove first tab if named Notes
table.remove(steps) --remove the last tab
startStep()
global = "select a step"
end
function showList()
output.clear()
for i=1,#steps do print(i,steps[i]) end
end
function startStep()
if cleanup then cleanup() end
lastStep=Step or readProjectData("lastStep") or 1
lastStep=math.min(lastStep,#steps)
saveProjectData("lastStep",lastStep)
parameter.clear()
parameter.integer("Step", 1, #steps, lastStep,showList)
parameter.action("Run", startStep)
loadstring(readProjectTab(steps[Step]))()
if PrintExplanation then PrintExplanation() end
setup()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment