Skip to content

Instantly share code, notes, and snippets.

@sp4cemonkey
Last active January 8, 2019 16:31
Show Gist options
  • Select an option

  • Save sp4cemonkey/5033682 to your computer and use it in GitHub Desktop.

Select an option

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

rolantin commented Jan 8, 2019

Copy link
Copy Markdown

error network friend

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