-
-
Save rolantin/f13e73b8bd1e47cb9f37f5641597c01f to your computer and use it in GitHub Desktop.
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
--# Main | |
-- Cube | |
function setup() | |
parameter.number("ambient", 0, 1, 0.1) | |
parameter.number("diffuse", 0, 1, 1.0) | |
parameter.number("specular", 0, 1, 1) | |
parameter.color("lightColor", color(255,255,255,255)) | |
parameter.color("surfaceColor", color(191,41,85,255)) | |
allTextures = { | |
CAMERA, | |
"Cargo Bot:Crate Blue 2", | |
"Cargo Bot:Codea Icon", | |
"Small World:Store Extra Large", | |
"Small World:Windmill", | |
} | |
cameraSource(CAMERA_FRONT) | |
cube = LitMesh() | |
--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 | |
cube.litMesh.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 texvertices = { vec2(0,0), | |
vec2(1,0), | |
vec2(0,1), | |
vec2(1,1) } | |
-- apply the texture coordinates to each triangle | |
cube.litMesh.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], | |
} | |
--setup vertex normals, tangents and binormals | |
--only call this after vertexes and texture coordinates have been set on the mesh | |
cube:deriveVertexNTB() | |
cube:setLight(vec3(-2,2,-3), ambient, diffuse, specular, lightColor) | |
cube:setEye(vec3(0,0,-3)) | |
cube:setColor(surfaceColor) | |
doBumpMapUpdate = 0 | |
parameter.integer("Texture",0,5,0,changeTexture) | |
parameter.integer("BumpMap",0,2,0,changeBumpMap) | |
parameter.integer("xRotation",0,360) | |
parameter.integer("yRotation",0,360) | |
currentLocation = vec2(0,0) | |
end | |
function changeBumpMap() | |
if BumpMap == 0 or (BumpMap == 1 and Texture < 2) then | |
cube:disableBumpMap() | |
else | |
if BumpMap == 1 then | |
--generated from texture | |
bumpTexture = cube:generateTextureBumpMap(cubeTexture, 0.01) | |
cube:setBumpMap(bumpTexture) | |
end | |
if BumpMap == 2 then | |
--sphericalish | |
bumpTexture = genCircularNormals(150) | |
cube:setBumpMap(bumpTexture) | |
end | |
end | |
end | |
function genCircularNormals(w) | |
local t = image(w, w) | |
r = w/1.5 | |
for x=1,w do | |
for y=1,w do | |
d = math.sqrt(((w/2-x)^2+(w/2-y)^2)) | |
if d <= r then | |
angle = math.acos(d/r) | |
z = r*math.sin(angle) | |
v = (vec3(x-r,y-r,z):normalize()+vec3(1,1,1))/2*255 | |
t:set(x, y, v.x, v.y, v.z, 255) | |
end | |
end | |
end | |
return t | |
end | |
function changeTexture() | |
if Texture == 0 then | |
--remove texture | |
cube:setColor(surfaceColor) | |
elseif Texture == 1 then | |
cube:setTexture(CAMERA) | |
else | |
cubeTexture = readImage(allTextures[Texture]) | |
cube:setTexture(cubeTexture) | |
end | |
if BumpMap == 1 then | |
doBumpMapUpdate = 30 | |
end | |
end | |
function draw() | |
if CurrentTouch.state == MOVING then | |
currentLocation.x = currentLocation.x + CurrentTouch.deltaX/500 | |
currentLocation.y = currentLocation.y + CurrentTouch.deltaY/500 | |
end | |
output.clear() | |
print(1/DeltaTime) | |
background(40, 40, 50) | |
camera(0,0,-3,0,0,0) | |
perspective() | |
pushMatrix() | |
translate(currentLocation.x, currentLocation.y, 0) | |
rotate(xRotation,0,1,0) | |
rotate(yRotation,1,0,0) | |
--do rotation for touch | |
cube:draw() | |
popMatrix() | |
if doBumpMapUpdate>0 then | |
doBumpMapUpdate = doBumpMapUpdate - 1 | |
print(doBumpMapUpdate) | |
if doBumpMapUpdate == 0 then | |
changeBumpMap() | |
end | |
end | |
end | |
--# LitMesh | |
LitMesh = class() | |
--[[ | |
LitMesh provides a bumpmappable ADS (ambient/diffuse/specular) lighting enhanced class | |
for meshes. | |
usage: | |
setup() | |
myObject = LitMesh() | |
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 wish to use 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() | |
self.litMesh = mesh() | |
self.litMesh.shader = shader(LitMesh.ADSLighting.vertexShader, LitMesh.ADSLighting.fragmentShader) | |
self.litMesh.shader.useTexture = false | |
self.litMesh.shader.useBumpMap = false | |
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) | |
self.litMesh.shader.useTexture = true | |
self.litMesh.texture = texture | |
end | |
function LitMesh:disableBumpMap() | |
self.litMesh.shader.useBumpMap = false | |
end | |
function LitMesh:setBumpMap(bumpMap) | |
self.litMesh.shader.useBumpMap = true | |
self.litMesh.shader.bumpMap = bumpMap | |
end | |
function LitMesh:setColor(surfaceColor) | |
--assumes the reason you are setting the color is because you don't want to use a texture | |
self.litMesh.texture = nil | |
self.litMesh.shader.useTexture = false | |
self.litMesh:setColors(surfaceColor) | |
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 | |
local texCoordBuffer = self.litMesh:buffer("texCoord") | |
if texCoordBuffer.length == self.litMesh.size then | |
useTexCoords = true | |
else | |
useTexCoords = false | |
end | |
local normalBuffer = self.litMesh:buffer("normal") | |
normalBuffer:resize(self.litMesh.size) | |
local tangentBuffer = self.litMesh:buffer("tangent") | |
tangentBuffer:resize(self.litMesh.size) | |
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 | |
tangentBuffer[j] = tangent | |
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 | |
LitMesh.ADSLighting = { | |
--shader() | |
vertexShader = [[ | |
uniform mat4 modelViewProjection; | |
uniform mat4 mInvModel; | |
uniform vec3 vEyePosition; | |
uniform vec3 vLightPosition; | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
attribute vec3 tangent; | |
attribute vec3 binormal; | |
varying lowp vec4 vColor; | |
varying mediump vec2 vTexCoord; | |
varying mediump vec3 lightDirection; | |
varying mediump vec3 eyeDirection; | |
void main() | |
{ | |
mat3 tangentMatrix = mat3(tangent, binormal, normal); | |
//convert the positions to object space, then get direction, then convert to tangent space | |
lightDirection = (normalize((vec4(vLightPosition,1) * mInvModel) - position).xyz | |
* tangentMatrix).xyz; | |
eyeDirection = (normalize((vec4(vEyePosition,1) * mInvModel) - position).xyz | |
* tangentMatrix).xyz; | |
vColor = color; | |
vTexCoord = vec2(texCoord.x, texCoord.y); | |
gl_Position = modelViewProjection * position; | |
} | |
]], | |
fragmentShader = [[ | |
precision mediump float; | |
uniform lowp sampler2D texture; | |
uniform lowp sampler2D bumpMap; | |
uniform bool useTexture; | |
uniform bool useBumpMap; | |
varying highp vec2 vTexCoord; | |
varying lowp vec4 vColor; | |
varying mediump vec3 lightDirection; | |
varying mediump vec3 eyeDirection; | |
uniform float vAmbientMaterial; | |
uniform float vDiffuseMaterial; | |
uniform float vSpecularMaterial; | |
uniform vec4 lightColor; | |
// Returns the specular component of the color | |
vec4 GetSpecularColor(vec3 vTransformedNormal) | |
{ | |
//normalise because interpolation may have broken it | |
vec3 vLightDirection = normalize(lightDirection); | |
vec3 vCameraDirection = normalize(eyeDirection); | |
// Calculate the reflection vector between the incoming light and the | |
// normal (incoming angle = outgoing angle) | |
vec3 vReflection = reflect( -vLightDirection, vTransformedNormal ); | |
// Calculate specular component | |
// Based on the dot product between the reflection vector and the camera | |
// direction. | |
float spec = pow( max( 0.0, dot( vCameraDirection, vReflection )), 32.0 ); | |
return lowp vec4( lightColor.r * spec, lightColor.g * spec, lightColor.b * spec, 1.0 ) * vSpecularMaterial; | |
} | |
// Ambient color component of vertex | |
vec4 GetAmbientColor(vec4 texCol) | |
{ | |
lowp vec4 vAmbientColor; | |
vAmbientColor.xyz = texCol.rgb * lightColor.rgb * vAmbientMaterial; | |
vAmbientColor.a = 1.0; | |
return vAmbientColor; | |
} | |
// Diffuse Color component of vertex | |
vec4 GetDiffuseColor(vec3 vTransformedNormal, vec4 texCol) | |
{ | |
vec3 vLightDirection = normalize(normalize(lightDirection)); | |
// Calculate Diffuse intensity | |
float fDiffuseIntensity = max( 0.0, dot( vTransformedNormal, vLightDirection )); | |
// Calculate resulting Color | |
lowp vec4 vDiffuseColor; | |
vDiffuseColor.xyz = texCol.rgb * lightColor.rgb * fDiffuseIntensity * vDiffuseMaterial; | |
vDiffuseColor.a = 1.0; | |
return vDiffuseColor; | |
} | |
void main() | |
{ | |
mediump vec3 curNormal; | |
if (useBumpMap) { | |
lowp vec4 bump = texture2D( bumpMap, vTexCoord ); | |
if (bump.x == 0.0 && bump.y == 0.0 && bump.z == 0.0) discard; | |
curNormal = normalize(vec3(bump.x, bump.y, bump.z)*2.0-vec3(1.0,1.0,1.0)); | |
} | |
else { | |
curNormal = vec3(0.0,0.0,1.0); | |
} | |
lowp vec4 curCol; | |
if (useTexture) { | |
curCol = texture2D( texture, vTexCoord); | |
if (curCol.a == 0.0) discard; | |
} | |
else { | |
curCol = vColor; | |
} | |
lowp vec4 ambientColor = GetAmbientColor(curCol); | |
lowp vec4 diffuseColor = GetDiffuseColor(curNormal, curCol); | |
lowp vec4 specularColor = GetSpecularColor(curNormal); | |
// Combine into final color | |
lowp vec4 outColor; | |
outColor = ambientColor + diffuseColor + specularColor; | |
//Set the output color to the texture color | |
gl_FragColor = outColor; | |
} | |
]] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment