Skip to content

Instantly share code, notes, and snippets.

@sp4cemonkey
Last active January 8, 2019 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sp4cemonkey/5033682 to your computer and use it in GitHub Desktop.
Save sp4cemonkey/5033682 to your computer and use it in GitHub Desktop.
--# 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;
}
]]
}
@rolantin
Copy link

rolantin commented Jan 8, 2019

error network friend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment