Created
March 18, 2011 11:56
-
-
Save 525c1e21-bd67-4735-ac99-b4b0e5262290/875936 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
THREE.WebGLRenderer = (parameters) -> | |
_canvas = document.createElement 'canvas' | |
_gl = null | |
_oldProgram = null | |
_oldFramebuffer = null | |
_this = this | |
# gl state cache | |
_oldDoubleSided = null | |
_oldFlipSided = null | |
_oldBlending = null | |
_oldDepth = null | |
_viewportX = 0 | |
_viewportY = 0 | |
_viewportWidth = 0 | |
_viewportHeight = 0 | |
# camera matrices caches | |
_frustum = [ | |
new THREE.Vector4 | |
new THREE.Vector4 | |
new THREE.Vector4 | |
new THREE.Vector4 | |
new THREE.Vector4 | |
new THREE.Vector4 | |
] | |
_projScreenMatrix = new THREE.Matrix4 | |
_projectionMatrixArray = new Float32Array 16 | |
_viewMatrixArray = new Float32Array 16 | |
_vector3 = new THREE.Vector4 | |
# light arrays cache | |
_lights = | |
ambient: [0, 0, 0] | |
directional: {length: 0, colors: new Array, positions: new Array} | |
point: {length: 0, colors: new Array, positions: new Array} | |
# parameters defaults | |
antialias = true | |
clearColor = new THREE.Color 0x000000 | |
clearAlpha = 0 | |
if parameters | |
if parameters.antialias? then antialias = parameters.antialias | |
if parameters.clearColor? then clearColor.setHex parameters.clearColor | |
if parameters.clearAlpha? then clearAlpha = parameters.clearAlpha | |
@maxMorphTargets = 8 | |
@domElement = _canvas | |
@autoClear = true | |
@sortObjects = true | |
do -> # init | |
try | |
if !(_gl = _canvas.getContext('experimental-webgl', {antialias: antialias})) | |
throw 'Error creating WebGL context.' | |
catch e | |
console.error e | |
_gl.clearColor 0, 0, 0, 1 | |
_gl.clearDepth 1 | |
_gl.enable _gl.DEPTH_TEST | |
_gl.depthFunc _gl.LEQUAL | |
_gl.frontFace _gl.CCW | |
_gl.cullFace _gl.BACK | |
_gl.enable _gl.CULL_FACE | |
_gl.enable _gl.BLEND | |
_gl.blendFunc _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA | |
_gl.clearColor clearColor.r, clearColor.g, clearColor.b, clearAlpha | |
_cullEnabled = true | |
@context = _gl | |
@setSize = (width, height) -> | |
_canvas.width = width | |
_canvas.height = height | |
@setViewport 0, 0, _canvas.width, _canvas.height | |
@setViewport = (x, y, width, height) -> | |
_viewportX = x | |
_viewportY = y | |
_viewportWidth = width | |
_viewportHeight = height | |
_gl.viewport _viewportX, _viewportY, _viewportWidth, _viewportHeight | |
@setScissor = (x, y, width, height) -> _gl.scissor x, y, width, height | |
@enableScissorTest = (enable) -> if enable then _gl.enable _gl.SCISSOR_TEST else _gl.disable _gl.SCISSOR_TEST | |
@enableDepthBufferWrite = (enable) -> _gl.depthMask enable | |
@setClearColorHex = (hex, alpha) -> | |
color = new THREE.Color hex | |
_gl.clearColor color.r, color.g, color.b, alpha | |
@setClearColor = (color, alpha) -> _gl.clearColor color.r, color.g, color.b, alpha | |
@clear = -> _gl.clear _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | |
setupLights = (program, lights) -> | |
l = null | |
ll = null | |
light = null | |
r = 0 | |
g = 0 | |
b = 0 | |
color = null | |
position = null | |
intensity = null | |
zlights = _lights | |
dcolors = zlights.directional.colors | |
dpositions = zlights.directional.positions | |
pcolors = zlights.point.colors | |
ppositions = zlights.point.positions | |
dlength = 0 | |
plength = 0 | |
doffset = 0 | |
poffset = 0 | |
for light in lights | |
color = light.color | |
position = light.position | |
intensity = light.intensity | |
if light instanceof THREE.AmbientLight | |
r += color.r | |
g += color.g | |
b += color.b | |
else if light instanceof THREE.DirectionalLight | |
doffset = dlength * 3 | |
dcolors[doffset] = color.r * intensity | |
dcolors[doffset + 1] = color.g * intensity | |
dcolors[doffset + 2] = color.b * intensity | |
dpositions[doffset] = position.x | |
dpositions[doffset + 1] = position.y | |
dpositions[doffset + 2] = position.z | |
dlength += 1 | |
else if light instanceof THREE.PointLight | |
poffset = plength * 3 | |
pcolors[poffset] = color.r * intensity | |
pcolors[poffset + 1] = color.g * intensity | |
pcolors[poffset + 2] = color.b * intensity | |
ppositions[poffset] = position.x | |
ppositions[poffset + 1] = position.y | |
ppositions[poffset + 2] = position.z | |
plength += 1 | |
for l in [(dlength * 3)...dcolors.length] then dcolors[l] = 0.0 | |
for l in [(plength * 3)...pcolors.length] then pcolors[l] = 0.0 | |
zlights.point.length = plength | |
zlights.directional.length = dlength | |
zlights.ambient[0] = r | |
zlights.ambient[1] = g | |
zlights.ambient[2] = b | |
createParticleBuffers = (geometry) -> | |
geometry.__webGLVertexBuffer = _gl.createBuffer() | |
geometry.__webGLColorBuffer = _gl.createBuffer() | |
createLineBuffers = (geometry) -> | |
geometry.__webGLVertexBuffer = _gl.createBuffer() | |
geometry.__webGLColorBuffer = _gl.createBuffer() | |
createRibbonBuffers = (geometry) -> | |
geometry.__webGLVertexBuffer = _gl.createBuffer() | |
geometry.__webGLColorBuffer = _gl.createBuffer() | |
createMeshBuffers = (geometryGroup) -> | |
geometryGroup.__webGLVertexBuffer = _gl.createBuffer() | |
geometryGroup.__webGLNormalBuffer = _gl.createBuffer() | |
geometryGroup.__webGLTangentBuffer = _gl.createBuffer() | |
geometryGroup.__webGLColorBuffer = _gl.createBuffer() | |
geometryGroup.__webGLUVBuffer = _gl.createBuffer() | |
geometryGroup.__webGLUV2Buffer = _gl.createBuffer() | |
geometryGroup.__webGLSkinVertexABuffer = _gl.createBuffer() | |
geometryGroup.__webGLSkinVertexBBuffer = _gl.createBuffer() | |
geometryGroup.__webGLSkinIndicesBuffer = _gl.createBuffer() | |
geometryGroup.__webGLSkinWeightsBuffer = _gl.createBuffer() | |
geometryGroup.__webGLFaceBuffer = _gl.createBuffer() | |
geometryGroup.__webGLLineBuffer = _gl.createBuffer() | |
if geometryGroup.numMorphTargets | |
geometryGroup.__webGLMorphTargetsBuffers = new Array | |
for m in [0...geometryGroup.numMorphTargets] then geometryGroup.__webGLMorphTargetsBuffers.push _gl.createBuffer() | |
initLineBuffers = (geometry) -> | |
nvertices = geometry.vertices.length | |
geometry.__vertexArray = new Float32Array nvertices * 3 | |
geometry.__colorArray = new Float32Array nvertices * 3 | |
geometry.__webGLLineCount = nvertices | |
initRibbonBuffers = (geometry) -> | |
nvertices = geometry.vertices.length | |
geometry.__vertexArray = new Float32Array nvertices * 3 | |
geometry.__colorArray = new Float32Array nvertices * 3 | |
geometry.__webGLVertexCount = nvertices | |
initParticleBuffers = (geometry) -> | |
nvertices = geometry.vertices.length | |
geometry.__vertexArray = new Float32Array nvertices * 3 | |
geometry.__colorArray = new Float32Array nvertices * 3 | |
geometry.__sortArray = new Array | |
geometry.__webGLParticleCount = nvertices | |
initMeshBuffers = (geometryGroup, object) -> | |
f = null | |
fl = null | |
nvertices = 0 | |
ntris = 0 | |
nlines = 0 | |
obj_faces = object.geometry.faces | |
chunk_faces = geometryGroup.faces | |
for f in [0...chunk_faces.length] | |
face = obj_faces[chunk_faces[f]] | |
if face instanceof THREE.Face3 | |
nvertices += 3 | |
ntris += 1 | |
nlines += 3 | |
else if face instanceof THREE.Face4 | |
nvertices += 4 | |
ntris += 2 | |
nlines += 4 | |
# TODO: only create arrays for attributes existing in the object | |
geometryGroup.__vertexArray = new Float32Array nvertices * 3 | |
geometryGroup.__normalArray = new Float32Array nvertices * 3 | |
geometryGroup.__tangentArray = new Float32Array nvertices * 4 | |
geometryGroup.__colorArray = new Float32Array nvertices * 3 | |
geometryGroup.__uvArray = new Float32Array nvertices * 2 | |
geometryGroup.__uv2Array = new Float32Array nvertices * 2 | |
geometryGroup.__skinVertexAArray = new Float32Array nvertices * 4 | |
geometryGroup.__skinVertexBArray = new Float32Array nvertices * 4 | |
geometryGroup.__skinIndexArray = new Float32Array nvertices * 4 | |
geometryGroup.__skinWeightArray = new Float32Array nvertices * 4 | |
geometryGroup.__faceArray = new Uint16Array ntris * 3 | |
geometryGroup.__lineArray = new Uint16Array nlines * 2 | |
geometryGroup.__needsSmoothNormals = bufferNeedsSmoothNormals geometryGroup, object | |
geometryGroup.__webGLFaceCount = ntris * 3 | |
geometryGroup.__webGLLineCount = nlines * 2 | |
if geometryGroup.numMorphTargets | |
geometryGroup.__morphTargetsArrays = new Array | |
for m in [0...geometryGroup.numMorphTargets] | |
geometryGroup.__morphTargetsArrays.push new Float32Array(nvertices * 3) | |
setMeshBuffers = (geometryGroup, object, hint) -> | |
f = null | |
fl = null | |
fi = null | |
face = null | |
vertexNormals = null | |
faceNormal = null | |
normal = null | |
uv = uv2 = null | |
v1 = v2 = v3 = v4 = null | |
t1 = t2 = t3 = t4 = null | |
c1 = c2 = c3 = c4 = null | |
sw1 = sw2 = sw3 = sw4 = null | |
si1 = si2 = si3 = si4 = null | |
sa1 = sa2 = sa3 = sa4 = null | |
sb1 = sb2 = sb3 = sb4 = null | |
m = ml = i = null | |
vn = uvi = uv2i = null | |
vk = vkl = vka = null | |
vertexIndex = 0 | |
offset = 0 | |
offset_uv = 0 | |
offset_uv2 = 0 | |
offset_face = 0 | |
offset_normal = 0 | |
offset_tangent = 0 | |
offset_line = 0 | |
offset_color = 0 | |
offset_skin = 0 | |
offset_morphTarget = 0 | |
vertexArray = geometryGroup.__vertexArray | |
uvArray = geometryGroup.__uvArray | |
uv2Array = geometryGroup.__uv2Array | |
normalArray = geometryGroup.__normalArray | |
tangentArray = geometryGroup.__tangentArray | |
colorArray = geometryGroup.__colorArray | |
skinVertexAArray = geometryGroup.__skinVertexAArray | |
skinVertexBArray = geometryGroup.__skinVertexBArray | |
skinIndexArray = geometryGroup.__skinIndexArray | |
skinWeightArray = geometryGroup.__skinWeightArray | |
morphTargetsArrays = geometryGroup.__morphTargetsArrays | |
faceArray = geometryGroup.__faceArray | |
lineArray = geometryGroup.__lineArray | |
needsSmoothNormals = geometryGroup.__needsSmoothNormals | |
geometry = object.geometry | |
dirtyVertices = geometry.__dirtyVertices | |
dirtyElements = geometry.__dirtyElements | |
dirtyUvs = geometry.__dirtyUvs | |
dirtyNormals = geometry.__dirtyNormals | |
dirtyTangents = geometry.__dirtyTangents | |
dirtyColors = geometry.__dirtyColors | |
dirtyMorphTargets = geometry.__dirtyMorphTargets | |
vertices = geometry.vertices | |
chunk_faces = geometryGroup.faces | |
obj_faces = geometry.faces | |
obj_uvs = geometry.uvs | |
obj_uvs2 = geometry.uvs2 | |
obj_colors = geometry.colors | |
obj_skinVerticesA = geometry.skinVerticesA | |
obj_skinVerticesB = geometry.skinVerticesB | |
obj_skinIndices = geometry.skinIndices | |
obj_skinWeights = geometry.skinWeights | |
morphTargets = geometry.morphTargets | |
for f in [0...chunk_faces.length] | |
fi = chunk_faces[f] | |
face = obj_faces[fi] | |
uv = obj_uvs[fi] | |
uv2 = obj_uvs2[fi] | |
vertexNormals = face.vertexNormals | |
faceNormal = face.normal | |
if face instanceof THREE.Face3 | |
if dirtyVertices | |
v1 = vertices[face.a].position | |
v2 = vertices[face.b].position | |
v3 = vertices[face.c].position | |
vertexArray[offset] = v1.x | |
vertexArray[offset + 1] = v1.y | |
vertexArray[offset + 2] = v1.z | |
vertexArray[offset + 3] = v2.x | |
vertexArray[offset + 4] = v2.y | |
vertexArray[offset + 5] = v2.z | |
vertexArray[offset + 6] = v3.x | |
vertexArray[offset + 7] = v3.y | |
vertexArray[offset + 8] = v3.z | |
offset += 9 | |
if dirtyMorphTargets | |
for vk in [0...morphTargets.length] | |
v1 = morphTargets[vk].vertices[face.a].position | |
v2 = morphTargets[vk].vertices[face.b].position | |
v3 = morphTargets[vk].vertices[face.c].position | |
vka = morphTargetsArrays[vk] | |
vka[offset_morphTarget + 0] = v1.x | |
vka[offset_morphTarget + 1] = v1.y | |
vka[offset_morphTarget + 2] = v1.z | |
vka[offset_morphTarget + 3] = v2.x | |
vka[offset_morphTarget + 4] = v2.y | |
vka[offset_morphTarget + 5] = v2.z | |
vka[offset_morphTarget + 6] = v3.x | |
vka[offset_morphTarget + 7] = v3.y | |
vka[offset_morphTarget + 8] = v3.z | |
offset_morphTarget += 9 | |
if obj_skinWeights.length | |
sw1 = obj_skinWeights[face.a] | |
sw2 = obj_skinWeights[face.b] | |
sw3 = obj_skinWeights[face.c] | |
skinWeightArray[offset_skin] = sw1.x | |
skinWeightArray[offset_skin + 1] = sw1.y | |
skinWeightArray[offset_skin + 2] = sw1.z | |
skinWeightArray[offset_skin + 3] = sw1.w | |
skinWeightArray[offset_skin + 4] = sw2.x | |
skinWeightArray[offset_skin + 5] = sw2.y | |
skinWeightArray[offset_skin + 6] = sw2.z | |
skinWeightArray[offset_skin + 7] = sw2.w | |
skinWeightArray[offset_skin + 8] = sw3.x | |
skinWeightArray[offset_skin + 9] = sw3.y | |
skinWeightArray[offset_skin + 10] = sw3.z | |
skinWeightArray[offset_skin + 11] = sw3.w | |
# indices | |
si1 = obj_skinIndices[face.a] | |
si2 = obj_skinIndices[face.b] | |
si3 = obj_skinIndices[face.c] | |
skinIndexArray[offset_skin] = si1.x | |
skinIndexArray[offset_skin + 1] = si1.y | |
skinIndexArray[offset_skin + 2] = si1.z | |
skinIndexArray[offset_skin + 3] = si1.w | |
skinIndexArray[offset_skin + 4] = si2.x | |
skinIndexArray[offset_skin + 5] = si2.y | |
skinIndexArray[offset_skin + 6] = si2.z | |
skinIndexArray[offset_skin + 7] = si2.w | |
skinIndexArray[offset_skin + 8] = si3.x | |
skinIndexArray[offset_skin + 9] = si3.y | |
skinIndexArray[offset_skin + 10] = si3.z | |
skinIndexArray[offset_skin + 11] = si3.w | |
# vertices A | |
sa1 = obj_skinVerticesA[face.a] | |
sa2 = obj_skinVerticesA[face.b] | |
sa3 = obj_skinVerticesA[face.c] | |
skinVertexAArray[offset_skin] = sa1.x | |
skinVertexAArray[offset_skin + 1] = sa1.y | |
skinVertexAArray[offset_skin + 2] = sa1.z | |
skinVertexAArray[offset_skin + 3] = 1 | |
skinVertexAArray[offset_skin + 4] = sa2.x | |
skinVertexAArray[offset_skin + 5] = sa2.y | |
skinVertexAArray[offset_skin + 6] = sa2.z | |
skinVertexAArray[offset_skin + 7] = 1 | |
skinVertexAArray[offset_skin + 8] = sa3.x | |
skinVertexAArray[offset_skin + 9] = sa3.y | |
skinVertexAArray[offset_skin + 10] = sa3.z | |
skinVertexAArray[offset_skin + 11] = 1 | |
# vertices B | |
sb1 = obj_skinVerticesB[face.a] | |
sb2 = obj_skinVerticesB[face.b] | |
sb3 = obj_skinVerticesB[face.c] | |
skinVertexBArray[offset_skin] = sb1.x | |
skinVertexBArray[offset_skin + 1] = sb1.y | |
skinVertexBArray[offset_skin + 2] = sb1.z | |
skinVertexBArray[offset_skin + 3] = 1 | |
skinVertexBArray[offset_skin + 4] = sb2.x | |
skinVertexBArray[offset_skin + 5] = sb2.y | |
skinVertexBArray[offset_skin + 6] = sb2.z | |
skinVertexBArray[offset_skin + 7] = 1 | |
skinVertexBArray[offset_skin + 8] = sb3.x | |
skinVertexBArray[offset_skin + 9] = sb3.y | |
skinVertexBArray[offset_skin + 10] = sb3.z | |
skinVertexBArray[offset_skin + 11] = 1 | |
offset_skin += 12 | |
if dirtyColors && obj_colors.length | |
c1 = obj_colors[face.a] | |
c2 = obj_colors[face.b] | |
c3 = obj_colors[face.c] | |
colorArray[offset_color] = c1.r | |
colorArray[offset_color + 1] = c1.g | |
colorArray[offset_color + 2] = c1.b | |
colorArray[offset_color + 3] = c2.r | |
colorArray[offset_color + 4] = c2.g | |
colorArray[offset_color + 5] = c2.b | |
colorArray[offset_color + 6] = c3.r | |
colorArray[offset_color + 7] = c3.g | |
colorArray[offset_color + 8] = c3.b | |
offset_color += 9 | |
if dirtyTangents && geometry.hasTangents | |
t1 = vertices[face.a].tangent | |
t2 = vertices[face.b].tangent | |
t3 = vertices[face.c].tangent | |
tangentArray[offset_tangent] = t1.x | |
tangentArray[offset_tangent + 1] = t1.y | |
tangentArray[offset_tangent + 2] = t1.z | |
tangentArray[offset_tangent + 3] = t1.w | |
tangentArray[offset_tangent + 4] = t2.x | |
tangentArray[offset_tangent + 5] = t2.y | |
tangentArray[offset_tangent + 6] = t2.z | |
tangentArray[offset_tangent + 7] = t2.w | |
tangentArray[offset_tangent + 8] = t3.x | |
tangentArray[offset_tangent + 9] = t3.y | |
tangentArray[offset_tangent + 10] = t3.z | |
tangentArray[offset_tangent + 11] = t3.w | |
offset_tangent += 12 | |
if dirtyNormals | |
if vertexNormals.length is 3 && needsSmoothNormals | |
for vn in vertexNormals | |
normalArray[offset_normal] = vn.x | |
normalArray[offset_normal + 1] = vn.y | |
normalArray[offset_normal + 2] = vn.z | |
offset_normal += 3 | |
else | |
for i in [0...3] | |
normalArray[offset_normal] = faceNormal.x | |
normalArray[offset_normal + 1] = faceNormal.y | |
normalArray[offset_normal + 2] = faceNormal.z | |
offset_normal += 3 | |
if dirtyUvs && uv | |
for uvi in uv | |
uvArray[offset_uv] = uvi.u | |
uvArray[offset_uv + 1] = uvi.v | |
offset_uv += 2 | |
if dirtyUvs && uv2 | |
for uv2i in uv2 | |
uv2Array[offset_uv2] = uv2i.u | |
uv2Array[offset_uv2 + 1] = uv2i.v | |
offset_uv2 += 2 | |
if dirtyElements | |
faceArray[offset_face] = vertexIndex | |
faceArray[offset_face + 1] = vertexIndex + 1 | |
faceArray[offset_face + 2] = vertexIndex + 2 | |
offset_face += 3 | |
lineArray[offset_line] = vertexIndex | |
lineArray[offset_line + 1] = vertexIndex + 1 | |
lineArray[offset_line + 2] = vertexIndex | |
lineArray[offset_line + 3] = vertexIndex + 2 | |
lineArray[offset_line + 4] = vertexIndex + 1 | |
lineArray[offset_line + 5] = vertexIndex + 2 | |
offset_line += 6 | |
vertexIndex += 3 | |
else if face instanceof THREE.Face4 | |
if dirtyVertices | |
v1 = vertices[face.a].position | |
v2 = vertices[face.b].position | |
v3 = vertices[face.c].position | |
v4 = vertices[face.d].position | |
vertexArray[offset] = v1.x | |
vertexArray[offset + 1] = v1.y | |
vertexArray[offset + 2] = v1.z | |
vertexArray[offset + 3] = v2.x | |
vertexArray[offset + 4] = v2.y | |
vertexArray[offset + 5] = v2.z | |
vertexArray[offset + 6] = v3.x | |
vertexArray[offset + 7] = v3.y | |
vertexArray[offset + 8] = v3.z | |
vertexArray[offset + 9] = v4.x | |
vertexArray[offset + 10] = v4.y | |
vertexArray[offset + 11] = v4.z | |
offset += 12 | |
if dirtyMorphTargets | |
for vk in [0...morphTargets.length] | |
v1 = morphTargets[vk].vertices[face.a].position | |
v2 = morphTargets[vk].vertices[face.b].position | |
v3 = morphTargets[vk].vertices[face.c].position | |
v4 = morphTargets[vk].vertices[face.d].position | |
vka = morphTargetsArrays[vk] | |
vka[offset_morphTarget + 0] = v1.x | |
vka[offset_morphTarget + 1] = v1.y | |
vka[offset_morphTarget + 2] = v1.z | |
vka[offset_morphTarget + 3] = v2.x | |
vka[offset_morphTarget + 4] = v2.y | |
vka[offset_morphTarget + 5] = v2.z | |
vka[offset_morphTarget + 6] = v3.x | |
vka[offset_morphTarget + 7] = v3.y | |
vka[offset_morphTarget + 8] = v3.z | |
vka[offset_morphTarget + 9] = v4.x | |
vka[offset_morphTarget + 10] = v4.y | |
vka[offset_morphTarget + 11] = v4.z | |
offset_morphTarget += 12 | |
if obj_skinWeights.length | |
# weights | |
sw1 = obj_skinWeights[face.a] | |
sw2 = obj_skinWeights[face.b] | |
sw3 = obj_skinWeights[face.c] | |
sw4 = obj_skinWeights[face.d] | |
skinWeightArray[offset_skin] = sw1.x | |
skinWeightArray[offset_skin + 1] = sw1.y | |
skinWeightArray[offset_skin + 2] = sw1.z | |
skinWeightArray[offset_skin + 3] = sw1.w | |
skinWeightArray[offset_skin + 4] = sw2.x | |
skinWeightArray[offset_skin + 5] = sw2.y | |
skinWeightArray[offset_skin + 6] = sw2.z | |
skinWeightArray[offset_skin + 7] = sw2.w | |
skinWeightArray[offset_skin + 8] = sw3.x | |
skinWeightArray[offset_skin + 9] = sw3.y | |
skinWeightArray[offset_skin + 10] = sw3.z | |
skinWeightArray[offset_skin + 11] = sw3.w | |
skinWeightArray[offset_skin + 12] = sw4.x | |
skinWeightArray[offset_skin + 13] = sw4.y | |
skinWeightArray[offset_skin + 14] = sw4.z | |
skinWeightArray[offset_skin + 15] = sw4.w | |
# indices | |
si1 = obj_skinIndices[face.a] | |
si2 = obj_skinIndices[face.b] | |
si3 = obj_skinIndices[face.c] | |
si4 = obj_skinIndices[face.d] | |
skinIndexArray[offset_skin] = si1.x | |
skinIndexArray[offset_skin + 1] = si1.y | |
skinIndexArray[offset_skin + 2] = si1.z | |
skinIndexArray[offset_skin + 3] = si1.w | |
skinIndexArray[offset_skin + 4] = si2.x | |
skinIndexArray[offset_skin + 5] = si2.y | |
skinIndexArray[offset_skin + 6] = si2.z | |
skinIndexArray[offset_skin + 7] = si2.w | |
skinIndexArray[offset_skin + 8] = si3.x | |
skinIndexArray[offset_skin + 9] = si3.y | |
skinIndexArray[offset_skin + 10] = si3.z | |
skinIndexArray[offset_skin + 11] = si3.w | |
skinIndexArray[offset_skin + 12] = si4.x | |
skinIndexArray[offset_skin + 13] = si4.y | |
skinIndexArray[offset_skin + 14] = si4.z | |
skinIndexArray[offset_skin + 15] = si4.w | |
# vertices A | |
sa1 = obj_skinVerticesA[face.a] | |
sa2 = obj_skinVerticesA[face.b] | |
sa3 = obj_skinVerticesA[face.c] | |
sa4 = obj_skinVerticesA[face.d] | |
skinVertexAArray[offset_skin] = sa1.x | |
skinVertexAArray[offset_skin + 1] = sa1.y | |
skinVertexAArray[offset_skin + 2] = sa1.z | |
skinVertexAArray[offset_skin + 3] = 1 | |
skinVertexAArray[offset_skin + 4] = sa2.x | |
skinVertexAArray[offset_skin + 5] = sa2.y | |
skinVertexAArray[offset_skin + 6] = sa2.z | |
skinVertexAArray[offset_skin + 7] = 1 | |
skinVertexAArray[offset_skin + 8] = sa3.x | |
skinVertexAArray[offset_skin + 9] = sa3.y | |
skinVertexAArray[offset_skin + 10] = sa3.z | |
skinVertexAArray[offset_skin + 11] = 1 | |
skinVertexAArray[offset_skin + 12] = sa4.x | |
skinVertexAArray[offset_skin + 13] = sa4.y | |
skinVertexAArray[offset_skin + 14] = sa4.z | |
skinVertexAArray[offset_skin + 15] = 1 | |
# vertices B | |
sb1 = obj_skinVerticesB[face.a] | |
sb2 = obj_skinVerticesB[face.b] | |
sb3 = obj_skinVerticesB[face.c] | |
sb4 = obj_skinVerticesB[face.d] | |
skinVertexBArray[offset_skin] = sb1.x | |
skinVertexBArray[offset_skin + 1] = sb1.y | |
skinVertexBArray[offset_skin + 2] = sb1.z | |
skinVertexBArray[offset_skin + 3] = 1 | |
skinVertexBArray[offset_skin + 4] = sb2.x | |
skinVertexBArray[offset_skin + 5] = sb2.y | |
skinVertexBArray[offset_skin + 6] = sb2.z | |
skinVertexBArray[offset_skin + 7] = 1 | |
skinVertexBArray[offset_skin + 8] = sb3.x | |
skinVertexBArray[offset_skin + 9] = sb3.y | |
skinVertexBArray[offset_skin + 10] = sb3.z | |
skinVertexBArray[offset_skin + 11] = 1 | |
skinVertexBArray[offset_skin + 12] = sb4.x | |
skinVertexBArray[offset_skin + 13] = sb4.y | |
skinVertexBArray[offset_skin + 14] = sb4.z | |
skinVertexBArray[offset_skin + 15] = 1 | |
offset_skin += 16 | |
if dirtyColors && obj_colors.length | |
c1 = obj_colors[face.a] | |
c2 = obj_colors[face.b] | |
c3 = obj_colors[face.c] | |
c4 = obj_colors[face.d] | |
colorArray[offset_color] = c1.r | |
colorArray[offset_color + 1] = c1.g | |
colorArray[offset_color + 2] = c1.b | |
colorArray[offset_color + 3] = c2.r | |
colorArray[offset_color + 4] = c2.g | |
colorArray[offset_color + 5] = c2.b | |
colorArray[offset_color + 6] = c3.r | |
colorArray[offset_color + 7] = c3.g | |
colorArray[offset_color + 8] = c3.b | |
colorArray[offset_color + 9] = c4.r | |
colorArray[offset_color + 10] = c4.g | |
colorArray[offset_color + 11] = c4.b | |
offset_color += 12 | |
if dirtyTangents && geometry.hasTangents | |
t1 = vertices[face.a].tangent | |
t2 = vertices[face.b].tangent | |
t3 = vertices[face.c].tangent | |
t4 = vertices[face.d].tangent | |
tangentArray[offset_tangent] = t1.x | |
tangentArray[offset_tangent + 1] = t1.y | |
tangentArray[offset_tangent + 2] = t1.z | |
tangentArray[offset_tangent + 3] = t1.w | |
tangentArray[offset_tangent + 4] = t2.x | |
tangentArray[offset_tangent + 5] = t2.y | |
tangentArray[offset_tangent + 6] = t2.z | |
tangentArray[offset_tangent + 7] = t2.w | |
tangentArray[offset_tangent + 8] = t3.x | |
tangentArray[offset_tangent + 9] = t3.y | |
tangentArray[offset_tangent + 10] = t3.z | |
tangentArray[offset_tangent + 11] = t3.w | |
tangentArray[offset_tangent + 12] = t4.x | |
tangentArray[offset_tangent + 13] = t4.y | |
tangentArray[offset_tangent + 14] = t4.z | |
tangentArray[offset_tangent + 15] = t4.w | |
offset_tangent += 16 | |
if dirtyNormals | |
if vertexNormals.length is 4 && needsSmoothNormals | |
for vn in vertexNormals | |
vn = vertexNormals[i] | |
normalArray[offset_normal] = vn.x | |
normalArray[offset_normal + 1] = vn.y | |
normalArray[offset_normal + 2] = vn.z | |
offset_normal += 3 | |
else | |
for i in [0...4] | |
normalArray[offset_normal] = faceNormal.x | |
normalArray[offset_normal + 1] = faceNormal.y | |
normalArray[offset_normal + 2] = faceNormal.z | |
offset_normal += 3 | |
if dirtyUvs && uv | |
for uvi in uv | |
uvArray[offset_uv] = uvi.u | |
uvArray[offset_uv + 1] = uvi.v | |
offset_uv += 2 | |
if dirtyUvs && uv2 | |
for uv2i in uv2 | |
uv2i = uv2[i] | |
uv2Array[offset_uv2] = uv2i.u | |
uv2Array[offset_uv2 + 1] = uv2i.v | |
offset_uv2 += 2 | |
if dirtyElements | |
faceArray[offset_face] = vertexIndex | |
faceArray[offset_face + 1] = vertexIndex + 1 | |
faceArray[offset_face + 2] = vertexIndex + 2 | |
faceArray[offset_face + 3] = vertexIndex | |
faceArray[offset_face + 4] = vertexIndex + 2 | |
faceArray[offset_face + 5] = vertexIndex + 3 | |
offset_face += 6 | |
lineArray[offset_line] = vertexIndex | |
lineArray[offset_line + 1] = vertexIndex + 1 | |
lineArray[offset_line + 2] = vertexIndex | |
lineArray[offset_line + 3] = vertexIndex + 3 | |
lineArray[offset_line + 4] = vertexIndex + 1 | |
lineArray[offset_line + 5] = vertexIndex + 2 | |
lineArray[offset_line + 6] = vertexIndex + 2 | |
lineArray[offset_line + 7] = vertexIndex + 3 | |
offset_line += 8 | |
vertexIndex += 4 | |
if dirtyVertices | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, vertexArray, hint | |
if dirtyMorphTargets | |
for vk in [0...morphTargets.length] | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLMorphTargetsBuffers[vk] | |
_gl.bufferData _gl.ARRAY_BUFFER, morphTargetsArrays[vk], hint | |
if dirtyColors && obj_colors.length | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLColorBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, colorArray, hint | |
if dirtyNormals | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, normalArray, hint | |
if dirtyTangents && geometry.hasTangents | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLTangentBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, tangentArray, hint | |
if dirtyUvs && offset_uv > 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLUVBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, uvArray, hint | |
if dirtyUvs && offset_uv2 > 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLUV2Buffer | |
_gl.bufferData _gl.ARRAY_BUFFER, uv2Array, hint | |
if dirtyElements | |
_gl.bindBuffer _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer | |
_gl.bufferData _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint | |
_gl.bindBuffer _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLLineBuffer | |
_gl.bufferData _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint | |
if offset_skin > 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexABuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, skinVertexAArray, hint | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexBBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, skinVertexBArray, hint | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinIndicesBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, skinIndexArray, hint | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinWeightsBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, skinWeightArray, hint | |
setLineBuffers = (geometry, hint) -> | |
v = null | |
c = null | |
vertex = null | |
offset = null | |
vertices = geometry.vertices | |
colors = geometry.colors | |
vl = vertices.length | |
cl = colors.length | |
vertexArray = geometry.__vertexArray | |
colorArray = geometry.__colorArray | |
dirtyVertices = geometry.__dirtyVertices | |
dirtyColors = geometry.__dirtyColors | |
if dirtyVertices | |
for v in [0...vl] | |
vertex = vertices[v].position | |
offset = v * 3 | |
vertexArray[offset] = vertex.x | |
vertexArray[offset + 1] = vertex.y | |
vertexArray[offset + 2] = vertex.z | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometry.__webGLVertexBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, vertexArray, hint | |
if dirtyColors | |
for c in [0...cl] | |
color = colors[c] | |
offset = c * 3 | |
colorArray[offset] = color.r | |
colorArray[offset + 1] = color.g | |
colorArray[offset + 2] = color.b | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometry.__webGLColorBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, colorArray, hint | |
setRibbonBuffers = (geometry, hint) -> | |
v = null | |
c = null | |
vertex = null | |
offset = null | |
vertices = geometry.vertices | |
colors = geometry.colors | |
vl = vertices.length | |
cl = colors.length | |
vertexArray = geometry.__vertexArray | |
colorArray = geometry.__colorArray | |
dirtyVertices = geometry.__dirtyVertices | |
dirtyColors = geometry.__dirtyColors | |
if dirtyVertices | |
for v in [0...vl] | |
vertex = vertices[v].position | |
offset = v * 3 | |
vertexArray[offset] = vertex.x | |
vertexArray[offset + 1] = vertex.y | |
vertexArray[offset + 2] = vertex.z | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometry.__webGLVertexBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, vertexArray, hint | |
if dirtyColors | |
for c in [0...cl] | |
color = colors[c] | |
offset = c * 3 | |
colorArray[offset] = color.r | |
colorArray[offset + 1] = color.g | |
colorArray[offset + 2] = color.b | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometry.__webGLColorBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, colorArray, hint | |
setParticleBuffers = (geometry, hint, object) -> | |
v = null | |
c = null | |
vertex = null | |
offset = null | |
vertices = geometry.vertices | |
vl = vertices.length | |
colors = geometry.colors | |
cl = colors.length | |
vertexArray = geometry.__vertexArray | |
colorArray = geometry.__colorArray | |
sortArray = geometry.__sortArray | |
dirtyVertices = geometry.__dirtyVertices | |
dirtyElements = geometry.__dirtyElements | |
dirtyColors = geometry.__dirtyColors | |
if object.sortParticles | |
_projScreenMatrix.multiplySelf object.matrixWorld | |
for v in [0...vl] | |
vertex = vertices[v].position | |
_vector3.copy vertex | |
_projScreenMatrix.multiplyVector3 _vector3 | |
sortArray[v] = [_vector3.z, v] | |
sortArray.sort (a, b) -> b[0] - a[0] | |
for v in [0...vl] | |
vertex = vertices[sortArray[v][1]].position | |
offset = v * 3 | |
vertexArray[offset] = vertex.x | |
vertexArray[offset + 1] = vertex.y | |
vertexArray[offset + 2] = vertex.z | |
for c in [0...cl] | |
offset = c * 3 | |
color = colors[sortArray[c][1]] | |
colorArray[offset] = color.r | |
colorArray[offset + 1] = color.g | |
colorArray[offset + 2] = color.b | |
else | |
if dirtyVertices | |
for v in [0...vl] | |
vertex = vertices[v].position | |
offset = v * 3 | |
vertexArray[offset] = vertex.x | |
vertexArray[offset + 1] = vertex.y | |
vertexArray[offset + 2] = vertex.z | |
if dirtyColors | |
for c in [0...cl] | |
color = colors[c] | |
offset = c * 3 | |
colorArray[offset] = color.r | |
colorArray[offset + 1] = color.g | |
colorArray[offset + 2] = color.b | |
if dirtyVertices || object.sortParticles | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometry.__webGLVertexBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, vertexArray, hint | |
if dirtyColors || object.sortParticles | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometry.__webGLColorBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, colorArray, hint | |
setMaterialShaders = (material, shaders) -> | |
material.fragmentShader = shaders.fragmentShader | |
material.vertexShader = shaders.vertexShader | |
material.uniforms = Uniforms.clone shaders.uniforms | |
refreshUniformsCommon = (uniforms, material) -> | |
# premultiply alpha | |
uniforms.diffuse.value.setRGB material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity | |
# pure color | |
#uniforms.color.value.setHex material.color.hex | |
uniforms.opacity.value = material.opacity | |
uniforms.map.texture = material.map | |
uniforms.lightMap.texture = material.lightMap | |
uniforms.envMap.texture = material.envMap | |
uniforms.reflectivity.value = material.reflectivity | |
uniforms.refractionRatio.value = material.refractionRatio | |
uniforms.combine.value = material.combine | |
uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping | |
refreshUniformsLine = (uniforms, material) -> | |
uniforms.diffuse.value.setRGB material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity | |
uniforms.opacity.value = material.opacity | |
refreshUniformsParticle = (uniforms, material) -> | |
uniforms.psColor.value.setRGB material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity | |
uniforms.opacity.value = material.opacity | |
uniforms.size.value = material.size | |
uniforms.scale.value = _canvas.height / 2.0 # TODO: Cache this | |
uniforms.map.texture = material.map | |
refreshUniformsFog = (uniforms, fog) -> | |
uniforms.fogColor.value.setHex fog.color.hex | |
if fog instanceof THREE.Fog | |
uniforms.fogNear.value = fog.near | |
uniforms.fogFar.value = fog.far | |
else if fog instanceof THREE.FogExp2 then uniforms.fogDensity.value = fog.density | |
refreshUniformsPhong = (uniforms, material) -> | |
# uniforms.ambient.value.setHex material.ambient.hex | |
# uniforms.specular.value.setHex material.specular.hex | |
uniforms.ambient.value.setRGB material.ambient.r, material.ambient.g, material.ambient.b | |
uniforms.specular.value.setRGB material.specular.r, material.specular.g, material.specular.b | |
uniforms.shininess.value = material.shininess | |
refreshUniformsLights = (uniforms, lights) -> | |
uniforms.enableLighting.value = lights.directional.length + lights.point.length | |
uniforms.ambientLightColor.value = lights.ambient | |
uniforms.directionalLightColor.value = lights.directional.colors | |
uniforms.directionalLightDirection.value = lights.directional.positions | |
uniforms.pointLightColor.value = lights.point.colors | |
uniforms.pointLightPosition.value = lights.point.positions | |
this.initMaterial = (material, lights, fog, object) -> | |
u = a = identifiers = i = parameters = maxLightCount = maxBones = null | |
if material instanceof THREE.MeshDepthMaterial then setMaterialShaders material, THREE.ShaderLib['depth'] | |
else if material instanceof THREE.MeshNormalMaterial then setMaterialShaders material, THREE.ShaderLib['normal'] | |
else if material instanceof THREE.MeshBasicMaterial then setMaterialShaders material, THREE.ShaderLib['basic'] | |
else if material instanceof THREE.MeshLambertMaterial then setMaterialShaders material, THREE.ShaderLib['lambert'] | |
else if material instanceof THREE.MeshPhongMaterial then setMaterialShaders material, THREE.ShaderLib['phong'] | |
else if material instanceof THREE.LineBasicMaterial then setMaterialShaders material, THREE.ShaderLib['basic'] | |
else if material instanceof THREE.ParticleBasicMaterial then setMaterialShaders material, THREE.ShaderLib['particle_basic'] | |
# heuristics to create shader parameters according to lights in the scene | |
# (not to blow over maxLights budget) | |
maxLightCount = allocateLights lights, 4 | |
maxBones = allocateBones object | |
parameters = | |
fog: fog | |
map: material.map | |
envMap: material.envMap | |
lightMap: material.lightMap | |
vertexColors: material.vertexColors | |
sizeAttenuation: material.sizeAttenuation | |
skinning: material.skinning | |
morphTargets: material.morphTargets | |
maxDirLights: maxLightCount.directional | |
maxPointLights: maxLightCount.point | |
maxBones: maxBones | |
material.program = buildProgram material.fragmentShader, material.vertexShader, parameters | |
# load uniforms | |
identifiers = ['viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'objectMatrix', 'cameraPosition', 'cameraInverseMatrix', 'boneGlobalMatrices', 'morphTargetInfluences'] | |
for k, v of material.uniforms then identifiers.push k | |
cacheUniformLocations material.program, identifiers | |
# load attributes | |
identifiers = ['position', 'normal', 'uv', 'uv2', 'tangent', 'color', 'skinVertexA', 'skinVertexB', 'skinIndex', 'skinWeight'] | |
for i in [0...@maxMorphTargets] then identifiers.push "morphTarget#{i}" | |
for k, v of material.attributes then identifiers.push k | |
cacheAttributeLocations material.program, identifiers | |
attributes = material.program.attributes | |
_gl.enableVertexAttribArray attributes.position | |
if attributes.color >= 0 then _gl.enableVertexAttribArray attributes.color | |
if attributes.normal >= 0 then _gl.enableVertexAttribArray attributes.normal | |
if attributes.tangent >= 0 then _gl.enableVertexAttribArray attributes.tangent | |
if material.skinning && attributes.skinVertexA >=0 && attributes.skinVertexB >= 0 && attributes.skinIndex >= 0 && attributes.skinWeight >= 0 | |
_gl.enableVertexAttribArray attributes.skinVertexA | |
_gl.enableVertexAttribArray attributes.skinVertexB | |
_gl.enableVertexAttribArray attributes.skinIndex | |
_gl.enableVertexAttribArray attributes.skinWeight | |
if material.morphTargets | |
material.numSupportedMorphTargets = 0 | |
if attributes.morphTarget0 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget0 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget1 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget1 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget2 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget2 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget3 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget3 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget4 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget4 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget5 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget5 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget6 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget6 | |
material.numSupportedMorphTargets++ | |
if attributes.morphTarget7 >= 0 | |
_gl.enableVertexAttribArray attributes.morphTarget7 | |
material.numSupportedMorphTargets++ | |
object.__webGLMorphTargetInfluences = new Float32Array @maxMorphTargets | |
for i in [0...@maxMorphTargets] then object.__webGLMorphTargetInfluences[i] = 0 | |
setProgram = (camera, lights, fog, material, object) -> | |
if not material.program then _this.initMaterial material, lights, fog, object | |
program = material.program | |
p_uniforms = program.uniforms | |
m_uniforms = material.uniforms | |
if program isnt _oldProgram | |
_gl.useProgram program | |
_oldProgram = program | |
_gl.uniformMatrix4fv p_uniforms.projectionMatrix, false, _projectionMatrixArray | |
# refresh uniforms common to several materials | |
if fog && (material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial || material instanceof THREE.LineBasicMaterial || material instanceof THREE.ParticleBasicMaterial) | |
refreshUniformsFog m_uniforms, fog | |
if material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || material.lights | |
setupLights program, lights | |
refreshUniformsLights m_uniforms, _lights | |
if material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial | |
refreshUniformsCommon m_uniforms, material | |
#refresh single material specific uniforms | |
if material instanceof THREE.LineBasicMaterial then refreshUniformsLine m_uniforms, material | |
else if material instanceof THREE.ParticleBasicMaterial then refreshUniformsParticle m_uniforms, material | |
else if material instanceof THREE.MeshPhongMaterial then refreshUniformsPhong m_uniforms, material | |
else if material instanceof THREE.MeshNormalMaterial then m_uniforms.opacity.value = material.opacity | |
else if material instanceof THREE.MeshDepthMaterial | |
m_uniforms.mNear.value = camera.near | |
m_uniforms.mFar.value = camera.far | |
m_uniforms.opacity.value = material.opacity | |
# load common uniforms | |
loadUniformsGeneric program, m_uniforms | |
loadUniformsMatrices p_uniforms, object | |
# load material specific uniforms | |
# (shader material also gets them for the sake of genericity) | |
if material instanceof THREE.MeshShaderMaterial || material instanceof THREE.MeshPhongMaterial || material.envMap | |
_gl.uniform3f p_uniforms.cameraPosition, camera.position.x, camera.position.y, camera.position.z | |
if material instanceof THREE.MeshShaderMaterial || material.envMap || material.skinning | |
_gl.uniformMatrix4fv p_uniforms.objectMatrix, false, object._objectMatrixArray | |
if material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshShaderMaterial || material.skinning | |
_gl.uniformMatrix4fv p_uniforms.viewMatrix, false, _viewMatrixArray | |
if material.skinning then loadUniformsSkinning p_uniforms, object | |
return program | |
renderBuffer = (camera, lights, fog, material, geometryGroup, object) -> | |
if material.opacity is 0 then return | |
program = attributes = linewidth = primitives = null | |
program = setProgram camera, lights, fog, material, object | |
attributes = program.attributes | |
# vertices | |
if not material.morphTargets | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer | |
_gl.vertexAttribPointer attributes.position, 3, _gl.FLOAT, false, 0, 0 | |
else | |
setupMorphTargets material, geometryGroup, object | |
# colors | |
if attributes.color >= 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLColorBuffer | |
_gl.vertexAttribPointer attributes.color, 3, _gl.FLOAT, false, 0, 0 | |
# normals | |
if attributes.normal >= 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer | |
_gl.vertexAttribPointer attributes.normal, 3, _gl.FLOAT, false, 0, 0 | |
# tangents | |
if attributes.tangent >= 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLTangentBuffer | |
_gl.vertexAttribPointer attributes.tangent, 4, _gl.FLOAT, false, 0, 0 | |
# uvs | |
if attributes.uv >= 0 | |
if geometryGroup.__webGLUVBuffer | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLUVBuffer | |
_gl.vertexAttribPointer attributes.uv, 2, _gl.FLOAT, false, 0, 0 | |
_gl.enableVertexAttribArray attributes.uv | |
else | |
_gl.disableVertexAttribArray attributes.uv | |
if attributes.uv2 >= 0 | |
if geometryGroup.__webGLUV2Buffer | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLUV2Buffer | |
_gl.vertexAttribPointer attributes.uv2, 2, _gl.FLOAT, false, 0, 0 | |
_gl.enableVertexAttribArray attributes.uv2 | |
else | |
_gl.disableVertexAttribArray attributes.uv2 | |
if material.skinning && attributes.skinVertexA >= 0 && attributes.skinVertexB >= 0 && attributes.skinIndex >= 0 && attributes.skinWeight >= 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexABuffer | |
_gl.vertexAttribPointer attributes.skinVertexA, 4, _gl.FLOAT, false, 0, 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexBBuffer | |
_gl.vertexAttribPointer attributes.skinVertexB, 4, _gl.FLOAT, false, 0, 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinIndicesBuffer | |
_gl.vertexAttribPointer attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinWeightsBuffer | |
_gl.vertexAttribPointer attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 | |
# render mesh | |
if object instanceof THREE.Mesh | |
# wireframe | |
if material.wireframe | |
_gl.lineWidth material.wireframeLinewidth | |
_gl.bindBuffer _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLLineBuffer | |
_gl.drawElements _gl.LINES, geometryGroup.__webGLLineCount, _gl.UNSIGNED_SHORT, 0 | |
# triangles | |
else | |
_gl.bindBuffer _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer | |
_gl.drawElements _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 | |
# render lines | |
else if object instanceof THREE.Line | |
primitives = if object.type is THREE.LineStrip then _gl.LINE_STRIP else _gl.LINES | |
_gl.lineWidth material.linewidth | |
_gl.drawArrays primitives, 0, geometryGroup.__webGLLineCount | |
# render particles | |
else if object instanceof THREE.ParticleSystem | |
_gl.drawArrays _gl.POINTS, 0, geometryGroup.__webGLParticleCount | |
# render ribbon | |
else if object instanceof THREE.Ribbon | |
_gl.drawArrays _gl.TRIANGLE_STRIP, 0, geometryGroup.__webGLVertexCount | |
setupMorphTargets = (material, geometryGroup, object) -> | |
# set base | |
attributes = material.program.attributes | |
if object.morphTargetBase isnt -1 | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLMorphTargetsBuffers[object.morphTargetBase] | |
_gl.vertexAttribPointer attributes.position, 3, _gl.FLOAT, false, 0, 0 | |
else | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer | |
_gl.vertexAttribPointer attributes.position, 3, _gl.FLOAT, false, 0, 0 | |
if object.morphTargetForcedOrder.length | |
# force order | |
m = 0 | |
order = object.morphTargetForcedOrder | |
influences = object.morphTargetInfluences | |
while m < material.numSupportedMorphTargets and m < order.length | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLMorphTargetsBuffers[order[m]] | |
_gl.vertexAttribPointer attributes["morphTarget" + m], 3, _gl.FLOAT, false, 0, 0 | |
object.__webGLMorphTargetInfluences[m] = influences[order[m]] | |
m++ | |
else | |
# find most influencing | |
used = [] | |
candidateInfluence = -1 | |
candidate = 0 | |
influences = object.morphTargetInfluences | |
m = 0 | |
if object.morphTargetBase isnt -1 then used[object.morphTargetBase] = true | |
while m < material.numSupportedMorphTargets | |
for i in [0...influences.length] | |
if !used[i] and influences[i] > candidateInfluence | |
candidate = i | |
candidateInfluence = influences[candidate] | |
_gl.bindBuffer _gl.ARRAY_BUFFER, geometryGroup.__webGLMorphTargetsBuffers[candidate] | |
_gl.vertexAttribPointer attributes["morphTarget" + m], 3, _gl.FLOAT, false, 0, 0 | |
object.__webGLMorphTargetInfluences[m] = candidateInfluence | |
used[candidate] = 1 | |
candidateInfluence = -1 | |
m++ | |
_gl.uniform1fv material.program.uniforms.morphTargetInfluences, object.__webGLMorphTargetInfluences | |
renderBufferImmediate = (object, program) -> | |
if not object.__webGLVertexBuffer then object.__webGLVertexBuffer = _gl.createBuffer() | |
if not object.__webGLNormalBuffer then object.__webGLNormalBuffer = _gl.createBuffer() | |
if object.hasPos | |
_gl.bindBuffer _gl.ARRAY_BUFFER, object.__webGLVertexBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW | |
_gl.enableVertexAttribArray program.attributes.position | |
_gl.vertexAttribPointer program.attributes.position, 3, _gl.FLOAT, false, 0, 0 | |
if object.hasNormal | |
_gl.bindBuffer _gl.ARRAY_BUFFER, object.__webGLNormalBuffer | |
_gl.bufferData _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW | |
_gl.enableVertexAttribArray program.attributes.normal | |
_gl.vertexAttribPointer program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 | |
_gl.drawArrays _gl.TRIANGLES, 0, object.count | |
object.count = 0 | |
setObjectFaces = (object) -> | |
if _oldDoubleSided isnt object.doubleSided | |
if object.doubleSided then _gl.disable _gl.CULL_FACE else _gl.enable _gl.CULL_FACE | |
_oldDoubleSided = object.doubleSided | |
if _oldFlipSided isnt object.flipSided | |
if object.flipSided then _gl.frontFace _gl.CW else _gl.frontFace _gl.CCW | |
_oldFlipSided = object.flipSided | |
setDepthTest = (test) -> | |
if _oldDepth isnt test | |
if test then _gl.enable _gl.DEPTH_TEST else _gl.disable _gl.DEPTH_TEST | |
_oldDepth = test | |
computeFrustum = (m) -> | |
_frustum[0].set m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 | |
_frustum[1].set m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 | |
_frustum[2].set m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 | |
_frustum[3].set m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 | |
_frustum[4].set m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 | |
_frustum[5].set m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 | |
for i in [0...6] | |
plane = _frustum[i] | |
plane.divideScalar Math.sqrt(plane.x * plane.x + plane.y * plane.y + plane.z * plane.z) | |
isInFrustum = (object) -> | |
distance = null | |
matrix = object.matrixWorld | |
radius = -(object.geometry.boundingSphere.radius * Math.max(object.scale.x, Math.max(object.scale.y, object.scale.z))) | |
for i in [0...6] | |
distance = _frustum[i].x * matrix.n14 + _frustum[i].y * matrix.n24 + _frustum[i].z * matrix.n34 + _frustum[i].w | |
if distance <= radius then return false | |
return true | |
addToFixedArray = (where, what) -> | |
where.list[where.count] = what | |
where.count += 1 | |
unrollImmediateBufferMaterials = (globject) -> | |
object = globject.object | |
opaque = globject.opaque | |
transparent = globject.transparent | |
transparent.count = 0 | |
opaque.count = 0 | |
for material in object.materials | |
if (material.opacity and material.opacity < 1.0) or material.blending isnt THREE.NormalBlending | |
addToFixedArray transparent, material | |
else | |
addToFixedArray opaque, material | |
unrollBufferMaterials = (globject) -> | |
object = globject.object | |
buffer = globject.buffer | |
opaque = globject.opaque | |
transparent = globject.transparent | |
transparent.count = 0 | |
opaque.count = 0 | |
for meshMaterial in object.materials | |
if meshMaterial instanceof THREE.MeshFaceMaterial | |
for material in buffer.materials | |
if material | |
if (material.opacity and material.opacity < 1.0) or material.blending isnt THREE.NormalBlending | |
addToFixedArray transparent, material | |
else | |
addToFixedArray opaque, material | |
else | |
material = meshMaterial | |
if (material.opacity && material.opacity < 1.0) or material.blending isnt THREE.NormalBlending | |
addToFixedArray transparent, material | |
else | |
addToFixedArray opaque, material | |
painterSort = (a, b) -> b.z - a.z | |
@render = (scene, camera, renderTarget, forceClear) -> | |
i = program = opaque = transparent = material = o = ol = oil = webglObject = object = buffer = null | |
lights = scene.lights | |
fog = scene.fog | |
if camera.matrixAutoUpdate then camera.updateMatrix() | |
scene.update undefined, false, camera | |
camera.matrixWorldInverse.flattenToArray _viewMatrixArray | |
camera.projectionMatrix.flattenToArray _projectionMatrixArray | |
_projScreenMatrix.multiply camera.projectionMatrix, camera.matrixWorldInverse | |
computeFrustum _projScreenMatrix | |
this.initWebGLObjects scene | |
setRenderTarget renderTarget | |
if @autoClear or forceClear then @clear() | |
# set matrices | |
ol = scene.__webglObjects.length | |
for webglObject in scene.__webglObjects | |
object = webglObject.object | |
if object.visible | |
if !(object instanceof THREE.Mesh) or isInFrustum(object) | |
object.matrixWorld.flattenToArray object._objectMatrixArray | |
setupMatrices object, camera | |
unrollBufferMaterials webglObject | |
webglObject.render = true | |
if @sortObjects | |
_vector3.copy object.position | |
_projScreenMatrix.multiplyVector3 _vector3 | |
webglObject.z = _vector3.z | |
else | |
webglObject.render = false | |
else | |
webglObject.render = false | |
if @sortObjects | |
scene.__webglObjects.sort painterSort | |
oil = scene.__webglObjectsImmediate.length | |
for webglObject in scene.__webglObjectsImmediate | |
object = webglObject.object | |
if object.visible | |
if object.matrixAutoUpdate then object.matrixWorld.flattenToArray object._objectMatrixArray | |
setupMatrices object, camera | |
unrollImmediateBufferMaterials webglObject | |
# opaque pass | |
setBlending THREE.NormalBlending | |
for webglObject in scene.__webglObjects | |
if webglObject.render | |
object = webglObject.object | |
buffer = webglObject.buffer | |
opaque = webglObject.opaque | |
setObjectFaces object | |
for material in opaque.list | |
setDepthTest material.depthTest | |
renderBuffer camera, lights, fog, material, buffer, object | |
# opaque pass (immediate simulator) | |
for webglObject in scene.__webglObjectsImmediate | |
object = webglObject.object | |
if object.visible | |
opaque = webglObject.opaque | |
setObjectFaces object | |
for material in opaque.list | |
setDepthTest material.depthTest | |
program = setProgram camera, lights, fog, material, object | |
object.render (object) -> renderBufferImmediate object, program | |
# transparent pass | |
for webglObject in scene.__webglObjects | |
if webglObject.render | |
object = webglObject.object | |
buffer = webglObject.buffer | |
transparent = webglObject.transparent | |
setObjectFaces object | |
for material in transparent.list | |
setBlending material.blending | |
setDepthTest material.depthTest | |
renderBuffer camera, lights, fog, material, buffer, object | |
# transparent pass (immediate simulator) | |
for webglObject in scene.__webglObjectsImmediate | |
object = webglObject.object | |
if object.visible | |
transparent = webglObject.transparent | |
setObjectFaces object | |
for material in transparent.list | |
setBlending material.blending | |
setDepthTest material.depthTest | |
program = setProgram camera, lights, fog, material, object | |
object.render (object) -> renderBufferImmediate object, program | |
# Generate mipmap if we're using any kind of mipmap filtering | |
if renderTarget and renderTarget.minFilter isnt THREE.NearestFilter and renderTarget.minFilter isnt THREE.LinearFilter | |
updateRenderTargetMipmap renderTarget | |
setupMatrices = (object, camera) -> | |
object._modelViewMatrix.multiplyToArray camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray | |
THREE.Matrix4.makeInvert3x3(object._modelViewMatrix).transposeIntoArray object._normalMatrixArray | |
@initWebGLObjects = (scene) -> | |
if not scene.__webglObjects | |
scene.__webglObjects = new Array | |
scene.__webglObjectsImmediate = new Array | |
while scene.__objectsAdded.length | |
addObject scene.__objectsAdded[0], scene | |
scene.__objectsAdded.splice 0, 1 | |
while scene.__objectsRemoved.length | |
removeObject scene.__objectsRemoved[0], scene | |
scene.__objectsRemoved.splice 0, 1 | |
# update must be called after objects adding / removal | |
for webglObject in scene.__webglObjects | |
updateObject webglObject.object, scene | |
addObject = (object, scene) -> | |
g = geometry = geometryGroup = null | |
if object._modelViewMatrix == undefined | |
object._modelViewMatrix = new THREE.Matrix4 | |
object._normalMatrixArray = new Float32Array 9 | |
object._modelViewMatrixArray = new Float32Array 16 | |
object._objectMatrixArray = new Float32Array 16 | |
object.matrixWorld.flattenToArray object._objectMatrixArray | |
if object instanceof THREE.Mesh | |
geometry = object.geometry | |
if geometry.geometryGroups == undefined then sortFacesByMaterial geometry | |
# create separate VBOs per geometry chunk | |
for key, geometryGroup of geometry.geometryGroups | |
# initialise VBO on the first access | |
if not geometryGroup.__webGLVertexBuffer | |
createMeshBuffers geometryGroup | |
initMeshBuffers geometryGroup, object | |
geometry.__dirtyVertices = true | |
geometry.__dirtyMorphTargets = true | |
geometry.__dirtyElements = true | |
geometry.__dirtyUvs = true | |
geometry.__dirtyNormals = true | |
geometry.__dirtyTangents = true | |
geometry.__dirtyColors = true | |
# create separate wrapper per each use of VBO | |
addBuffer scene.__webglObjects, geometryGroup, object | |
else if object instanceof THREE.Ribbon | |
geometry = object.geometry | |
if not geometry.__webGLVertexBuffer | |
createRibbonBuffers geometry | |
initRibbonBuffers geometry | |
geometry.__dirtyVertices = true | |
geometry.__dirtyColors = true | |
addBuffer scene.__webglObjects, geometry, object | |
else if object instanceof THREE.Line | |
geometry = object.geometry | |
if geometry.__webGLVertexBuffer | |
createLineBuffers geometry | |
initLineBuffers geometry | |
geometry.__dirtyVertices = true | |
geometry.__dirtyColors = true | |
addBuffer scene.__webglObjects, geometry, object | |
else if object instanceof THREE.ParticleSystem | |
geometry = object.geometry | |
if not geometry.__webGLVertexBuffer | |
createParticleBuffers geometry | |
initParticleBuffers geometry | |
geometry.__dirtyVertices = true | |
geometry.__dirtyColors = true | |
addBuffer scene.__webglObjects, geometry, object | |
else if THREE.MarchingCubes? and object instanceof THREE.MarchingCubes | |
addBufferImmediate scene.__webglObjectsImmediate, object | |
updateObject = (object, scene) -> | |
if object instanceof THREE.Mesh | |
geometry = object.geometry | |
# check all geometry groups | |
for key, geometryGroup of geometry.geometryGroups | |
if geometry.__dirtyVertices || geometry.__dirtyMorphTargets || geometry.__dirtyElements || geometry.__dirtyUvs || geometry.__dirtyNormals || geometry.__dirtyColors || geometry.__dirtyTangents | |
setMeshBuffers geometryGroup, object, _gl.DYNAMIC_DRAW | |
geometry.__dirtyVertices = false | |
geometry.__dirtyMorphTargets = false | |
geometry.__dirtyElements = false | |
geometry.__dirtyUvs = false | |
geometry.__dirtyNormals = false | |
geometry.__dirtyTangents = false | |
geometry.__dirtyColors = false | |
else if object instanceof THREE.Ribbon | |
geometry = object.geometry | |
if geometry.__dirtyVertices || geometry.__dirtyColors | |
setRibbonBuffers geometry, _gl.DYNAMIC_DRAW | |
geometry.__dirtyVertices = false | |
geometry.__dirtyColors = false | |
else if object instanceof THREE.Line | |
geometry = object.geometry | |
if geometry.__dirtyVertices || geometry.__dirtyColors | |
setLineBuffers geometry, _gl.DYNAMIC_DRAW | |
geometry.__dirtyVertices = false | |
geometry.__dirtyColors = false | |
else if object instanceof THREE.ParticleSystem | |
geometry = object.geometry | |
if geometry.__dirtyVertices || geometry.__dirtyColors || object.sortParticles | |
setParticleBuffers geometry, _gl.DYNAMIC_DRAW, object | |
geometry.__dirtyVertices = false | |
geometry.__dirtyColors = false | |
removeObject = (object, scene) -> | |
for o in [0...scene.__webglObjects.length] | |
zobject = scene.__webglObjects[o].object | |
if object is zobject then scene.__webglObjects.splice o, 1 | |
sortFacesByMaterial = (geometry) -> | |
# TODO | |
# Should optimize by grouping faces with ColorFill / ColorStroke materials | |
# which could then use vertex color attributes instead of each being | |
# in its separate VBO | |
i = l = f = fl = face = material = materials = vertices = mhash = ghash = null | |
hash_map = {} | |
numMorphTargets = if geometry.morphTargets isnt undefined then geometry.morphTargets.length else 0 | |
geometry.geometryGroups = new Object | |
materialHash = (material) -> | |
hash_array = new Array | |
for m in material | |
if m is undefined | |
hash_array.push "undefined" | |
else | |
hash_array.push m.id | |
return hash_array.join '_' | |
for f in [0...geometry.faces.length] | |
face = geometry.faces[f] | |
materials = face.materials | |
mhash = materialHash materials | |
if hash_map[mhash] is undefined then hash_map[mhash] = hash: mhash, counter: 0 | |
ghash = "#{hash_map[mhash].hash}_#{hash_map[mhash].counter}" | |
if geometry.geometryGroups[ghash] is undefined | |
geometry.geometryGroups[ghash] = faces: new Array, materials: materials, vertices: 0, numMorphTargets: numMorphTargets | |
vertices = if face instanceof THREE.Face3 then 3 else 4 | |
if (geometry.geometryGroups[ghash].vertices + vertices) > 65535 | |
hash_map[mhash].counter += 1 | |
ghash = "#{hash_map[mhash].hash}_#{hash_map[mhash].counter}" | |
if geometry.geometryGroups[ghash] is undefined | |
geometry.geometryGroups[ghash] = faces: new Array, materials: materials, vertices: 0, numMorphTargets: numMorphTargets | |
geometry.geometryGroups[ghash].faces.push f | |
geometry.geometryGroups[ghash].vertices += vertices | |
addBuffer = (objlist, buffer, object) -> | |
objlist.push | |
buffer: buffer | |
object: object | |
opaque: {list: new Array, count: 0} | |
transparent: {list: new Array, count: 0} | |
addBufferImmediate = (objlist, object) -> | |
objlist.push | |
object: object | |
opaque: {list: new Array, count: 0} | |
transparent: {list: new Array, count: 0} | |
@setFaceCulling = (cullFace, frontFace) -> | |
if cullFace | |
if !frontFace or frontFace is 'ccw' then _gl.frontFace _gl.CCW else _gl.frontFace _gl.CW | |
if cullFace is 'back' then _gl.cullFace _gl.BACK | |
else if cullFace is 'front' then _gl.cullFace _gl.FRONT | |
else _gl.cullFace _gl.FRONT_AND_BACK | |
_gl.enable _gl.CULL_FACE | |
else _gl.disable _gl.CULL_FACE | |
maxVertexTextures = -> _gl.getParameter _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS | |
@supportsVertexTextures = -> maxVertexTextures() > 0 | |
buildProgram = (fragmentShader, vertexShader, parameters) -> | |
program = _gl.createProgram() | |
prefix_fragment = """ | |
#ifdef GL_ES | |
precision highp float; | |
#endif | |
#define MAX_DIR_LIGHTS #{parameters.maxDirLights} | |
#define MAX_POINT_LIGHTS #{parameters.maxPointLights} | |
#{if parameters.fog then '#define USE_FOG' else ''} | |
#{if parameters.fog instanceof THREE.FogExp2 then '#define FOG_EXP2' else ''} | |
#{if parameters.map then '#define USE_MAP'else ''} | |
#{if parameters.envMap then '#define USE_ENVMAP' else ''} | |
#{if parameters.lightMap then '#define USE_LIGHTMAP' else ''} | |
#{if parameters.vertexColors then '#define USE_COLOR' else ''} | |
uniform mat4 viewMatrix; | |
uniform vec3 cameraPosition; | |
""" | |
prefix_vertex = """ | |
#{if maxVertexTextures() > 0 then '#define VERTEX_TEXTURES' else ''} | |
#define MAX_DIR_LIGHTS #{parameters.maxDirLights} | |
#define MAX_POINT_LIGHTS #{parameters.maxPointLights} | |
#define MAX_BONES #{parameters.maxBones} | |
#{if parameters.map then '#define USE_MAP' else ''} | |
#{if parameters.envMap then '#define USE_ENVMAP' else ''} | |
#{if parameters.lightMap then '#define USE_LIGHTMAP' else ''} | |
#{if parameters.vertexColors then '#define USE_COLOR' else ''} | |
#{if parameters.skinning then '#define USE_SKINNING' else ''} | |
#{if parameters.morphTargets then '#define USE_MORPHTARGETS' else ''} | |
#{if parameters.sizeAttenuation then '#define USE_SIZEATTENUATION' else ''} | |
uniform mat4 objectMatrix; | |
uniform mat4 modelViewMatrix; | |
uniform mat4 projectionMatrix; | |
uniform mat4 viewMatrix; | |
uniform mat3 normalMatrix; | |
uniform vec3 cameraPosition; | |
uniform mat4 cameraInverseMatrix; | |
attribute vec3 position; | |
attribute vec3 morphTarget0; | |
attribute vec3 morphTarget1; | |
attribute vec3 morphTarget2; | |
attribute vec3 morphTarget3; | |
attribute vec3 morphTarget4; | |
attribute vec3 morphTarget5; | |
attribute vec3 morphTarget6; | |
attribute vec3 morphTarget7; | |
attribute vec3 normal; | |
attribute vec3 color; | |
attribute vec2 uv; | |
attribute vec2 uv2; | |
attribute vec4 skinVertexA; | |
attribute vec4 skinVertexB; | |
attribute vec4 skinIndex; | |
attribute vec4 skinWeight; | |
""" | |
_gl.attachShader program, getShader("fragment", prefix_fragment + fragmentShader) | |
_gl.attachShader program, getShader("vertex", prefix_vertex + vertexShader) | |
_gl.linkProgram program | |
if not _gl.getProgramParameter(program, _gl.LINK_STATUS) | |
alert """ | |
Could not initialise shaders | |
VALIDATE_STATUS: #{_gl.getProgramParameter(program, _gl.VALIDATE_STATUS)} | |
ERROR: #{_gl.getError()} | |
""" | |
program.uniforms = new Object | |
program.attributes = new Object | |
return program | |
loadUniformsSkinning = (uniforms, object) -> | |
_gl.uniformMatrix4fv uniforms.cameraInverseMatrix, false, _viewMatrixArray | |
_gl.uniformMatrix4fv uniforms.boneGlobalMatrices, false, object.boneMatrices | |
loadUniformsMatrices = (uniforms, object) -> | |
_gl.uniformMatrix4fv uniforms.modelViewMatrix, false, object._modelViewMatrixArray | |
_gl.uniformMatrix3fv uniforms.normalMatrix, false, object._normalMatrixArray | |
loadUniformsGeneric = (program, uniforms) -> | |
u = uniform = value = type = location = texture = null | |
for u, uniform of uniforms | |
location = program.uniforms[u] | |
if not location then continue | |
type = uniform.type | |
value = uniform.value | |
switch type | |
when 'i' then _gl.uniform1i location, value | |
when 'f' then _gl.uniform1f location, value | |
when 'fv1' then _gl.uniform1fv location, value | |
when 'fv' then _gl.uniform3fv location, value | |
when 'v2' then _gl.uniform2f location, value.x, value.y | |
when 'v3' then _gl.uniform3f location, value.x, value.y, value.z | |
when 'c' then _gl.uniform3f location, value.r, value.g, value.b | |
when 't' then _gl.uniform1i location, value | |
texture = uniform.texture | |
if not texture then continue | |
if texture.image instanceof Array and texture.image.length is 6 | |
setCubeTexture texture, value | |
else | |
setTexture texture, value | |
setBlending = (blending) -> | |
if blending isnt _oldBlending | |
switch blending | |
when THREE.AdditiveBlending | |
_gl.blendEquation _gl.FUNC_ADD | |
_gl.blendFunc _gl.ONE, _gl.ONE | |
when THREE.SubtractiveBlending | |
# _gl.blendEquation _gl.FUNC_SUBTRACT | |
_gl.blendFunc _gl.DST_COLOR, _gl.ZERO | |
when THREE.BillboardBlending | |
_gl.blendEquation _gl.FUNC_ADD | |
_gl.blendFunc _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA | |
when THREE.ReverseSubtractiveBlending | |
_gl.blendEquation _gl.FUNC_REVERSE_SUBTRACT | |
_gl.blendFunc _gl.ONE, _gl.ONE | |
else | |
_gl.blendEquation _gl.FUNC_ADD | |
_gl.blendFunc _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA | |
_oldBlending = blending | |
setTextureParameters = (textureType, texture, image) -> | |
if isPowerOfTwo(image.width) and isPowerOfTwo(image.height) | |
_gl.texParameteri textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL(texture.wrapS) | |
_gl.texParameteri textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL(texture.wrapT) | |
_gl.texParameteri textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL(texture.magFilter) | |
_gl.texParameteri textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL(texture.minFilter) | |
_gl.generateMipmap textureType | |
else | |
_gl.texParameteri textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE | |
_gl.texParameteri textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE | |
_gl.texParameteri textureType, _gl.TEXTURE_MAG_FILTER, filterFallback(texture.magFilter) | |
_gl.texParameteri textureType, _gl.TEXTURE_MIN_FILTER, filterFallback(texture.minFilter) | |
setTexture = (texture, slot) -> | |
if texture.needsUpdate | |
if not texture.__wasSetOnce | |
texture.__webGLTexture = _gl.createTexture() | |
_gl.bindTexture _gl.TEXTURE_2D, texture.__webGLTexture | |
_gl.texImage2D _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image | |
texture.__wasSetOnce = true | |
else | |
_gl.bindTexture _gl.TEXTURE_2D, texture.__webGLTexture | |
_gl.texSubImage2D _gl.TEXTURE_2D, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image | |
setTextureParameters _gl.TEXTURE_2D, texture, texture.image | |
_gl.bindTexture _gl.TEXTURE_2D, null | |
texture.needsUpdate = false | |
_gl.activeTexture _gl.TEXTURE0 + slot | |
_gl.bindTexture _gl.TEXTURE_2D, texture.__webGLTexture | |
setCubeTexture = (texture, slot) -> | |
if texture.image.length is 6 | |
if texture.needsUpdate | |
if not texture.__wasSetOnce | |
texture.image.__webGLTextureCube = _gl.createTexture() | |
_gl.bindTexture _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube | |
for i in [0...6] | |
_gl.texImage2D _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[i] | |
texture.__wasSetOnce = true | |
else | |
_gl.bindTexture _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube | |
for i in [0...6] | |
_gl.texSubImage2D _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[i] | |
setTextureParameters _gl.TEXTURE_CUBE_MAP, texture, texture.image[0] | |
_gl.bindTexture _gl.TEXTURE_CUBE_MAP, null | |
texture.needsUpdate = false | |
_gl.activeTexture _gl.TEXTURE0 + slot | |
_gl.bindTexture _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube | |
setRenderTarget = (renderTexture) -> | |
if renderTexture and !renderTexture.__webGLFramebuffer | |
renderTexture.__webGLFramebuffer = _gl.createFramebuffer() | |
renderTexture.__webGLRenderbuffer = _gl.createRenderbuffer() | |
renderTexture.__webGLTexture = _gl.createTexture() | |
# Setup renderbuffer | |
_gl.bindRenderbuffer _gl.RENDERBUFFER, renderTexture.__webGLRenderbuffer | |
_gl.renderbufferStorage _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTexture.width, renderTexture.height | |
# Setup texture | |
_gl.bindTexture _gl.TEXTURE_2D, renderTexture.__webGLTexture | |
_gl.texParameteri _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL(renderTexture.wrapS) | |
_gl.texParameteri _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL(renderTexture.wrapT) | |
_gl.texParameteri _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, paramThreeToGL(renderTexture.magFilter) | |
_gl.texParameteri _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, paramThreeToGL(renderTexture.minFilter) | |
_gl.texImage2D _gl.TEXTURE_2D, 0, paramThreeToGL(renderTexture.format), renderTexture.width, renderTexture.height, 0, paramThreeToGL(renderTexture.format), paramThreeToGL(renderTexture.type), null | |
# Setup framebuffer | |
_gl.bindFramebuffer _gl.FRAMEBUFFER, renderTexture.__webGLFramebuffer | |
_gl.framebufferTexture2D _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, renderTexture.__webGLTexture, 0 | |
_gl.framebufferRenderbuffer _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTexture.__webGLRenderbuffer | |
# Release everything | |
_gl.bindTexture _gl.TEXTURE_2D, null | |
_gl.bindRenderbuffer _gl.RENDERBUFFER, null | |
_gl.bindFramebuffer _gl.FRAMEBUFFER, null | |
framebuffer = width = height = null | |
if renderTexture | |
framebuffer = renderTexture.__webGLFramebuffer | |
width = renderTexture.width | |
height = renderTexture.height | |
else | |
framebuffer = null | |
width = _viewportWidth | |
height = _viewportHeight | |
if framebuffer isnt _oldFramebuffer | |
_gl.bindFramebuffer _gl.FRAMEBUFFER, framebuffer | |
_gl.viewport _viewportX, _viewportY, width, height | |
_oldFramebuffer = framebuffer | |
updateRenderTargetMipmap = (renderTarget) -> | |
_gl.bindTexture _gl.TEXTURE_2D, renderTarget.__webGLTexture | |
_gl.generateMipmap _gl.TEXTURE_2D | |
_gl.bindTexture _gl.TEXTURE_2D, null | |
cacheUniformLocations = (program, identifiers) -> | |
i = l = id = null | |
for i in [0...identifiers.length] | |
id = identifiers[i] | |
program.uniforms[id] = _gl.getUniformLocation program, id | |
cacheAttributeLocations = (program, identifiers) -> | |
i = l = id = null | |
for i in [0...identifiers.length] | |
id = identifiers[i] | |
program.attributes[id] = _gl.getAttribLocation program, id | |
getShader = (type, string) -> | |
shader = null | |
switch type | |
when 'fragment' | |
shader = _gl.createShader _gl.FRAGMENT_SHADER | |
when 'vertex' | |
shader = _gl.createShader _gl.VERTEX_SHADER | |
_gl.shaderSource shader, string | |
_gl.compileShader shader | |
if !_gl.getShaderParameter(shader, _gl.COMPILE_STATUS) | |
alert _gl.getShaderInfoLog(shader) | |
return null | |
return shader | |
# fallback filters for non-power-of-2 textures | |
filterFallback = (f) -> | |
switch f | |
when THREE.NearestFilter, THREE.NearestMipMapNearestFilter, THREE.NearestMipMapLinearFilter | |
return _gl.NEAREST | |
when THREE.LinearFilter, THREE.LinearMipMapNearestFilter, THREE.LinearMipMapLinearFilter | |
return _gl.LINEAR | |
paramThreeToGL = (p) -> | |
switch p | |
when THREE.RepeatWrapping then return _gl.REPEAT | |
when THREE.ClampToEdgeWrapping then return _gl.CLAMP_TO_EDGE | |
when THREE.MirroredRepeatWrapping then return _gl.MIRRORED_REPEAT | |
when THREE.NearestFilter then return _gl.NEAREST | |
when THREE.NearestMipMapNearestFilter then return _gl.NEAREST_MIPMAP_NEAREST | |
when THREE.NearestMipMapLinearFilter then return _gl.NEAREST_MIPMAP_LINEAR | |
when THREE.LinearFilter then return _gl.LINEAR | |
when THREE.LinearMipMapNearestFilter then return _gl.LINEAR_MIPMAP_NEAREST | |
when THREE.LinearMipMapLinearFilter then return _gl.LINEAR_MIPMAP_LINEAR | |
when THREE.ByteType then return _gl.BYTE | |
when THREE.UnsignedByteType then return _gl.UNSIGNED_BYTE | |
when THREE.ShortType then return _gl.SHORT | |
when THREE.UnsignedShortType then return _gl.UNSIGNED_SHORT | |
when THREE.IntType then return _gl.INT | |
when THREE.UnsignedShortType then return _gl.UNSIGNED_INT | |
when THREE.FloatType then return _gl.FLOAT | |
when THREE.AlphaFormat then return _gl.ALPHA | |
when THREE.RGBFormat then return _gl.RGB | |
when THREE.RGBAFormat then return _gl.RGBA | |
when THREE.LuminanceFormat then return _gl.LUMINANCE | |
when THREE.LuminanceAlphaFormat then return _gl.LUMINANCE_ALPHA | |
return 0 | |
isPowerOfTwo = (value) -> (value & (value - 1)) is 0 | |
materialNeedsSmoothNormals = (material) -> material and material.shading isnt undefined and material.shading is THREE.SmoothShading | |
bufferNeedsSmoothNormals = (geometryGroup, object) -> | |
m = ml = i = l = meshMaterial = null | |
needsSmoothNormals = false | |
for m in [0...object.materials.length] | |
meshMaterial = object.materials[m] | |
if meshMaterial instanceof THREE.MeshFaceMaterial | |
for i in [0...geometryGroup.materials.length] | |
if materialNeedsSmoothNormals geometryGroup.materials[i] | |
needsSmoothNormals = true | |
else | |
if materialNeedsSmoothNormals meshMaterial | |
needsSmoothNormals = true | |
break | |
if needsSmoothNormals then break | |
return needsSmoothNormals | |
allocateBones = (object) -> | |
# default for when object is not specified | |
# ( for example when prebuilding shader | |
# to be used with multiple objects ) | |
# | |
# - leave some extra space for other uniforms | |
# - limit here is ANGLE's 254 max uniform vectors | |
# (up to 54 should be safe) | |
maxBones = 50 | |
if object isnt undefined and object instanceof THREE.SkinnedMesh | |
maxBones = object.bones.length | |
return maxBones | |
allocateLights = (lights, maxLights) -> | |
l = ll = light = dirLights = pointLights = maxDirLights = maxPointLights = null | |
dirLights = pointLights = maxDirLights = maxPointLights = 0 | |
for l in [0...lights.length] | |
light = lights[l] | |
if light instanceof THREE.DirectionalLight then dirLights++ | |
if light instanceof THREE.PointLight then pointLights++ | |
if (pointLights + dirLights) <= maxLights | |
maxDirLights = dirLights | |
maxPointLights = pointLights | |
else | |
maxDirLights = Math.ceil(maxLights * dirLights / (pointLights + dirLights)) | |
maxPointLights = maxLights - maxDirLights | |
return directional: maxDirLights, point: maxPointLights | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment