123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- # San Angeles Observation
- # Original C version Copyright 2004-2005 Jetro Lauha
- # Web: http://iki.fi/jetro/
- #
- # BSD-license.
- #
- # Javascript version by Ken Waters
- # Skulpt (Python) version by Scott Graham
- import webgl
- ShapeParams = [
- # m a b n1 n2 n3 m a b n1 n2 n3 res1 res2 scale (org.res1,res2)
- [10, 1, 2, 90, 1, -45, 8, 1, 1, -1, 1, -0.4 , 20, 30, 2], # 40, 60
- [10, 1, 2, 90, 1, -45, 4, 1, 1, 10, 1, -0.4 , 20, 20, 4], # 40, 40
- [10, 1, 2, 60, 1, -10, 4, 1, 1, -1, -2, -0.4 , 41, 41, 1], # 82, 82
- [ 6, 1, 1, 60, 1, -70, 8, 1, 1, 0.4 , 3, 0.25 , 20, 20, 1], # 40, 40
- [ 4, 1, 1, 30, 1, 20, 12, 1, 1, 0.4 , 3, 0.25 , 10, 30, 1], # 20, 60
- [ 8, 1, 1, 30, 1, -4, 8, 2, 1, -1, 5, 0.5 , 25, 26, 1], # 60, 60
- [13, 1, 1, 30, 1, -4, 13, 1, 1, 1, 5, 1, 30, 30, 6], # 60, 60
- [10, 1, 1.1 , -0.5 , 0.1 , 70, 60, 1, 1, -90, 0, -0.25 , 20, 60, 8], # 60, 180
- [ 7, 1, 1, 20, -0.3 , -3.5 , 6, 1, 1, -1, 4.5 , 0.5 , 10, 20, 4], # 60, 80
- [ 4, 1, 1, 10, 10, 10, 4, 1, 1, 10, 10, 10, 10, 20, 1], # 20, 40
- [ 4, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 10, 10, 2], # 10, 10
- [ 1, 1, 1, 38, -0.25 , 19, 4, 1, 1, 10, 10, 10, 10, 15, 2], # 20, 40
- [ 2, 1, 1, 0.7 , 0.3 , 0.2 , 3, 1, 1, 100, 100, 100, 10, 25, 2], # 20, 50
- [ 6, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 30, 30, 2], # 60, 60
- [ 3, 1, 1, 1, 1, 1, 6, 1, 1, 2, 1, 1, 10, 20, 2], # 20, 40
- [ 6, 1, 1, 6, 5.5 , 100, 6, 1, 1, 25, 10, 10, 30, 20, 2], # 60, 40
- [ 3, 1, 1, 0.5 , 1.7 , 1.7 , 2, 1, 1, 10, 10, 10, 20, 20, 2], # 40, 40
- [ 5, 1, 1, 0.1 , 1.7 , 1.7 , 1, 1, 1, 0.3 , 0.5 , 0.5 , 20, 20, 4], # 40, 40
- [ 2, 1, 1, 6, 5.5 , 100, 6, 1, 1, 4, 10, 10, 10, 22, 1], # 40, 40
- [ 6, 1, 1, -1, 70, 0.1 , 9, 1, 0.5 , -98, 0.05 , -45, 20, 30, 4], # 60, 91
- [ 6, 1, 1, -1, 90, -0.1 , 7, 1, 1, 90, 1.3 , 34, 13, 16, 1] # 32, 60
- ]
- class CamTrack:
- def __init__(self, src, dest, dist, len):
- self.src = src
- self.dest = dest
- self.dist = dist
- self.len = len
- CamTracks = [
- CamTrack([4500, 2700, 100, 70, -30], [50, 50, -90, -100, 0], 20, 1),
- CamTrack([ -1448, 4294, 25, 363, 0 ], [ -136, 202, 125, -98, 100], 0, 1),
- CamTrack([ 1437, 4930, 200, -275, -20 ], [ 1684, 0, 0, 9, 0], 0, 1),
- CamTrack([ 1800, 3609, 200, 0, 675 ], [ 0, 0, 0, 300, 0], 0, 1),
- CamTrack([ 923, 996, 50, 2336, -80 ], [ 0, -20, -50, 0, 170], 0, 1),
- CamTrack([ -1663, -43, 600, 2170, 0 ], [ 20, 0, -600, 0, 100], 0, 1),
- CamTrack([ 1049, -1420, 175, 2111, -17 ], [ 0, 0, 0, -334, 0], 0, 2),
- CamTrack([ 0, 0, 50, 300, 25 ], [ 0, 0, 0, 300, 0], 70, 2),
- CamTrack([ -473, -953, 3500, -353, -350 ], [ 0, 0, -2800, 0, 0], 0, 2),
- CamTrack([ 191, 1938, 35, 1139, -17 ], [ 1205, -2909, 0, 0, 0], 0, 2),
- CamTrack([ -1449, -2700, 150, 0, 0 ], [ 0, 2000, 0, 0, 0], 0, 2),
- CamTrack([ 5273, 4992, 650, 373, -50 ], [ -4598, -3072, 0, 0, 0], 0, 2),
- CamTrack([ 3223, -3282, 1075, -393, -25 ], [ 1649, -1649, 0, 0, 0], 0, 2),
- ]
- CAMTRACK_LEN = 5442
- FlatVertexSource = """
- attribute vec3 pos;
- attribute vec4 colorIn;
- uniform mat4 mvp;
- varying vec4 color;
- void main() {
- color = colorIn;
- gl_Position = mvp * vec4(pos.xyz, 1.);
- }
- """
- FlatFragmentSource = """
- #ifdef GL_ES
- precision highp float;
- #endif
- varying vec4 color;
- void main() {
- gl_FragColor = vec4(color.rgb, 1.0);
- }
- """
- LitVertexSource = """
- attribute vec3 pos;
- attribute vec3 normal;
- attribute vec4 colorIn;
- varying vec4 color;
- uniform mat4 mvp;
- uniform mat3 normalMatrix;
- uniform vec4 ambient;
- uniform float shininess;
- uniform vec3 light_0_direction;
- uniform vec4 light_0_diffuse;
- uniform vec4 light_0_specular;
- uniform vec3 light_1_direction;
- uniform vec4 light_1_diffuse;
- uniform vec3 light_2_direction;
- uniform vec4 light_2_diffuse;
- vec3 worldNormal;
- vec4 SpecularLight(vec3 direction,
- vec4 diffuseColor,
- vec4 specularColor) {
- vec3 lightDir = normalize(direction);
- float diffuse = max(0., dot(worldNormal, lightDir));
- float specular = 0.;
- if (diffuse > 0.) {
- vec3 halfv = normalize(lightDir + vec3(0., 0., 1.));
- specular = pow(max(0., dot(halfv, worldNormal)), shininess);
- }
- return diffuse * diffuseColor * colorIn + specular * specularColor;
- }
- vec4 DiffuseLight(vec3 direction, vec4 diffuseColor) {
- vec3 lightDir = normalize(direction);
- float diffuse = max(0., dot(worldNormal, lightDir));
- return diffuse * diffuseColor * colorIn;
- }
- void main() {
- worldNormal = normalize(normalMatrix * normal);
- gl_Position = mvp * vec4(pos, 1.);
- color = ambient * colorIn;
- color += SpecularLight(light_0_direction, light_0_diffuse,
- light_0_specular);
- color += DiffuseLight(light_1_direction, light_1_diffuse);
- color += DiffuseLight(light_2_direction, light_2_diffuse);
- }
- """
- FadeVertexSource = """
- #ifdef GL_ES
- precision highp float;
- #endif
- attribute vec2 pos;
- varying vec4 color;
- uniform float minFade;
- void main() {
- color = vec4(minFade, minFade, minFade, 1.);
- gl_Position = vec4(pos, 0., 1.);
- }
- """
- class Random:
- def __init__(self, seed):
- self.randomSeed = seed
- def seed(self, seed):
- self.randomSeed = seed
- def uInt(self):
- self.randomSeed = (self.randomSeed * 0x343fd + 0x269ec3) & 0xffffffff
- return (self.randomSeed >> 16) & 0xfff
- class GlObject:
- def __init__(self, gl, shader, vertices, colors, normals=None):
- self.shader = shader
- self.count = len(vertices) / 3
- self.vbo = gl.createBuffer()
- vertexArray = gl.Float32Array(vertices)
- colorArray = gl.Uint8Array(colors)
- self.vertexOffset = 0
- self.colorOffset = vertexArray.byteLength
- self.normalOffset = self.colorOffset + colorArray.byteLength
- sizeInBytes = self.normalOffset
- normalArray = None
- self.hasNormals = normals != None
- if normals:
- normalArray = gl.Float32Array(normals)
- sizeInBytes += normalArray.byteLength
- gl.bindBuffer(gl.ARRAY_BUFFER, self.vbo)
- gl.bufferData(gl.ARRAY_BUFFER, sizeInBytes, gl.STATIC_DRAW)
- gl.bufferSubData(gl.ARRAY_BUFFER, self.vertexOffset, vertexArray)
- gl.bufferSubData(gl.ARRAY_BUFFER, self.colorOffset, colorArray)
- if normals:
- gl.bufferSubData(gl.ARRAY_BUFFER, self.normalOffset, normalArray)
- def draw(self):
- self.shader.use()
- gl.bindBuffer(gl.ARRAY_BUFFER, self.vbo)
- gl.vertexAttribPointer(self.shader.posLoc, 3, gl.FLOAT, False, 0, self.vertexOffset)
- gl.enableVertexAttribArray(self.shader.posLoc)
- gl.vertexAttribPointer(self.shader.colorInLoc, 4, gl.UNSIGNED_BYTE, True, 0, self.colorOffset)
- gl.enableVertexAttribArray(self.shader.colorInLoc)
- if self.hasNormals:
- gl.vertexAttribPointer(self.shader.normalLoc, 3, gl.FLOAT, False, 0, self.normalOffset)
- gl.enableVertexAttribArray(self.shader.normalLoc)
- gl.drawArrays(gl.TRIANGLES, 0, self.count)
- if self.hasNormals:
- gl.disableVertexAttribArray(self.shader.normalLoc)
- gl.disableVertexAttribArray(self.shader.colorInLoc)
- gl.disableVertexAttribArray(self.shader.posLoc)
- def createGroundPlane(gl, shader, random):
- scale = 4
- xBegin, xEnd = -15, 15
- yBegin, yEnd = -15, 15
- triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2
- colors = []
- vertices = []
- for y in range(yBegin, yEnd):
- for x in range(xBegin, xEnd):
- color = (random.uInt() & 0x4f) + 81
- for i in range(6):
- colors.extend([color, color, color, 0])
- for i in range(6):
- xm = x + ((0x1c >> a) & 1)
- ym = y + ((0x31 >> a) & 1)
- m = math.cos(xm * 2) * math.sin(ym * 4) * 0.75
- vertices.extend([xm * scale + m, ym * scale + m, 0])
- return GlObject(shader, vertices, colors)
- ground = None
- fadeVBO = None
- shapes = None
- modelview = None
- projection = None
- mvp = None
- normalMatrix = None
- currentCamTrackStartTick = 0
- nextCamTrackStartTick = 0
- sTick = 0
- currentCamTrack = 0
- def main():
- global gl, random, modelview, projection, mvp, normalMatrix
- modelview = webgl.Mat44()
- projection = webgl.Mat44()
- mvp = webgl.Mat44()
- normalMatrix = webgl.Mat33()
- gl = webgl.GL("canv")
- gl.enable(gl.DEPTH_TEST)
- gl.disable(gl.CULL_FACE)
- random = Random(15)
- flatShader = webgl.Shader(gl, FlatVertexSource, FlatFragmentSource)
- litShader = webgl.Shader(gl, LitVertexSource, FlatFragmentSource)
- fadeShader = webgl.Shader(gl, FadeVertexSource, FlatFragmentSource)
- # bind non-changing lighting parameters
- litShader.use()
- gl.uniform4f(litShader.ambientLoc, .2, .2, .2, 1.)
- gl.uniform4f(litShader.light_0_diffuseLoc, 1., .4, 0, 1.)
- gl.uniform4f(litShader.light_1_diffuseLoc, .07, .14, .35, 1.)
- gl.uniform4f(litShader.light_2_diffuseLoc, .07, .17, .14, 1.)
- gl.uniform4f(litShader.light_0_specularLoc, 1., 1., 1., 1.)
- gl.uniform1f(litShader.shininessLoc, 60.)
- shapes = [createSuperShape(litShader, x) for x in ShapeParams]
- ground = createGroundPlane(flatShader)
- def clamp(x, mn=0, mx=255):
- return max(min(x, mx), mn)
- def superShapeMap(r1, r2, t, p):
- return gl.Vec3(math.cos(t) * math.cos(p) / r1 / r2,
- math.sin(t) * math.cos(p) / r1 / r2,
- math.sin(p) / r2)
- def ssFunc(t, p):
- return pow(pow(abs(cos(p[0] * t / 4)) / p[1], p[4]) +
- pow(abs(sin(p[0] * t / 4)) / p[2], p[5]),
- 1.0 / p[3])
- def createSuperShape(shader, params):
- resol1 = params[-3]
- resol2 = params[-2]
- # latitude 0 to pi/2 for no mirrored bottom
- # (latitudeBegin==0 for -pi/2 to pi/2 originally)
- latitudeBegin = resol2 / 4
- latitudeEnd = resol2 / 2
- longitudeCount = resol1
- vertices = []
- colors = []
- normals = []
- baseColor = [(random.uInt() % 155 + 100) / 255.0 for x in range(3)]
- currentVertex = 0
- for longitude in range(longitudeCount):
- for latitude in range(latitudeBegin, latitudeEnd):
- t1 = -math.pi + longitude * 2 * math.pi / resol1
- t2 = -math.pi + (longitute + 1) * 2 * math.pi / resol1
- p1 = -math.pi / 2 + latitude * 2 * math.pi / resol2
- p2 = -math.pi / 2 + (latitude + 1) * 2 * math.pi / resol2
- r0 = ssFunc(t1, params)
- r1 = ssFunc(p1, params[6:])
- r2 = ssFunc(t2)
- r3 = ssFunc(p2, params[6:])
- if r0 and r1 and r2 and r3:
- pa = superShapeMap(r0, r1, t1, p1)
- pb = superShapeMap(r2, r1, t2, p1)
- pc = superShapeMap(r2, r3, r2, p2)
- pd = superShapeMap(r0, r3, t1, p2)
-
- # kludge to set lower edge of the object to fixed level
- if latitude == latitudeBegin + 1:
- pa.z = pb.z = 0
- v1 = pb - pa
- v2 = pd - pa
- n = gl.cross(v1, v2)
-
- # Pre-normalization of the normals is disabled here because
- # they will be normalized anyway later due to automatic
- # normalization (NORMALIZE). It is enabled because the
- # objects are scaled with scale.
- #
- # Note we have to normalize by hand in the shader
- ca = pa.z + 0.5
- for i in range(6):
- normals.extend([n.x, n.y, n.z])
- for i in range(6):
- colors.append(clamp(ca * baseColor[0] * 255))
- colors.append(clamp(ca * baseColor[1] * 255))
- colors.append(clamp(ca * baseColor[2] * 255))
- colors.append(0)
- vertices.extend([pa.x, pa.y, pa.z])
- vertices.extend([pb.x, pb.y, pb.z])
- vertices.extend([pd.x, pd.y, pd.z])
- vertices.extend([pb.x, pb.y, pb.z])
- vertices.extend([pc.x, pc.y, pc.z])
- vertices.extend([pd.x, pd.y, pd.z])
- return GlObject(gl, shader, vertices, colors, normals)
- def configureLightAndMaterial():
- l0 = modelview.transform3(Vec3(-4., 1., 1.))
- l1 = modelview.transform3(Vec3(1., -2., -1.))
- l2 = modelview.transform3(Vec3(-1., 0., -4.))
- litShader.use()
- gl.uniform3f(litShader.light_0_directionLoc, l0.x, l0.y, l0.z)
- gl.uniform3f(litShader.light_1_directionLoc, l1.x, l1.y, l1.z)
- gl.uniform3f(litShader.light_2_directionLoc, l2.x, l2.y, l2.z)
- def drawModels(zScale):
- translationScale = 9
- modelview.scale(1, 1, zScale)
- random.seed(9)
- for y in range(-5, 5):
- for x in range(-5, 5):
- curShape = random.uInt() % len(ShapeParams)
- buildingScale = ShapeParams[curShape][-1]
- modelview.push()
- modelview.translate(x * translationScale, y * translationScale, 0)
- rv = random.uInt() % 360
- modelview.rotate(-rv, 0, 0, 1)
- modelview.scale(buildingScale, buildingScale, buildingScale)
- shapes[curShape].draw()
- modelview.pop()
- ship = shapes[-1]
- for x in range(-2, 2):
- shipScale100 = translationScale * 500
- offs100 = x * shipScale100 + (sTick % shipScale100)
- offs = 0.01 * offs100
- modelview.push()
- modelview.translate(offs, -4.0, 2.0)
- ship.draw()
- modelview.pop()
- modelview.push()
- modelview.translate(-4., offs, 4.)
- modelview.rotate(-90., 0., 0., 1.)
- ship.draw()
- modelview.pop()
- def camTrack():
- nextCamTrackStartTick = currentCamTrackStartTick + CamTracks[currentCamTrack].len * CAMTRACK_LEN
- while nextCamTrackStartTick <= sTick:
- ++currentCamTrack
- if currentCamTrack >= len(CamTracks):
- currentCamTrack = 0
- currentCamTrackStartTick = nextCamTrackStartTick
- nextCamTrackStartTick = currentCamTrackStartTick + CamTracks[currentCamTrack].len * CAMTRACK_LEN
- cam = CamTracks[currentCamTrack]
- currentCamTick = sTick - currentCamTrackStartTick
- trackPos = currentCamTick / (CAMTRACK_LEN * cam.len)
- lerp = [0.01 * cam.src[a] + cam.dest[a] * trackPos for a in range(5)]
- if cam.dist:
- dist = cam.dist * 0.1
- cX = lerp[0]
- cY = lerp[1]
- cZ = lerp[2]
- eX = cX - math.cos(lerp[3]) * dist
- eY = cY - math.sin(lerp[3]) * dist
- eZ = cZ - lerp[4]
- else:
- eX = lerp[0]
- eY = lerp[1]
- eZ = lerp[2]
- cX = eX + math.cos(lerp[3])
- cY = eY + math.sin(lerp[3])
- cZ = eZ + lerp[4]
- modelview.lookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1)
- def drawGroundPlane():
- gl.disable(gl.CULL_FACE)
- gl.disable(gl.DEPTH_TEST)
- gl.enable(gl.BLEND)
- gl.blendFunc(gl.ZERO, gl.SRC_COLOR)
- ground.draw()
- gl.disable(gl.BLEND)
- gl.enable(gl.DEPTH_TEST)
- def drawFadeQuad():
- global fadeVBO
- if not fadeVBO:
- vertices = gl.Float32Array([
- -1, -1,
- 1, -1,
- -1, 1,
- 1, -1,
- 1, 1,
- -1, 1])
- fadeVBO = gl.createBuffer()
- gl.bindBuffer(gl.ARRAY_BUFFER, fadeVBO)
- gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
- beginFade = sTick - currentCamTrackStartTick
- endFade = nextCamTrackStartTick - sTick
- minFade = min(beginFade, endFade)
- if minFade < 1024:
- gl.disable(gl.DEPTH_TEST)
- gl.enable(gl.BLEND)
- gl.blendFunc(gl.ZERO, gl.SRC_COLOR)
- fadeShader.use()
- gl.uniform1f(fadeShader.minFadeLoc, minFade / 1024.0)
- gl.bindBuffer(gl.ARRAY_BUFFER, fadeVBO)
- gl.vertexAttribPointer(fadeShader.posLoc, 2, gl.FLOAT, false, 0, 0)
- gl.enableVertexAttribArray(fadeShader.posLoc)
- gl.drawArrays(gl.TRIANGLES, 0, 6)
- gl.disableVertexAttribArray(fadeShader.posLoc)
- gl.disable(gl.BLEND)
- gl.enable(gl.DEPTH_TEST)
- def draw(gl, width, height):
- sTick = (sTick + tick) / 2
- gl.clearColor(0.1, 0.2, 0.3, 1.0)
- gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT)
- projection.loadIdentity()
- projection.perspective(45, width / height, 0.5, 100)
- modelview.loadIdentity()
- camTrack()
- configureLightAndMaterial()
- modelview.push()
- drawModels(-1)
- modelview.pop()
- drawGroundPlane()
- drawModels(1)
- drawFadeQuad()
- main()
|