Skip to content

Instantly share code, notes, and snippets.

@sp4cemonkey
Last active December 14, 2015 15:59
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sp4cemonkey/5112117 to your computer and use it in GitHub Desktop.
Save sp4cemonkey/5112117 to your computer and use it in GitHub Desktop.
This is a codea class with an ADS lighting with options for colored, textured and bumpmapped
LitMesh = class()
--[[
LitMesh provides a bumpmappable ADS (ambient/diffuse/specular) lighting enhanced class
for meshes.
usage:
setup()
myObject = LitMesh(isTextured, isBumpMapped)
myObject.litMesh.vertices = some table of vertices
-- this must be a multiple of 3 representing the triangles
-- this is the normal mesh vertices array and can be manipulated as per docs
-- eg myObject.litMesh:vertex(i, vec3(x,y,z))
-- myObject.litMesh:setRect(i,x,y,w,h)
myObject.litMesh.texCoords = some table of texture coordinates for the vertices
-- this is the normal mesh texCoords array and can be
manipulated as per the docs
-- eg myObject.litMesh:texCoord(i, x, y)
-- myObject.litMesh:setRectTex(i,s,t,w,h)
--Once all vertexes and texture coordinates have been set call:
myObject:deriveVertexNTB()
-- you will need to make this call again if you modify any vertexes or texture coordinates
--setup lighting
--lightPosition is the location of the light in world space
--eyePosition is the location of the camera in world space this is the eye vector in your camera() call
myObject:setLight(vec3(lightPosition), ambient, diffuse, specular, lightColor)
--set the eye position which is the eye vector from your camera statement
myObject:setEye(vec3(eyePosition))
--then either color or texture your mesh with one of
myObject:setColor(color)
myObject:setTexture(texture)
--finally if you are using bumpmapping set a bumpmap
myObject:setBumpMap(bumpMap)
--a bumpMap is just an image with normal vectors encoded into the colors, these can be generated in tools like blender or photoshop
--Alternately the LitMesh class contains (a poor performing) helper method for generating bumpMaps from your texture: - strength is how aggressive the edge mapping is 0.01 is a good start
myObject:generateTextureBumpMap(texture, strength)
--this could be used as a shortcut by:
bumpTexture = cube:generateTextureBumpMap(cubeTexture, 0.01)
myObject:setBumpMap(bumpTexture)
draw()
--do all your normal drawing activity
background(40, 40, 50)
camera(eyex, eyey, eyez, lookatx, lookaty, lookatz)
--if the camera eye is moving remember to do
myObject:setEye(vec3(eyex, eyey, eyez))
perspective()
--object drawing
pushMatrix()
translate(x,y,z) --move centre of your mesh wherever
rotate(angle,x,y,z) -- rotate your object about it's centre
myObject:draw()
popMatrix()
]]
function LitMesh:init(isTextured, isBump)
self.litMesh = mesh()
self.isTextured = isTextured
self.isBump = isBump
if isBump == true then
self.litMesh.shader = shader(LitMesh.ADSLightingWBumpMap.vertexShader, LitMesh.ADSLightingWBumpMap.fragmentShader)
else
if isTextured == true then
self.litMesh.shader = shader(LitMesh.ADSLightingWTextureOnly.vertexShader, LitMesh.ADSLightingWTextureOnly.fragmentShader)
else
self.litMesh.shader = shader(LitMesh.ADSLightingColor.vertexShader, LitMesh.ADSLightingColor.fragmentShader)
end
end
self.litMesh.shader.useTexture = isTextured
self.litMesh.shader.useBumpMap = isBump
end
function LitMesh:draw()
self.litMesh.shader.mInvModel = modelMatrix():inverse():transpose()
self.litMesh:draw()
end
function LitMesh:setLight(lightPosition, ambient, diffuse, specular, lightColor)
self.litMesh.shader.vLightPosition = lightPosition
self.litMesh.shader.vAmbientMaterial = ambient
self.litMesh.shader.vDiffuseMaterial = diffuse
self.litMesh.shader.vSpecularMaterial = specular
self.litMesh.shader.lightColor = lightColor
end
function LitMesh:setEye(eyePosition)
self.litMesh.shader.vEyePosition = eyePosition
end
function LitMesh:setTexture(texture)
if self.isTextured == true then
self.litMesh.texture = texture
end
end
function LitMesh:setBumpMap(bumpMap)
if self.isBump == true then
self.litMesh.shader.bumpMap = bumpMap
end
end
function LitMesh:setColor(surfaceColor)
if self.isTextured ~= true then
self.litMesh:setColors(surfaceColor)
end
end
function LitMesh:deriveVertexNTB()
--this will calculate the tangent, binormal and from those the normal for each vertex, these will all be stored in buffers
--assumes that the surfaces have their texture coordinates set (even if being left untextured)
--tangent is the X axis on the plane of the surface relative to textures
--binormal is the Y axis on the plane of the surface relative to textures
--normal is the surface normal
if self.isTextured == true then
useTexCoords = true
else
useTexCoords = false
end
local normalBuffer = self.litMesh:buffer("normal")
normalBuffer:resize(self.litMesh.size)
local tangentBuffer
if self.isBump == true then
tangentBuffer = self.litMesh:buffer("tangent")
tangentBuffer:resize(self.litMesh.size)
end
--local binormalBuffer = self.litMesh:buffer("binormal")
--binormalBuffer:resize(self.litMesh.size)
local tangent,binormal, normal
for i=1, self.litMesh.size/3 do
--calculate the surface vectors
local v1 = self.litMesh:vertex(i*3-1) - self.litMesh:vertex(i*3-2)
local v2 = self.litMesh:vertex(i*3) - self.litMesh:vertex(i*3-2)
--calculate the texture space vectors
if useTexCoords then
local tuV = vec2(self.litMesh:texCoord(i*3-1).x - self.litMesh:texCoord(i*3-2).x, self.litMesh:texCoord(i*3).x - self.litMesh:texCoord(i*3-2).x)
local tvV = vec2(self.litMesh:texCoord(i*3-1).y - self.litMesh:texCoord(i*3-2).y, self.litMesh:texCoord(i*3).y - self.litMesh:texCoord(i*3-2).y)
--calculate denominator
local den=1/(tuV.x*tvV.y - tuV.y*tvV.x)
--tangent
tangent = vec3((tvV.y*v1.x - tvV.x*v2.x)*den, (tvV.y*v1.y - tvV.x*v2.y)*den, (tvV.y*v1.z - tvV.x*v2.z)*den):normalize()
binormal = vec3((tuV.x*v2.x - tuV.y*v1.x)*den, (tuV.x*v2.y - tuV.y*v1.y)*den, (tuV.x*v2.z - tuV.y*v1.z)*den):normalize()
normal = tangent:cross(binormal):normalize()
else
tangent = v1:normalize()
normal = v1:normalize():cross(v2:normalize()):normalize()
binormal = normal:cross(tangent):normalize()
end
for j=i*3-2,i*3 do
normalBuffer[j] = normal
--binormalBuffer[j] = binormal
if self.isBump == true then
tangentBuffer[j] = tangent
end
end
end
end
function LitMesh:generateTextureBumpMap(source, strength)
local t = image(source.width, source.height)
for y=2,source.height-1 do
for x=2,source.width-1 do
r,g,b,a = source:get(x-1,y)
xLeft = (0.3*r+0.59*g+0.11*b)*strength
r,g,b,a = source:get(x+1,y)
xRight = (0.3*r+0.59*g+0.11*b)*strength
r,g,b,a = source:get(x,y-1)
yUp = (0.3*r+0.59*g+0.11*b)*strength
r,g,b,a = source:get(x,y+1)
yDown = (0.3*r+0.59*g+0.11*b)*strength
xDelta = ((xLeft-xRight)+1)*127.5
yDelta = ((yUp - yDown)+1)*127.5
t:set(x,y,color(xDelta,yDelta,255,255))
end
end
for y=1,source.height do
t:set(1,y,color(0,0,255,255))
t:set(source.width,y,color(0,0,255,255))
end
for x=1,source.width do
t:set(x,1,color(0,0,255,255))
t:set(x,source.height,color(0,0,255,255))
end
return t
end
--shader("Documents:z")
LitMesh.ADSLightingColor = {
vertexShader = [[
uniform highp mat4 modelViewProjection;
uniform highp mat4 mInvModel;
uniform mediump vec3 vEyePosition;
uniform mediump vec3 vLightPosition;
attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
varying lowp vec4 vColor;
varying mediump vec3 lightDirection;
varying mediump vec3 eyeDirection;
varying mediump vec3 vNormal;
void main()
{
//convert the positions to object space, then get direction
lightDirection = ((vec4(vLightPosition,1) * mInvModel) - position).xyz;
eyeDirection = ((vec4(vEyePosition,1) * mInvModel) - position).xyz;
vNormal = normal;
vColor = color;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision lowp float;
uniform lowp sampler2D texture;
uniform lowp sampler2D bumpMap;
varying lowp vec4 vColor;
varying mediump vec3 lightDirection;
varying mediump vec3 eyeDirection;
varying mediump vec3 vNormal;
uniform float vAmbientMaterial;
uniform float vDiffuseMaterial;
uniform float vSpecularMaterial;
uniform lowp vec4 lightColor;
const float c_zero = 0.0;
const float c_one = 1.0;
const float c_two = 2.0;
void main()
{
if (!gl_FrontFacing) discard;
vec3 curNormal = normalize(vNormal);
lowp vec4 curCol = vColor;
vec3 vLightDirection = normalize(normalize(lightDirection));
vec3 vCameraDirection = normalize(eyeDirection);
lowp vec4 vAmbientColor = curCol * lightColor * vAmbientMaterial;
// Calculate Diffuse intensity
float fDiffuseIntensity = max( c_zero, dot( curNormal, vLightDirection ));
lowp vec4 vDiffuseColor = curCol * lightColor * fDiffuseIntensity * vDiffuseMaterial;
// Calculate the reflection vector between the incoming light and the
// normal (incoming angle = outgoing angle)
vec3 vReflection = reflect( -vLightDirection, curNormal );
// Calculate specular component
// Based on the dot product between the reflection vector and the camera
// direction.
float spec = pow( max( c_zero, dot( vCameraDirection, vReflection )), 32.0 );
lowp vec4 vSpecularColor = lightColor * spec * vSpecularMaterial;
lowp vec4 outColor = vAmbientColor + vDiffuseColor + vSpecularColor;
outColor.a = vColor.a;
gl_FragColor = outColor;
}
]]
}
LitMesh.ADSLightingWTextureOnly = {
vertexShader = [[
uniform highp mat4 modelViewProjection;
uniform highp mat4 mInvModel;
uniform mediump vec3 vEyePosition;
uniform mediump vec3 vLightPosition;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
varying lowp vec2 vTexCoord;
varying mediump vec3 lightDirection;
varying mediump vec3 eyeDirection;
varying mediump vec3 vNormal;
void main()
{
//convert the positions to object space, then get direction
lightDirection = ((vec4(vLightPosition,1) * mInvModel) - position).xyz;
eyeDirection = ((vec4(vEyePosition,1) * mInvModel) - position).xyz;
vNormal = normal;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision lowp float;
uniform lowp sampler2D texture;
uniform lowp sampler2D bumpMap;
varying lowp vec2 vTexCoord;
varying mediump vec3 lightDirection;
varying mediump vec3 eyeDirection;
varying mediump vec3 vNormal;
uniform float vAmbientMaterial;
uniform float vDiffuseMaterial;
uniform float vSpecularMaterial;
uniform lowp vec4 lightColor;
const float c_zero = 0.0;
const float c_one = 1.0;
const float c_two = 2.0;
void main()
{
if (!gl_FrontFacing) discard;
vec3 curNormal = normalize(vNormal);
lowp vec4 curCol = texture2D( texture, vTexCoord);
if (curCol.a == c_zero) discard;
vec3 vLightDirection = normalize(normalize(lightDirection));
vec3 vCameraDirection = normalize(eyeDirection);
lowp vec4 vAmbientColor = curCol * lightColor * vAmbientMaterial;
// Calculate Diffuse intensity
float fDiffuseIntensity = max( c_zero, dot( curNormal, vLightDirection ));
lowp vec4 vDiffuseColor = curCol * lightColor * fDiffuseIntensity * vDiffuseMaterial;
// Calculate the reflection vector between the incoming light and the
// normal (incoming angle = outgoing angle)
vec3 vReflection = reflect( -vLightDirection, curNormal );
// Calculate specular component
// Based on the dot product between the reflection vector and the camera
// direction.
float spec = pow( max( c_zero, dot( vCameraDirection, vReflection )), 32.0 );
lowp vec4 vSpecularColor = lightColor * spec * vSpecularMaterial;
lowp vec4 outColor = vAmbientColor + vDiffuseColor + vSpecularColor;
outColor.a = curCol.a;
gl_FragColor = outColor;
}
]]
}
LitMesh.ADSLightingWBumpMap = {
vertexShader = [[
uniform highp mat4 modelViewProjection;
uniform highp mat4 mInvModel;
uniform mediump vec3 vEyePosition;
uniform mediump vec3 vLightPosition;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute vec3 normal;
attribute vec3 tangent;
varying lowp vec2 vTexCoord;
varying mediump vec3 lightDirection;
varying mediump vec3 eyeDirection;
void main()
{
highp mat3 tangentMatrix = mat3(tangent, cross(normal, tangent), normal);
//convert the positions to object space, then get direction, then convert to tangent space
lightDirection = (((vec4(vLightPosition,1) * mInvModel) - position).xyz
* tangentMatrix).xyz;
eyeDirection = (((vec4(vEyePosition,1) * mInvModel) - position).xyz
* tangentMatrix).xyz;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
precision lowp float;
uniform lowp sampler2D texture;
uniform lowp sampler2D bumpMap;
varying lowp vec2 vTexCoord;
varying lowp vec3 lightDirection;
varying lowp vec3 eyeDirection;
uniform float vAmbientMaterial;
uniform float vDiffuseMaterial;
uniform float vSpecularMaterial;
uniform lowp vec4 lightColor;
const float c_zero = 0.0;
const float c_one = 1.0;
const float c_two = 2.0;
void main()
{
if (!gl_FrontFacing) discard;
vec3 curNormal = normalize(texture2D( bumpMap, vTexCoord ).xyz*c_two-vec3(c_one,c_one,c_one));
lowp vec4 curCol = texture2D( texture, vTexCoord);
if (curCol.a == c_zero) discard;
vec3 vLightDirection = normalize(normalize(lightDirection));
vec3 vCameraDirection = normalize(eyeDirection);
lowp vec4 vAmbientColor = curCol * lightColor * vAmbientMaterial;
// Calculate Diffuse intensity
float fDiffuseIntensity = max( c_zero, dot( curNormal, vLightDirection ));
lowp vec4 vDiffuseColor = curCol * lightColor * fDiffuseIntensity * vDiffuseMaterial;
// Calculate the reflection vector between the incoming light and the
// normal (incoming angle = outgoing angle)
vec3 vReflection = reflect( -vLightDirection, curNormal );
// Calculate specular component
// Based on the dot product between the reflection vector and the camera
// direction.
float spec = pow( max( c_zero, dot( vCameraDirection, vReflection )), 32.0 );
lowp vec4 vSpecularColor = lightColor * spec * vSpecularMaterial;
lowp vec4 outColor = vAmbientColor + vDiffuseColor + vSpecularColor;
outColor.a = curCol.a;
gl_FragColor = outColor;
}
]]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment