Last active
December 14, 2015 15:59
-
-
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
This file contains hidden or 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
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