Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Ablesons
three.js
提交
1efe37f9
T
three.js
项目概览
Ablesons
/
three.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
three.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
1efe37f9
编写于
1月 09, 2013
作者:
M
Mr.doob
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'gero3/dev' into dev
上级
cc64999a
b17b3418
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
7742 addition
and
1 deletion
+7742
-1
src/renderers/WebGLRenderer2.js
src/renderers/WebGLRenderer2.js
+3298
-0
src/renderers/webgl/LowLevelRenderer.js
src/renderers/webgl/LowLevelRenderer.js
+1526
-0
src/renderers/webgl/ShaderBuilder.js
src/renderers/webgl/ShaderBuilder.js
+406
-0
src/renderers/webgl/objects/LineRenderer.js
src/renderers/webgl/objects/LineRenderer.js
+200
-0
src/renderers/webgl/objects/MeshRenderer.js
src/renderers/webgl/objects/MeshRenderer.js
+1616
-0
src/renderers/webgl/objects/Object3DRenderer.js
src/renderers/webgl/objects/Object3DRenderer.js
+124
-0
src/renderers/webgl/objects/ParticleRenderer.js
src/renderers/webgl/objects/ParticleRenderer.js
+358
-0
src/renderers/webgl/objects/RibbonRenderer.js
src/renderers/webgl/objects/RibbonRenderer.js
+205
-0
utils/includes/common.json
utils/includes/common.json
+9
-1
未找到文件。
src/renderers/WebGLRenderer2.js
0 → 100644
浏览文件 @
1efe37f9
/**
* @author supereggbert / http://www.paulbrunt.co.uk/
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
* @author szimek / https://github.com/szimek/
* @author gero3 / https://github.com/gero3/
*/
THREE
.
WebGLRenderer2
=
function
(
parameters
)
{
console
.
log
(
'
THREE.WebGLRenderer
'
,
THREE
.
REVISION
);
parameters
=
parameters
||
{};
var
info
=
{
memory
:
{
programs
:
0
,
geometries
:
0
,
textures
:
0
},
render
:
{
calls
:
0
,
vertices
:
0
,
faces
:
0
,
points
:
0
}
};
var
renderer
=
new
THREE
.
WebGLRenderer2
.
LowLevelRenderer
(
parameters
);
var
meshRenderer
=
new
THREE
.
WebGLRenderer2
.
MeshRenderer
(
renderer
,
info
);
var
particleRenderer
=
new
THREE
.
WebGLRenderer2
.
ParticleRenderer
(
renderer
,
info
);
var
lineRenderer
=
new
THREE
.
WebGLRenderer2
.
LineRenderer
(
renderer
,
info
);
var
ribbonRenderer
=
new
THREE
.
WebGLRenderer2
.
RibbonRenderer
(
renderer
,
info
);
var
shaderBuilder
=
new
THREE
.
WebGLRenderer2
.
ShaderBuilder
(
renderer
,
info
);
// clearing
this
.
autoClear
=
true
;
this
.
autoClearColor
=
true
;
this
.
autoClearDepth
=
true
;
this
.
autoClearStencil
=
true
;
// scene graph
this
.
sortObjects
=
true
;
this
.
autoUpdateObjects
=
true
;
this
.
autoUpdateScene
=
true
;
// physically based shading
this
.
gammaInput
=
false
;
this
.
gammaOutput
=
false
;
this
.
physicallyBasedShading
=
false
;
// shadow map
this
.
shadowMapEnabled
=
false
;
this
.
shadowMapAutoUpdate
=
true
;
this
.
shadowMapType
=
THREE
.
PCFShadowMap
;
this
.
shadowMapCullFace
=
THREE
.
CullFaceFront
;
this
.
shadowMapDebug
=
false
;
this
.
shadowMapCascade
=
false
;
// morphs
this
.
maxMorphTargets
=
8
;
this
.
maxMorphNormals
=
4
;
// flags
this
.
autoScaleCubemaps
=
true
;
// custom render plugins
this
.
renderPluginsPre
=
[];
this
.
renderPluginsPost
=
[];
// info
this
.
info
=
info
;
// internal properties
var
_this
=
this
,
// internal state cache
_currentProgram
=
null
,
_currentFramebuffer
=
null
,
_currentMaterialId
=
-
1
,
_currentGeometryGroupHash
=
null
,
_currentCamera
=
null
,
_geometryGroupCounter
=
0
,
_usedTextureUnits
=
0
,
// GL state
_viewportX
=
0
,
_viewportY
=
0
,
_viewportWidth
=
0
,
_viewportHeight
=
0
,
_currentWidth
=
0
,
_currentHeight
=
0
,
_enabledAttributes
=
{},
// frustum
_frustum
=
new
THREE
.
Frustum
(),
// camera matrices cache
_projScreenMatrix
=
new
THREE
.
Matrix4
(),
_projScreenMatrixPS
=
new
THREE
.
Matrix4
(),
_vector3
=
new
THREE
.
Vector3
(),
// light arrays cache
_direction
=
new
THREE
.
Vector3
(),
_lightsNeedUpdate
=
true
,
_lights
=
{
ambient
:
[
0
,
0
,
0
],
directional
:
{
length
:
0
,
colors
:
[],
positions
:
[]
},
point
:
{
length
:
0
,
colors
:
[],
positions
:
[],
distances
:
[]
},
spot
:
{
length
:
0
,
colors
:
[],
positions
:
[],
distances
:
[],
directions
:
[],
anglesCos
:
[],
exponents
:
[]
},
hemi
:
{
length
:
0
,
skyColors
:
[],
groundColors
:
[],
positions
:
[]
}
};
// initialize
this
.
context
=
renderer
.
getContext
();
this
.
domElement
=
renderer
.
getDomElement
();
this
.
getPrecision
=
renderer
.
getPrecision
;
// low level API
this
.
getPrecision
=
renderer
.
getPrecision
;
this
.
getContext
=
renderer
.
getContext
;
this
.
supportsVertexTextures
=
renderer
.
supportsVertexTextures
;
this
.
getMaxAnisotropy
=
renderer
.
getMaxAnisotropy
;
this
.
setSize
=
renderer
.
setSize
;
this
.
setViewport
=
renderer
.
setViewport
;
this
.
setScissor
=
renderer
.
setScissor
;
this
.
enableScissorTest
=
renderer
.
enableScissorTest
;
this
.
setDepthTest
=
renderer
.
setDepthTest
;
this
.
setRenderTarget
=
renderer
.
setRenderTarget
;
// Clearing
this
.
setClearColorHex
=
renderer
.
setClearColorHex
;
this
.
setClearColor
=
renderer
.
setClearColor
;
this
.
getClearColor
=
renderer
.
getClearColor
;
this
.
getClearAlpha
=
renderer
.
getClearAlpha
;
this
.
clear
=
renderer
.
clear
;
this
.
clearTarget
=
renderer
.
clearTarget
;
// Plugins
this
.
addPostPlugin
=
function
(
plugin
)
{
plugin
.
init
(
this
);
this
.
renderPluginsPost
.
push
(
plugin
);
};
this
.
addPrePlugin
=
function
(
plugin
)
{
plugin
.
init
(
this
);
this
.
renderPluginsPre
.
push
(
plugin
);
};
// Rendering
this
.
updateShadowMap
=
function
(
scene
,
camera
)
{
_currentProgram
=
null
;
_currentGeometryGroupHash
=
-
1
;
_currentMaterialId
=
-
1
;
_lightsNeedUpdate
=
true
;
renderer
.
resetState
();
this
.
shadowMapPlugin
.
update
(
scene
,
camera
);
};
// Events
var
onGeometryDispose
=
function
(
event
)
{
var
geometry
=
event
.
target
;
geometry
.
removeEventListener
(
'
dispose
'
,
onGeometryDispose
);
deallocateGeometry
(
geometry
);
_this
.
info
.
memory
.
geometries
--
;
};
var
onTextureDispose
=
function
(
event
)
{
var
texture
=
event
.
target
;
texture
.
removeEventListener
(
'
dispose
'
,
onTextureDispose
);
deallocateTexture
(
texture
);
_this
.
info
.
memory
.
textures
--
;
};
var
onRenderTargetDispose
=
function
(
event
)
{
var
renderTarget
=
event
.
target
;
renderTarget
.
removeEventListener
(
'
dispose
'
,
onRenderTargetDispose
);
deallocateRenderTarget
(
renderTarget
);
_this
.
info
.
memory
.
textures
--
;
};
var
onMaterialDispose
=
function
(
event
)
{
var
material
=
event
.
target
;
material
.
removeEventListener
(
'
dispose
'
,
onMaterialDispose
);
deallocateMaterial
(
material
);
};
// Buffer deallocation
var
deallocateGeometry
=
function
(
geometry
)
{
var
m
,
ml
;
geometry
.
__webglInit
=
undefined
;
if
(
geometry
.
__webglVertexBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglVertexBuffer
);
if
(
geometry
.
__webglNormalBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglNormalBuffer
);
if
(
geometry
.
__webglTangentBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglTangentBuffer
);
if
(
geometry
.
__webglColorBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglColorBuffer
);
if
(
geometry
.
__webglUVBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglUVBuffer
);
if
(
geometry
.
__webglUV2Buffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglUV2Buffer
);
if
(
geometry
.
__webglSkinIndicesBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglSkinIndicesBuffer
);
if
(
geometry
.
__webglSkinWeightsBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglSkinWeightsBuffer
);
if
(
geometry
.
__webglFaceBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglFaceBuffer
);
if
(
geometry
.
__webglLineBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglLineBuffer
);
if
(
geometry
.
__webglLineDistanceBuffer
!==
undefined
)
renderer
.
deleteBuffer
(
geometry
.
__webglLineDistanceBuffer
);
// geometry groups
if
(
geometry
.
geometryGroups
!==
undefined
)
{
for
(
var
g
in
geometry
.
geometryGroups
)
{
var
geometryGroup
=
geometry
.
geometryGroups
[
g
];
if
(
geometryGroup
.
numMorphTargets
!==
undefined
)
{
for
(
m
=
0
,
ml
=
geometryGroup
.
numMorphTargets
;
m
<
ml
;
m
++
)
{
renderer
.
deleteBuffer
(
geometryGroup
.
__webglMorphTargetsBuffers
[
m
]
);
}
}
if
(
geometryGroup
.
numMorphNormals
!==
undefined
)
{
for
(
m
=
0
,
ml
=
geometryGroup
.
numMorphNormals
;
m
<
ml
;
m
++
)
{
renderer
.
deleteBuffer
(
geometryGroup
.
__webglMorphNormalsBuffers
[
m
]
);
}
}
deleteCustomAttributesBuffers
(
geometryGroup
);
}
}
deleteCustomAttributesBuffers
(
geometry
);
};
var
deallocateTexture
=
function
(
texture
)
{
if
(
texture
.
image
&&
texture
.
image
.
__webglTextureCube
)
{
// cube texture
renderer
.
deleteTexture
(
texture
.
image
.
__webglTextureCube
);
}
else
{
// 2D texture
if
(
!
texture
.
__webglInit
)
return
;
texture
.
__webglInit
=
false
;
renderer
.
deleteTexture
(
texture
.
__webglTexture
);
}
};
var
deallocateRenderTarget
=
function
(
renderTarget
)
{
if
(
!
renderTarget
||
!
renderTarget
.
__webglTexture
)
return
;
renderer
.
deleteTexture
(
renderTarget
.
__webglTexture
);
if
(
renderTarget
instanceof
THREE
.
WebGLRenderTargetCube
)
{
for
(
var
i
=
0
;
i
<
6
;
i
++
)
{
renderer
.
deleteFramebuffer
(
renderTarget
.
__webglFramebuffer
[
i
]
);
renderer
.
deleteRenderbuffer
(
renderTarget
.
__webglRenderbuffer
[
i
]
);
}
}
else
{
renderer
.
deleteFramebuffer
(
renderTarget
.
__webglFramebuffer
);
renderer
.
deleteRenderbuffer
(
renderTarget
.
__webglRenderbuffer
);
}
};
var
deallocateMaterial
=
function
(
material
)
{
var
program
=
material
.
program
;
if
(
program
===
undefined
)
return
;
material
.
program
=
undefined
;
// only deallocate GL program if this was the last use of shared program
// assumed there is only single copy of any program in the _programs list
// (that's how it's constructed)
shaderBuilder
.
removeProgram
(
program
)
};
function
deleteCustomAttributesBuffers
(
geometry
)
{
if
(
geometry
.
__webglCustomAttributesList
)
{
for
(
var
id
in
geometry
.
__webglCustomAttributesList
)
{
renderer
.
deleteBuffer
(
geometry
.
__webglCustomAttributesList
[
id
].
buffer
);
}
}
};
// Buffer initialization
function
initCustomAttributes
(
geometry
,
object
)
{
var
nvertices
=
geometry
.
vertices
.
length
;
var
material
=
object
.
material
;
if
(
material
.
attributes
)
{
if
(
geometry
.
__webglCustomAttributesList
===
undefined
)
{
geometry
.
__webglCustomAttributesList
=
[];
}
for
(
var
a
in
material
.
attributes
)
{
var
attribute
=
material
.
attributes
[
a
];
if
(
!
attribute
.
__webglInitialized
||
attribute
.
createUniqueBuffers
)
{
attribute
.
__webglInitialized
=
true
;
var
size
=
1
;
// "f" and "i"
if
(
attribute
.
type
===
"
v2
"
)
size
=
2
;
else
if
(
attribute
.
type
===
"
v3
"
)
size
=
3
;
else
if
(
attribute
.
type
===
"
v4
"
)
size
=
4
;
else
if
(
attribute
.
type
===
"
c
"
)
size
=
3
;
attribute
.
size
=
size
;
attribute
.
array
=
new
Float32Array
(
nvertices
*
size
);
attribute
.
buffer
=
renderer
.
createBuffer
();
attribute
.
buffer
.
belongsToAttribute
=
a
;
attribute
.
needsUpdate
=
true
;
}
geometry
.
__webglCustomAttributesList
.
push
(
attribute
);
}
}
};
function
getBufferMaterial
(
object
,
geometryGroup
)
{
return
object
.
material
instanceof
THREE
.
MeshFaceMaterial
?
object
.
material
.
materials
[
geometryGroup
.
materialIndex
]
:
object
.
material
;
};
//
function
initDirectBuffers
(
geometry
)
{
var
a
,
attribute
;
for
(
a
in
geometry
.
attributes
)
{
attribute
=
geometry
.
attributes
[
a
];
attribute
.
buffer
=
renderer
.
createBuffer
();
if
(
a
===
"
index
"
)
{
renderer
.
setStaticIndexBuffer
(
attribute
.
buffer
,
attribute
.
array
);
}
else
{
renderer
.
setStaticArrayBuffer
(
attribute
.
buffer
,
attribute
.
array
);
}
}
};
// Buffer setting
function
setDirectBuffers
(
geometry
,
dispose
)
{
var
attributes
=
geometry
.
attributes
;
var
index
=
attributes
[
"
index
"
];
var
position
=
attributes
[
"
position
"
];
var
normal
=
attributes
[
"
normal
"
];
var
uv
=
attributes
[
"
uv
"
];
var
color
=
attributes
[
"
color
"
];
var
tangent
=
attributes
[
"
tangent
"
];
if
(
geometry
.
elementsNeedUpdate
&&
index
!==
undefined
)
{
renderer
.
setDynamicIndexBuffer
(
index
.
buffer
,
index
.
array
);
}
if
(
geometry
.
verticesNeedUpdate
&&
position
!==
undefined
)
{
renderer
.
setDynamicArrayBuffer
(
position
.
buffer
,
position
.
array
);
}
if
(
geometry
.
normalsNeedUpdate
&&
normal
!==
undefined
)
{
renderer
.
setDynamicArrayBuffer
(
normal
.
buffer
,
normal
.
array
);
}
if
(
geometry
.
uvsNeedUpdate
&&
uv
!==
undefined
)
{
renderer
.
setDynamicArrayBuffer
(
uv
.
buffer
,
uv
.
array
);
}
if
(
geometry
.
colorsNeedUpdate
&&
color
!==
undefined
)
{
renderer
.
setDynamicArrayBuffer
(
color
.
buffer
,
color
.
array
);
}
if
(
geometry
.
tangentsNeedUpdate
&&
tangent
!==
undefined
)
{
renderer
.
setDynamicArrayBuffer
(
tangent
.
buffer
,
tangent
.
array
);
}
if
(
dispose
)
{
for
(
var
i
in
geometry
.
attributes
)
{
delete
geometry
.
attributes
[
i
].
array
;
}
}
};
// Buffer rendering
this
.
renderBufferImmediate
=
function
(
object
,
program
,
material
)
{
if
(
object
.
hasPositions
&&
!
object
.
__webglVertexBuffer
)
object
.
__webglVertexBuffer
=
renderer
.
createBuffer
();
if
(
object
.
hasNormals
&&
!
object
.
__webglNormalBuffer
)
object
.
__webglNormalBuffer
=
renderer
.
createBuffer
();
if
(
object
.
hasUvs
&&
!
object
.
__webglUvBuffer
)
object
.
__webglUvBuffer
=
renderer
.
createBuffer
();
if
(
object
.
hasColors
&&
!
object
.
__webglColorBuffer
)
object
.
__webglColorBuffer
=
renderer
.
createBuffer
();
if
(
object
.
hasPositions
)
{
renderer
.
setDynamicArrayBuffer
(
object
.
__webglVertexBuffer
,
object
.
positionArray
);
renderer
.
setFloatAttribute
(
program
.
attributes
.
position
,
object
.
__webglVertexBuffer
,
3
,
0
);
}
if
(
object
.
hasNormals
)
{
if
(
material
.
shading
===
THREE
.
FlatShading
)
{
var
nx
,
ny
,
nz
,
nax
,
nbx
,
ncx
,
nay
,
nby
,
ncy
,
naz
,
nbz
,
ncz
,
normalArray
,
i
,
il
=
object
.
count
*
3
;
for
(
i
=
0
;
i
<
il
;
i
+=
9
)
{
normalArray
=
object
.
normalArray
;
nax
=
normalArray
[
i
];
nay
=
normalArray
[
i
+
1
];
naz
=
normalArray
[
i
+
2
];
nbx
=
normalArray
[
i
+
3
];
nby
=
normalArray
[
i
+
4
];
nbz
=
normalArray
[
i
+
5
];
ncx
=
normalArray
[
i
+
6
];
ncy
=
normalArray
[
i
+
7
];
ncz
=
normalArray
[
i
+
8
];
nx
=
(
nax
+
nbx
+
ncx
)
/
3
;
ny
=
(
nay
+
nby
+
ncy
)
/
3
;
nz
=
(
naz
+
nbz
+
ncz
)
/
3
;
normalArray
[
i
]
=
nx
;
normalArray
[
i
+
1
]
=
ny
;
normalArray
[
i
+
2
]
=
nz
;
normalArray
[
i
+
3
]
=
nx
;
normalArray
[
i
+
4
]
=
ny
;
normalArray
[
i
+
5
]
=
nz
;
normalArray
[
i
+
6
]
=
nx
;
normalArray
[
i
+
7
]
=
ny
;
normalArray
[
i
+
8
]
=
nz
;
}
}
renderer
.
setDynamicArrayBuffer
(
object
.
__webglNormalBuffer
,
object
.
normalArray
);
renderer
.
setFloatAttribute
(
program
.
attributes
.
normal
,
object
.
__webglNormalBuffer
,
3
,
0
);
}
if
(
object
.
hasUvs
&&
material
.
map
)
{
renderer
.
setDynamicArrayBuffer
(
object
.
__webglUvBuffer
,
object
.
uvArray
);
renderer
.
setFloatAttribute
(
program
.
attributes
.
uv
,
object
.
__webglUvBuffer
,
2
,
0
);
}
if
(
object
.
hasColors
&&
material
.
vertexColors
!==
THREE
.
NoColors
)
{
renderer
.
setDynamicArrayBuffer
(
object
.
__webglColorBuffer
,
object
.
colorArray
);
renderer
.
setFloatAttribute
(
program
.
attributes
.
color
,
object
.
__webglColorBuffer
,
3
,
0
);
}
renderer
.
drawTriangles
(
object
.
count
);
object
.
count
=
0
;
};
this
.
renderBufferDirect
=
function
(
camera
,
lights
,
fog
,
material
,
geometry
,
object
)
{
if
(
material
.
visible
===
false
)
return
;
var
program
,
attributes
,
linewidth
,
primitives
,
a
,
attribute
;
program
=
setProgram
(
camera
,
lights
,
fog
,
material
,
object
);
attributes
=
program
.
attributes
;
var
updateBuffers
=
false
,
wireframeBit
=
material
.
wireframe
?
1
:
0
,
geometryHash
=
(
geometry
.
id
*
0xffffff
)
+
(
program
.
id
*
2
)
+
wireframeBit
;
if
(
geometryHash
!==
_currentGeometryGroupHash
)
{
_currentGeometryGroupHash
=
geometryHash
;
updateBuffers
=
true
;
}
if
(
updateBuffers
)
{
renderer
.
disableAttributes
();
}
// render mesh
if
(
object
instanceof
THREE
.
Mesh
)
{
var
index
=
geometry
.
attributes
[
"
index
"
];
// indexed triangles
if
(
index
)
{
var
offsets
=
geometry
.
offsets
;
// if there is more than 1 chunk
// must set attribute pointers to use new offsets for each chunk
// even if geometry and materials didn't change
if
(
offsets
.
length
>
1
)
updateBuffers
=
true
;
for
(
var
i
=
0
,
il
=
offsets
.
length
;
i
<
il
;
i
++
)
{
var
startIndex
=
offsets
[
i
].
index
;
if
(
updateBuffers
)
{
// vertices
var
position
=
geometry
.
attributes
[
"
position
"
];
var
positionSize
=
position
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
position
,
position
.
buffer
,
positionSize
,
startIndex
*
positionSize
*
4
);
// normals
var
normal
=
geometry
.
attributes
[
"
normal
"
];
if
(
attributes
.
normal
>=
0
&&
normal
)
{
var
normalSize
=
normal
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
normal
,
normal
.
buffer
,
normalSize
,
startIndex
*
normalSize
*
4
);
}
// uvs
var
uv
=
geometry
.
attributes
[
"
uv
"
];
if
(
attributes
.
uv
>=
0
&&
uv
)
{
var
uvSize
=
uv
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
uv
,
uv
.
buffer
,
uvSize
,
startIndex
*
uvSize
*
4
);
}
// colors
var
color
=
geometry
.
attributes
[
"
color
"
];
if
(
attributes
.
color
>=
0
&&
color
)
{
var
colorSize
=
color
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
color
,
color
.
buffer
,
colorSize
,
startIndex
*
colorSize
*
4
);
}
// tangents
var
tangent
=
geometry
.
attributes
[
"
tangent
"
];
if
(
attributes
.
tangent
>=
0
&&
tangent
)
{
var
tangentSize
=
tangent
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
tangent
,
tangent
.
buffer
,
tangentSize
,
startIndex
*
tangentSize
*
4
);
}
}
// render indexed triangles
renderer
.
drawTriangleElements
(
index
.
buffer
,
offsets
[
i
].
count
,
offsets
[
i
].
start
*
2
);
_this
.
info
.
render
.
calls
++
;
_this
.
info
.
render
.
vertices
+=
offsets
[
i
].
count
;
// not really true, here vertices can be shared
_this
.
info
.
render
.
faces
+=
offsets
[
i
].
count
/
3
;
}
// non-indexed triangles
}
else
{
if
(
updateBuffers
)
{
// vertices
var
position
=
geometry
.
attributes
[
"
position
"
];
var
positionSize
=
position
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
position
,
position
.
buffer
,
positionSize
,
0
);
// normals
var
normal
=
geometry
.
attributes
[
"
normal
"
];
if
(
attributes
.
normal
>=
0
&&
normal
)
{
var
normalSize
=
normal
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
normal
,
normal
.
buffer
,
normalSize
,
0
);
}
// uvs
var
uv
=
geometry
.
attributes
[
"
uv
"
];
if
(
attributes
.
uv
>=
0
&&
uv
)
{
var
uvSize
=
uv
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
uv
,
uv
.
buffer
,
uvSize
,
0
);
}
// colors
var
color
=
geometry
.
attributes
[
"
color
"
];
if
(
attributes
.
color
>=
0
&&
color
)
{
var
colorSize
=
color
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
color
,
color
.
buffer
,
colorSize
,
0
);
}
// tangents
var
tangent
=
geometry
.
attributes
[
"
tangent
"
];
if
(
attributes
.
tangent
>=
0
&&
tangent
)
{
var
tangentSize
=
tangent
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
tangent
,
tangent
.
buffer
,
tangentSize
,
0
);
}
}
// render non-indexed triangles
renderer
.
drawTriangles
(
position
.
numItems
/
3
)
_this
.
info
.
render
.
calls
++
;
_this
.
info
.
render
.
vertices
+=
position
.
numItems
/
3
;
_this
.
info
.
render
.
faces
+=
position
.
numItems
/
3
/
3
;
}
// render particles
}
else
if
(
object
instanceof
THREE
.
ParticleSystem
)
{
if
(
updateBuffers
)
{
// vertices
var
position
=
geometry
.
attributes
[
"
position
"
];
var
positionSize
=
position
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
position
,
position
.
buffer
,
positionSize
,
0
);
// colors
var
color
=
geometry
.
attributes
[
"
color
"
];
if
(
attributes
.
color
>=
0
&&
color
)
{
var
colorSize
=
color
.
itemSize
;
renderer
.
setFloatAttribute
(
attributes
.
color
,
color
.
buffer
,
colorSize
,
0
);
}
// render particles
renderer
.
drawPoints
(
position
.
numItems
/
3
);
_this
.
info
.
render
.
calls
++
;
_this
.
info
.
render
.
points
+=
position
.
numItems
/
3
;
}
}
};
this
.
renderBuffer
=
function
(
camera
,
lights
,
fog
,
material
,
geometryGroup
,
object
)
{
if
(
material
.
visible
===
false
)
return
;
var
program
,
attributes
,
linewidth
,
primitives
,
a
,
attribute
,
i
,
il
;
program
=
setProgram
(
camera
,
lights
,
fog
,
material
,
object
);
attributes
=
program
.
attributes
;
var
updateBuffers
=
false
,
wireframeBit
=
material
.
wireframe
?
1
:
0
,
geometryGroupHash
=
(
geometryGroup
.
id
*
0xffffff
)
+
(
program
.
id
*
2
)
+
wireframeBit
;
if
(
geometryGroupHash
!==
_currentGeometryGroupHash
)
{
_currentGeometryGroupHash
=
geometryGroupHash
;
updateBuffers
=
true
;
}
if
(
updateBuffers
)
{
renderer
.
disableAttributes
();
}
// vertices
if
(
!
material
.
morphTargets
&&
attributes
.
position
>=
0
)
{
if
(
updateBuffers
)
{
renderer
.
setFloatAttribute
(
attributes
.
position
,
geometryGroup
.
__webglVertexBuffer
,
3
,
0
);
}
}
else
{
if
(
object
.
morphTargetBase
)
{
setupMorphTargets
(
material
,
geometryGroup
,
object
);
}
}
if
(
updateBuffers
)
{
// custom attributes
// Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
if
(
geometryGroup
.
__webglCustomAttributesList
)
{
for
(
i
=
0
,
il
=
geometryGroup
.
__webglCustomAttributesList
.
length
;
i
<
il
;
i
++
)
{
attribute
=
geometryGroup
.
__webglCustomAttributesList
[
i
];
if
(
attributes
[
attribute
.
buffer
.
belongsToAttribute
]
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
[
attribute
.
buffer
.
belongsToAttribute
]
,
attribute
.
buffer
,
attribute
.
size
,
0
);
}
}
}
// colors
if
(
attributes
.
color
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
color
,
geometryGroup
.
__webglColorBuffer
,
3
,
0
);
}
// normals
if
(
attributes
.
normal
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
normal
,
geometryGroup
.
__webglNormalBuffer
,
3
,
0
);
}
// tangents
if
(
attributes
.
tangent
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
tangent
,
geometryGroup
.
__webglTangentBuffer
,
4
,
0
);
}
// uvs
if
(
attributes
.
uv
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
uv
,
geometryGroup
.
__webglUVBuffer
,
2
,
0
);
}
if
(
attributes
.
uv2
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
uv2
,
geometryGroup
.
__webglUV2Buffer
,
2
,
0
);
}
if
(
material
.
skinning
&&
attributes
.
skinIndex
>=
0
&&
attributes
.
skinWeight
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
skinIndex
,
geometryGroup
.
__webglSkinIndicesBuffer
,
4
,
0
);
renderer
.
setFloatAttribute
(
attributes
.
skinWeight
,
geometryGroup
.
__webglSkinWeightsBuffer
,
4
,
0
);
}
// line distances
if
(
attributes
.
lineDistance
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
lineDistance
,
geometryGroup
.
__webglLineDistanceBuffer
,
1
,
0
);
}
}
// render mesh
if
(
object
instanceof
THREE
.
Mesh
)
{
// wireframe
if
(
material
.
wireframe
)
{
renderer
.
setLineWidth
(
material
.
wireframeLinewidth
);
renderer
.
drawLineElements
(
geometryGroup
.
__webglLineBuffer
,
geometryGroup
.
__webglLineCount
,
0
);
// triangles
}
else
{
renderer
.
drawTriangleElements
(
geometryGroup
.
__webglFaceBuffer
,
geometryGroup
.
__webglFaceCount
,
0
);
}
_this
.
info
.
render
.
calls
++
;
_this
.
info
.
render
.
vertices
+=
geometryGroup
.
__webglFaceCount
;
_this
.
info
.
render
.
faces
+=
geometryGroup
.
__webglFaceCount
/
3
;
// render lines
}
else
if
(
object
instanceof
THREE
.
Line
)
{
renderer
.
setLineWidth
(
material
.
linewidth
);
if
(
object
.
type
===
THREE
.
LineStrip
)
{
renderer
.
drawLineStrip
(
geometryGroup
.
__webglLineCount
);
}
else
{
renderer
.
drawLines
(
geometryGroup
.
__webglLineCount
);
}
_this
.
info
.
render
.
calls
++
;
// render particles
}
else
if
(
object
instanceof
THREE
.
ParticleSystem
)
{
renderer
.
drawPoints
(
geometryGroup
.
__webglParticleCount
);
_this
.
info
.
render
.
calls
++
;
_this
.
info
.
render
.
points
+=
geometryGroup
.
__webglParticleCount
;
// render ribbon
}
else
if
(
object
instanceof
THREE
.
Ribbon
)
{
renderer
.
drawTriangleStrip
(
geometryGroup
.
__webglVertexCount
);
_this
.
info
.
render
.
calls
++
;
}
};
function
setupMorphTargets
(
material
,
geometryGroup
,
object
)
{
// set base
var
attributes
=
material
.
program
.
attributes
;
if
(
object
.
morphTargetBase
!==
-
1
&&
attributes
.
position
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
position
,
geometryGroup
.
__webglMorphTargetsBuffers
[
object
.
morphTargetBase
],
3
,
0
);
}
else
if
(
attributes
.
position
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
.
position
,
geometryGroup
.
__webglVertexBuffer
,
3
,
0
);
}
if
(
object
.
morphTargetForcedOrder
.
length
)
{
// set forced order
var
m
=
0
;
var
order
=
object
.
morphTargetForcedOrder
;
var
influences
=
object
.
morphTargetInfluences
;
while
(
m
<
material
.
numSupportedMorphTargets
&&
m
<
order
.
length
)
{
if
(
attributes
[
"
morphTarget
"
+
m
]
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
[
"
morphTarget
"
+
m
],
geometryGroup
.
__webglMorphTargetsBuffers
[
order
[
m
]
],
3
,
0
);
}
if
(
attributes
[
"
morphNormal
"
+
m
]
>=
0
&&
material
.
morphNormals
)
{
renderer
.
setFloatAttribute
(
attributes
[
"
morphNormal
"
+
m
],
geometryGroup
.
__webglMorphNormalsBuffers
[
order
[
m
]
],
3
,
0
);
}
object
.
__webglMorphTargetInfluences
[
m
]
=
influences
[
order
[
m
]
];
m
++
;
}
}
else
{
// find the most influencing
var
influence
,
activeInfluenceIndices
=
[];
var
influences
=
object
.
morphTargetInfluences
;
var
i
,
il
=
influences
.
length
;
for
(
i
=
0
;
i
<
il
;
i
++
)
{
influence
=
influences
[
i
];
if
(
influence
>
0
)
{
activeInfluenceIndices
.
push
(
[
influence
,
i
]
);
}
}
if
(
activeInfluenceIndices
.
length
>
material
.
numSupportedMorphTargets
)
{
activeInfluenceIndices
.
sort
(
numericalSort
);
activeInfluenceIndices
.
length
=
material
.
numSupportedMorphTargets
;
}
else
if
(
activeInfluenceIndices
.
length
>
material
.
numSupportedMorphNormals
)
{
activeInfluenceIndices
.
sort
(
numericalSort
);
}
else
if
(
activeInfluenceIndices
.
length
===
0
)
{
activeInfluenceIndices
.
push
(
[
0
,
0
]
);
};
var
influenceIndex
,
m
=
0
;
while
(
m
<
material
.
numSupportedMorphTargets
)
{
if
(
activeInfluenceIndices
[
m
]
)
{
influenceIndex
=
activeInfluenceIndices
[
m
][
1
];
if
(
attributes
[
"
morphTarget
"
+
m
]
>=
0
)
{
renderer
.
setFloatAttribute
(
attributes
[
"
morphTarget
"
+
m
],
geometryGroup
.
__webglMorphTargetsBuffers
[
influenceIndex
],
3
,
0
);
}
if
(
attributes
[
"
morphNormal
"
+
m
]
>=
0
&&
material
.
morphNormals
)
{
renderer
.
setFloatAttribute
(
attributes
[
"
morphNormal
"
+
m
],
geometryGroup
.
__webglMorphNormalsBuffers
[
influenceIndex
],
3
,
0
);
}
object
.
__webglMorphTargetInfluences
[
m
]
=
influences
[
influenceIndex
];
}
else
{
/*
_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
if ( material.morphNormals ) {
_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
}
*/
object
.
__webglMorphTargetInfluences
[
m
]
=
0
;
}
m
++
;
}
}
// load updated influences uniform
if
(
material
.
program
.
uniforms
.
morphTargetInfluences
!==
null
)
{
renderer
.
uniform1fv
(
material
.
program
.
uniforms
.
morphTargetInfluences
,
object
.
__webglMorphTargetInfluences
);
}
};
// Sorting
function
painterSortStable
(
a
,
b
)
{
if
(
a
.
z
!==
b
.
z
)
{
return
b
.
z
-
a
.
z
;
}
else
{
return
b
.
id
-
a
.
id
;
}
};
function
numericalSort
(
a
,
b
)
{
return
b
[
0
]
-
a
[
0
];
};
// Rendering
this
.
render
=
function
(
scene
,
camera
,
renderTarget
,
forceClear
)
{
if
(
camera
instanceof
THREE
.
Camera
===
false
)
{
console
.
error
(
'
THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.
'
);
return
;
}
var
i
,
il
,
webglObject
,
object
,
renderList
,
lights
=
scene
.
__lights
,
fog
=
scene
.
fog
;
// reset caching for this frame
_currentMaterialId
=
-
1
;
_lightsNeedUpdate
=
true
;
// update scene graph
if
(
this
.
autoUpdateScene
)
scene
.
updateMatrixWorld
();
// update camera matrices and frustum
if
(
camera
.
parent
===
undefined
)
camera
.
updateMatrixWorld
();
camera
.
matrixWorldInverse
.
getInverse
(
camera
.
matrixWorld
);
_projScreenMatrix
.
multiply
(
camera
.
projectionMatrix
,
camera
.
matrixWorldInverse
);
_frustum
.
setFromMatrix
(
_projScreenMatrix
);
// update WebGL objects
if
(
this
.
autoUpdateObjects
)
this
.
initWebGLObjects
(
scene
);
// custom render plugins (pre pass)
renderPlugins
(
this
.
renderPluginsPre
,
scene
,
camera
);
//
_this
.
info
.
render
.
calls
=
0
;
_this
.
info
.
render
.
vertices
=
0
;
_this
.
info
.
render
.
faces
=
0
;
_this
.
info
.
render
.
points
=
0
;
renderer
.
setRenderTarget
(
renderTarget
);
if
(
this
.
autoClear
||
forceClear
)
{
this
.
clear
(
this
.
autoClearColor
,
this
.
autoClearDepth
,
this
.
autoClearStencil
);
}
// set matrices for regular objects (frustum culled)
renderList
=
scene
.
__webglObjects
;
for
(
i
=
0
,
il
=
renderList
.
length
;
i
<
il
;
i
++
)
{
webglObject
=
renderList
[
i
];
object
=
webglObject
.
object
;
webglObject
.
render
=
false
;
if
(
object
.
visible
)
{
if
(
!
(
object
instanceof
THREE
.
Mesh
||
object
instanceof
THREE
.
ParticleSystem
)
||
!
(
object
.
frustumCulled
)
||
_frustum
.
intersectsObject
(
object
)
)
{
setupMatrices
(
object
,
camera
);
unrollBufferMaterial
(
webglObject
);
webglObject
.
render
=
true
;
if
(
this
.
sortObjects
===
true
)
{
if
(
object
.
renderDepth
!==
null
)
{
webglObject
.
z
=
object
.
renderDepth
;
}
else
{
_vector3
.
copy
(
object
.
matrixWorld
.
getPosition
()
);
_vector3
.
applyMatrix4
(
_projScreenMatrix
);
webglObject
.
z
=
_vector3
.
z
;
}
webglObject
.
id
=
object
.
id
;
}
}
}
}
if
(
this
.
sortObjects
)
{
renderList
.
sort
(
painterSortStable
);
}
// set matrices for immediate objects
renderList
=
scene
.
__webglObjectsImmediate
;
for
(
i
=
0
,
il
=
renderList
.
length
;
i
<
il
;
i
++
)
{
webglObject
=
renderList
[
i
];
object
=
webglObject
.
object
;
if
(
object
.
visible
)
{
setupMatrices
(
object
,
camera
);
unrollImmediateBufferMaterial
(
webglObject
);
}
}
if
(
scene
.
overrideMaterial
)
{
var
material
=
scene
.
overrideMaterial
;
renderer
.
setBlending
(
material
.
blending
,
material
.
blendEquation
,
material
.
blendSrc
,
material
.
blendDst
);
renderer
.
setDepthTest
(
material
.
depthTest
);
renderer
.
setDepthWrite
(
material
.
depthWrite
);
renderer
.
setPolygonOffset
(
material
.
polygonOffset
,
material
.
polygonOffsetFactor
,
material
.
polygonOffsetUnits
);
renderObjects
(
scene
.
__webglObjects
,
false
,
""
,
camera
,
lights
,
fog
,
true
,
material
);
renderObjectsImmediate
(
scene
.
__webglObjectsImmediate
,
""
,
camera
,
lights
,
fog
,
false
,
material
);
}
else
{
var
material
=
null
;
// opaque pass (front-to-back order)
renderer
.
setBlending
(
THREE
.
NoBlending
);
renderObjects
(
scene
.
__webglObjects
,
true
,
"
opaque
"
,
camera
,
lights
,
fog
,
false
,
material
);
renderObjectsImmediate
(
scene
.
__webglObjectsImmediate
,
"
opaque
"
,
camera
,
lights
,
fog
,
false
,
material
);
// transparent pass (back-to-front order)
renderObjects
(
scene
.
__webglObjects
,
false
,
"
transparent
"
,
camera
,
lights
,
fog
,
true
,
material
);
renderObjectsImmediate
(
scene
.
__webglObjectsImmediate
,
"
transparent
"
,
camera
,
lights
,
fog
,
true
,
material
);
}
// custom render plugins (post pass)
renderPlugins
(
this
.
renderPluginsPost
,
scene
,
camera
);
// Generate mipmap if we're using any kind of mipmap filtering
if
(
renderTarget
&&
renderTarget
.
generateMipmaps
&&
renderTarget
.
minFilter
!==
THREE
.
NearestFilter
&&
renderTarget
.
minFilter
!==
THREE
.
LinearFilter
)
{
renderer
.
updateRenderTargetMipmap
(
renderTarget
);
}
// Ensure depth buffer writing is enabled so it can be cleared on next render
renderer
.
setDepthTest
(
true
);
renderer
.
setDepthWrite
(
true
);
// _gl.finish();
};
function
renderPlugins
(
plugins
,
scene
,
camera
)
{
if
(
!
plugins
.
length
)
return
;
for
(
var
i
=
0
,
il
=
plugins
.
length
;
i
<
il
;
i
++
)
{
// reset state for plugin (to start from clean slate)
_currentProgram
=
null
;
_currentCamera
=
null
;
_currentGeometryGroupHash
=
-
1
;
_currentMaterialId
=
-
1
;
_lightsNeedUpdate
=
true
;
renderer
.
resetState
();
plugins
[
i
].
render
(
scene
,
camera
,
renderer
.
getCurrentWidth
(),
renderer
.
getCurrentWidth
()
);
// reset state after plugin (anything could have changed)
_currentProgram
=
null
;
_currentCamera
=
null
;
_currentGeometryGroupHash
=
-
1
;
_currentMaterialId
=
-
1
;
_lightsNeedUpdate
=
true
;
renderer
.
resetState
();
}
};
function
renderObjects
(
renderList
,
reverse
,
materialType
,
camera
,
lights
,
fog
,
useBlending
,
overrideMaterial
)
{
var
webglObject
,
object
,
buffer
,
material
,
start
,
end
,
delta
;
if
(
reverse
)
{
start
=
renderList
.
length
-
1
;
end
=
-
1
;
delta
=
-
1
;
}
else
{
start
=
0
;
end
=
renderList
.
length
;
delta
=
1
;
}
for
(
var
i
=
start
;
i
!==
end
;
i
+=
delta
)
{
webglObject
=
renderList
[
i
];
if
(
webglObject
.
render
)
{
object
=
webglObject
.
object
;
buffer
=
webglObject
.
buffer
;
if
(
overrideMaterial
)
{
material
=
overrideMaterial
;
}
else
{
material
=
webglObject
[
materialType
];
if
(
!
material
)
continue
;
if
(
useBlending
)
renderer
.
setBlending
(
material
.
blending
,
material
.
blendEquation
,
material
.
blendSrc
,
material
.
blendDst
);
renderer
.
setDepthTest
(
material
.
depthTest
);
renderer
.
setDepthWrite
(
material
.
depthWrite
);
renderer
.
setPolygonOffset
(
material
.
polygonOffset
,
material
.
polygonOffsetFactor
,
material
.
polygonOffsetUnits
);
}
renderer
.
setMaterialFaces
(
material
);
if
(
buffer
instanceof
THREE
.
BufferGeometry
)
{
_this
.
renderBufferDirect
(
camera
,
lights
,
fog
,
material
,
buffer
,
object
);
}
else
{
_this
.
renderBuffer
(
camera
,
lights
,
fog
,
material
,
buffer
,
object
);
}
}
}
};
function
renderObjectsImmediate
(
renderList
,
materialType
,
camera
,
lights
,
fog
,
useBlending
,
overrideMaterial
)
{
var
webglObject
,
object
,
material
,
program
;
for
(
var
i
=
0
,
il
=
renderList
.
length
;
i
<
il
;
i
++
)
{
webglObject
=
renderList
[
i
];
object
=
webglObject
.
object
;
if
(
object
.
visible
)
{
if
(
overrideMaterial
)
{
material
=
overrideMaterial
;
}
else
{
material
=
webglObject
[
materialType
];
if
(
!
material
)
continue
;
if
(
useBlending
)
renderer
.
setBlending
(
material
.
blending
,
material
.
blendEquation
,
material
.
blendSrc
,
material
.
blendDst
);
renderer
.
setDepthTest
(
material
.
depthTest
);
renderer
.
setDepthWrite
(
material
.
depthWrite
);
renderer
.
setPolygonOffset
(
material
.
polygonOffset
,
material
.
polygonOffsetFactor
,
material
.
polygonOffsetUnits
);
}
_this
.
renderImmediateObject
(
camera
,
lights
,
fog
,
material
,
object
);
}
}
};
this
.
renderImmediateObject
=
function
(
camera
,
lights
,
fog
,
material
,
object
)
{
var
program
=
setProgram
(
camera
,
lights
,
fog
,
material
,
object
);
_currentGeometryGroupHash
=
-
1
;
renderer
.
setMaterialFaces
(
material
);
if
(
object
.
immediateRenderCallback
)
{
object
.
immediateRenderCallback
(
program
,
renderer
.
getContext
(),
_frustum
);
}
else
{
object
.
render
(
function
(
object
)
{
_this
.
renderBufferImmediate
(
object
,
program
,
material
);
}
);
}
};
function
unrollImmediateBufferMaterial
(
globject
)
{
var
object
=
globject
.
object
,
material
=
object
.
material
;
if
(
material
.
transparent
)
{
globject
.
transparent
=
material
;
globject
.
opaque
=
null
;
}
else
{
globject
.
opaque
=
material
;
globject
.
transparent
=
null
;
}
};
function
unrollBufferMaterial
(
globject
)
{
var
object
=
globject
.
object
,
buffer
=
globject
.
buffer
,
material
,
materialIndex
,
meshMaterial
;
meshMaterial
=
object
.
material
;
if
(
meshMaterial
instanceof
THREE
.
MeshFaceMaterial
)
{
materialIndex
=
buffer
.
materialIndex
;
material
=
meshMaterial
.
materials
[
materialIndex
];
if
(
material
.
transparent
)
{
globject
.
transparent
=
material
;
globject
.
opaque
=
null
;
}
else
{
globject
.
opaque
=
material
;
globject
.
transparent
=
null
;
}
}
else
{
material
=
meshMaterial
;
if
(
material
)
{
if
(
material
.
transparent
)
{
globject
.
transparent
=
material
;
globject
.
opaque
=
null
;
}
else
{
globject
.
opaque
=
material
;
globject
.
transparent
=
null
;
}
}
}
};
// Geometry splitting
function
sortFacesByMaterial
(
geometry
,
material
)
{
var
f
,
fl
,
face
,
materialIndex
,
vertices
,
groupHash
,
hash_map
=
{};
var
numMorphTargets
=
geometry
.
morphTargets
.
length
;
var
numMorphNormals
=
geometry
.
morphNormals
.
length
;
var
usesFaceMaterial
=
material
instanceof
THREE
.
MeshFaceMaterial
;
geometry
.
geometryGroups
=
{};
for
(
f
=
0
,
fl
=
geometry
.
faces
.
length
;
f
<
fl
;
f
++
)
{
face
=
geometry
.
faces
[
f
];
materialIndex
=
usesFaceMaterial
?
face
.
materialIndex
:
0
;
if
(
hash_map
[
materialIndex
]
===
undefined
)
{
hash_map
[
materialIndex
]
=
{
'
hash
'
:
materialIndex
,
'
counter
'
:
0
};
}
groupHash
=
hash_map
[
materialIndex
].
hash
+
'
_
'
+
hash_map
[
materialIndex
].
counter
;
if
(
geometry
.
geometryGroups
[
groupHash
]
===
undefined
)
{
geometry
.
geometryGroups
[
groupHash
]
=
{
'
faces3
'
:
[],
'
faces4
'
:
[],
'
materialIndex
'
:
materialIndex
,
'
vertices
'
:
0
,
'
numMorphTargets
'
:
numMorphTargets
,
'
numMorphNormals
'
:
numMorphNormals
};
}
vertices
=
face
instanceof
THREE
.
Face3
?
3
:
4
;
if
(
geometry
.
geometryGroups
[
groupHash
].
vertices
+
vertices
>
65535
)
{
hash_map
[
materialIndex
].
counter
+=
1
;
groupHash
=
hash_map
[
materialIndex
].
hash
+
'
_
'
+
hash_map
[
materialIndex
].
counter
;
if
(
geometry
.
geometryGroups
[
groupHash
]
===
undefined
)
{
geometry
.
geometryGroups
[
groupHash
]
=
{
'
faces3
'
:
[],
'
faces4
'
:
[],
'
materialIndex
'
:
materialIndex
,
'
vertices
'
:
0
,
'
numMorphTargets
'
:
numMorphTargets
,
'
numMorphNormals
'
:
numMorphNormals
};
}
}
if
(
face
instanceof
THREE
.
Face3
)
{
geometry
.
geometryGroups
[
groupHash
].
faces3
.
push
(
f
);
}
else
{
geometry
.
geometryGroups
[
groupHash
].
faces4
.
push
(
f
);
}
geometry
.
geometryGroups
[
groupHash
].
vertices
+=
vertices
;
}
geometry
.
geometryGroupsList
=
[];
for
(
var
g
in
geometry
.
geometryGroups
)
{
geometry
.
geometryGroups
[
g
].
id
=
_geometryGroupCounter
++
;
geometry
.
geometryGroupsList
.
push
(
geometry
.
geometryGroups
[
g
]
);
}
};
// Objects refresh
this
.
initWebGLObjects
=
function
(
scene
)
{
if
(
!
scene
.
__webglObjects
)
{
scene
.
__webglObjects
=
[];
scene
.
__webglObjectsImmediate
=
[];
scene
.
__webglSprites
=
[];
scene
.
__webglFlares
=
[];
}
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
(
var
o
=
0
,
ol
=
scene
.
__webglObjects
.
length
;
o
<
ol
;
o
++
)
{
updateObject
(
scene
.
__webglObjects
[
o
].
object
);
}
};
// Objects adding
function
addObject
(
object
,
scene
)
{
var
g
,
geometry
,
material
,
geometryGroup
;
if
(
!
object
.
__webglInit
)
{
object
.
__webglInit
=
true
;
object
.
_modelViewMatrix
=
new
THREE
.
Matrix4
();
object
.
_normalMatrix
=
new
THREE
.
Matrix3
();
if
(
object
.
geometry
!==
undefined
&&
object
.
geometry
.
__webglInit
===
undefined
)
{
object
.
geometry
.
__webglInit
=
true
;
object
.
geometry
.
addEventListener
(
'
dispose
'
,
onGeometryDispose
);
}
if
(
object
instanceof
THREE
.
Mesh
)
{
geometry
=
object
.
geometry
;
material
=
object
.
material
;
if
(
geometry
instanceof
THREE
.
Geometry
)
{
if
(
geometry
.
geometryGroups
===
undefined
)
{
sortFacesByMaterial
(
geometry
,
material
);
}
// create separate VBOs per geometry chunk
for
(
g
in
geometry
.
geometryGroups
)
{
geometryGroup
=
geometry
.
geometryGroups
[
g
];
// initialise VBO on the first access
if
(
!
geometryGroup
.
__webglVertexBuffer
)
{
meshRenderer
.
createBuffers
(
geometryGroup
);
meshRenderer
.
initBuffers
(
geometryGroup
,
object
);
geometry
.
verticesNeedUpdate
=
true
;
geometry
.
morphTargetsNeedUpdate
=
true
;
geometry
.
elementsNeedUpdate
=
true
;
geometry
.
uvsNeedUpdate
=
true
;
geometry
.
normalsNeedUpdate
=
true
;
geometry
.
tangentsNeedUpdate
=
true
;
geometry
.
colorsNeedUpdate
=
true
;
}
}
}
else
if
(
geometry
instanceof
THREE
.
BufferGeometry
)
{
initDirectBuffers
(
geometry
);
}
}
else
if
(
object
instanceof
THREE
.
Ribbon
)
{
geometry
=
object
.
geometry
;
if
(
!
geometry
.
__webglVertexBuffer
)
{
ribbonRenderer
.
createBuffers
(
geometry
);
ribbonRenderer
.
initBuffers
(
geometry
,
object
);
geometry
.
verticesNeedUpdate
=
true
;
geometry
.
colorsNeedUpdate
=
true
;
geometry
.
normalsNeedUpdate
=
true
;
}
}
else
if
(
object
instanceof
THREE
.
Line
)
{
geometry
=
object
.
geometry
;
if
(
!
geometry
.
__webglVertexBuffer
)
{
lineRenderer
.
createBuffers
(
geometry
);
lineRenderer
.
initBuffers
(
geometry
,
object
);
geometry
.
verticesNeedUpdate
=
true
;
geometry
.
colorsNeedUpdate
=
true
;
geometry
.
lineDistancesNeedUpdate
=
true
;
}
}
else
if
(
object
instanceof
THREE
.
ParticleSystem
)
{
geometry
=
object
.
geometry
;
if
(
!
geometry
.
__webglVertexBuffer
)
{
if
(
geometry
instanceof
THREE
.
Geometry
)
{
particleRenderer
.
createBuffers
(
geometry
);
particleRenderer
.
initBuffers
(
geometry
,
object
);
geometry
.
verticesNeedUpdate
=
true
;
geometry
.
colorsNeedUpdate
=
true
;
}
else
if
(
geometry
instanceof
THREE
.
BufferGeometry
)
{
initDirectBuffers
(
geometry
);
}
}
}
}
if
(
!
object
.
__webglActive
)
{
if
(
object
instanceof
THREE
.
Mesh
)
{
geometry
=
object
.
geometry
;
if
(
geometry
instanceof
THREE
.
BufferGeometry
)
{
addBuffer
(
scene
.
__webglObjects
,
geometry
,
object
);
}
else
if
(
geometry
instanceof
THREE
.
Geometry
)
{
for
(
g
in
geometry
.
geometryGroups
)
{
geometryGroup
=
geometry
.
geometryGroups
[
g
];
addBuffer
(
scene
.
__webglObjects
,
geometryGroup
,
object
);
}
}
}
else
if
(
object
instanceof
THREE
.
Ribbon
||
object
instanceof
THREE
.
Line
||
object
instanceof
THREE
.
ParticleSystem
)
{
geometry
=
object
.
geometry
;
addBuffer
(
scene
.
__webglObjects
,
geometry
,
object
);
}
else
if
(
object
instanceof
THREE
.
ImmediateRenderObject
||
object
.
immediateRenderCallback
)
{
addBufferImmediate
(
scene
.
__webglObjectsImmediate
,
object
);
}
else
if
(
object
instanceof
THREE
.
Sprite
)
{
scene
.
__webglSprites
.
push
(
object
);
}
else
if
(
object
instanceof
THREE
.
LensFlare
)
{
scene
.
__webglFlares
.
push
(
object
);
}
object
.
__webglActive
=
true
;
}
};
function
addBuffer
(
objlist
,
buffer
,
object
)
{
objlist
.
push
(
{
buffer
:
buffer
,
object
:
object
,
opaque
:
null
,
transparent
:
null
}
);
};
function
addBufferImmediate
(
objlist
,
object
)
{
objlist
.
push
(
{
object
:
object
,
opaque
:
null
,
transparent
:
null
}
);
};
// Objects updates
function
updateObject
(
object
)
{
var
geometry
=
object
.
geometry
,
geometryGroup
,
customAttributesDirty
,
material
;
if
(
object
instanceof
THREE
.
Mesh
)
{
if
(
geometry
instanceof
THREE
.
BufferGeometry
)
{
if
(
geometry
.
verticesNeedUpdate
||
geometry
.
elementsNeedUpdate
||
geometry
.
uvsNeedUpdate
||
geometry
.
normalsNeedUpdate
||
geometry
.
colorsNeedUpdate
||
geometry
.
tangentsNeedUpdate
)
{
setDirectBuffers
(
geometry
,
!
geometry
.
dynamic
);
}
geometry
.
verticesNeedUpdate
=
false
;
geometry
.
elementsNeedUpdate
=
false
;
geometry
.
uvsNeedUpdate
=
false
;
geometry
.
normalsNeedUpdate
=
false
;
geometry
.
colorsNeedUpdate
=
false
;
geometry
.
tangentsNeedUpdate
=
false
;
}
else
{
// check all geometry groups
for
(
var
i
=
0
,
il
=
geometry
.
geometryGroupsList
.
length
;
i
<
il
;
i
++
)
{
geometryGroup
=
geometry
.
geometryGroupsList
[
i
];
material
=
getBufferMaterial
(
object
,
geometryGroup
);
if
(
geometry
.
buffersNeedUpdate
)
{
meshRenderer
.
initBuffers
(
geometryGroup
,
object
);
}
customAttributesDirty
=
material
.
attributes
&&
areCustomAttributesDirty
(
material
);
if
(
geometry
.
verticesNeedUpdate
||
geometry
.
morphTargetsNeedUpdate
||
geometry
.
elementsNeedUpdate
||
geometry
.
uvsNeedUpdate
||
geometry
.
normalsNeedUpdate
||
geometry
.
colorsNeedUpdate
||
geometry
.
tangentsNeedUpdate
||
customAttributesDirty
)
{
meshRenderer
.
setBuffers
(
geometryGroup
,
object
,
!
geometry
.
dynamic
,
material
);
}
}
geometry
.
verticesNeedUpdate
=
false
;
geometry
.
morphTargetsNeedUpdate
=
false
;
geometry
.
elementsNeedUpdate
=
false
;
geometry
.
uvsNeedUpdate
=
false
;
geometry
.
normalsNeedUpdate
=
false
;
geometry
.
colorsNeedUpdate
=
false
;
geometry
.
tangentsNeedUpdate
=
false
;
geometry
.
buffersNeedUpdate
=
false
;
material
.
attributes
&&
clearCustomAttributes
(
material
);
}
}
else
if
(
object
instanceof
THREE
.
Ribbon
)
{
material
=
getBufferMaterial
(
object
,
geometry
);
customAttributesDirty
=
material
.
attributes
&&
areCustomAttributesDirty
(
material
);
if
(
geometry
.
verticesNeedUpdate
||
geometry
.
colorsNeedUpdate
||
geometry
.
normalsNeedUpdate
||
customAttributesDirty
)
{
ribbonRenderer
.
setBuffers
(
geometry
);
}
geometry
.
verticesNeedUpdate
=
false
;
geometry
.
colorsNeedUpdate
=
false
;
geometry
.
normalsNeedUpdate
=
false
;
material
.
attributes
&&
clearCustomAttributes
(
material
);
}
else
if
(
object
instanceof
THREE
.
Line
)
{
material
=
getBufferMaterial
(
object
,
geometry
);
customAttributesDirty
=
material
.
attributes
&&
areCustomAttributesDirty
(
material
);
if
(
geometry
.
verticesNeedUpdate
||
geometry
.
colorsNeedUpdate
||
geometry
.
lineDistancesNeedUpdate
||
customAttributesDirty
)
{
lineRenderer
.
setBuffers
(
geometry
);
}
geometry
.
verticesNeedUpdate
=
false
;
geometry
.
colorsNeedUpdate
=
false
;
geometry
.
lineDistancesNeedUpdate
=
false
;
material
.
attributes
&&
clearCustomAttributes
(
material
);
}
else
if
(
object
instanceof
THREE
.
ParticleSystem
)
{
if
(
geometry
instanceof
THREE
.
BufferGeometry
)
{
if
(
geometry
.
verticesNeedUpdate
||
geometry
.
colorsNeedUpdate
)
{
setDirectBuffers
(
geometry
,
!
geometry
.
dynamic
);
}
geometry
.
verticesNeedUpdate
=
false
;
geometry
.
colorsNeedUpdate
=
false
;
}
else
{
material
=
getBufferMaterial
(
object
,
geometry
);
customAttributesDirty
=
material
.
attributes
&&
areCustomAttributesDirty
(
material
);
if
(
geometry
.
verticesNeedUpdate
||
geometry
.
colorsNeedUpdate
||
object
.
sortParticles
||
customAttributesDirty
)
{
particleRenderer
.
setBuffers
(
geometry
,
object
,
_projScreenMatrix
);
}
geometry
.
verticesNeedUpdate
=
false
;
geometry
.
colorsNeedUpdate
=
false
;
material
.
attributes
&&
clearCustomAttributes
(
material
);
}
}
};
// Objects updates - custom attributes check
function
areCustomAttributesDirty
(
material
)
{
for
(
var
a
in
material
.
attributes
)
{
if
(
material
.
attributes
[
a
].
needsUpdate
)
return
true
;
}
return
false
;
};
function
clearCustomAttributes
(
material
)
{
for
(
var
a
in
material
.
attributes
)
{
material
.
attributes
[
a
].
needsUpdate
=
false
;
}
};
// Objects removal
function
removeObject
(
object
,
scene
)
{
if
(
object
instanceof
THREE
.
Mesh
||
object
instanceof
THREE
.
ParticleSystem
||
object
instanceof
THREE
.
Ribbon
||
object
instanceof
THREE
.
Line
)
{
removeInstances
(
scene
.
__webglObjects
,
object
);
}
else
if
(
object
instanceof
THREE
.
Sprite
)
{
removeInstancesDirect
(
scene
.
__webglSprites
,
object
);
}
else
if
(
object
instanceof
THREE
.
LensFlare
)
{
removeInstancesDirect
(
scene
.
__webglFlares
,
object
);
}
else
if
(
object
instanceof
THREE
.
ImmediateRenderObject
||
object
.
immediateRenderCallback
)
{
removeInstances
(
scene
.
__webglObjectsImmediate
,
object
);
}
object
.
__webglActive
=
false
;
};
function
removeInstances
(
objlist
,
object
)
{
for
(
var
o
=
objlist
.
length
-
1
;
o
>=
0
;
o
--
)
{
if
(
objlist
[
o
].
object
===
object
)
{
objlist
.
splice
(
o
,
1
);
}
}
};
function
removeInstancesDirect
(
objlist
,
object
)
{
for
(
var
o
=
objlist
.
length
-
1
;
o
>=
0
;
o
--
)
{
if
(
objlist
[
o
]
===
object
)
{
objlist
.
splice
(
o
,
1
);
}
}
};
// Materials
this
.
initMaterial
=
function
(
material
,
lights
,
fog
,
object
)
{
material
.
addEventListener
(
'
dispose
'
,
onMaterialDispose
);
var
u
,
a
,
identifiers
,
i
,
parameters
,
maxLightCount
,
maxBones
,
maxShadows
,
shaderID
;
if
(
material
instanceof
THREE
.
MeshDepthMaterial
)
{
shaderID
=
'
depth
'
;
}
else
if
(
material
instanceof
THREE
.
MeshNormalMaterial
)
{
shaderID
=
'
normal
'
;
}
else
if
(
material
instanceof
THREE
.
MeshBasicMaterial
)
{
shaderID
=
'
basic
'
;
}
else
if
(
material
instanceof
THREE
.
MeshLambertMaterial
)
{
shaderID
=
'
lambert
'
;
}
else
if
(
material
instanceof
THREE
.
MeshPhongMaterial
)
{
shaderID
=
'
phong
'
;
}
else
if
(
material
instanceof
THREE
.
LineBasicMaterial
)
{
shaderID
=
'
basic
'
;
}
else
if
(
material
instanceof
THREE
.
LineDashedMaterial
)
{
shaderID
=
'
dashed
'
;
}
else
if
(
material
instanceof
THREE
.
ParticleBasicMaterial
)
{
shaderID
=
'
particle_basic
'
;
}
if
(
shaderID
)
{
setMaterialShaders
(
material
,
THREE
.
ShaderLib
[
shaderID
]
);
}
// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
maxLightCount
=
allocateLights
(
lights
);
maxShadows
=
allocateShadows
(
lights
);
maxBones
=
allocateBones
(
object
);
parameters
=
{
map
:
!!
material
.
map
,
envMap
:
!!
material
.
envMap
,
lightMap
:
!!
material
.
lightMap
,
bumpMap
:
!!
material
.
bumpMap
,
normalMap
:
!!
material
.
normalMap
,
specularMap
:
!!
material
.
specularMap
,
vertexColors
:
material
.
vertexColors
,
fog
:
fog
,
useFog
:
material
.
fog
,
fogExp
:
fog
instanceof
THREE
.
FogExp2
,
sizeAttenuation
:
material
.
sizeAttenuation
,
skinning
:
material
.
skinning
,
maxBones
:
maxBones
,
useVertexTexture
:
renderer
.
supportsBoneTextures
&&
object
&&
object
.
useVertexTexture
,
boneTextureWidth
:
object
&&
object
.
boneTextureWidth
,
boneTextureHeight
:
object
&&
object
.
boneTextureHeight
,
morphTargets
:
material
.
morphTargets
,
morphNormals
:
material
.
morphNormals
,
maxMorphTargets
:
this
.
maxMorphTargets
,
maxMorphNormals
:
this
.
maxMorphNormals
,
maxDirLights
:
maxLightCount
.
directional
,
maxPointLights
:
maxLightCount
.
point
,
maxSpotLights
:
maxLightCount
.
spot
,
maxHemiLights
:
maxLightCount
.
hemi
,
maxShadows
:
maxShadows
,
shadowMapEnabled
:
this
.
shadowMapEnabled
&&
object
.
receiveShadow
,
shadowMapType
:
this
.
shadowMapType
,
shadowMapDebug
:
this
.
shadowMapDebug
,
shadowMapCascade
:
this
.
shadowMapCascade
,
alphaTest
:
material
.
alphaTest
,
metal
:
material
.
metal
,
perPixel
:
material
.
perPixel
,
wrapAround
:
material
.
wrapAround
,
doubleSided
:
material
.
side
===
THREE
.
DoubleSide
,
flipSided
:
material
.
side
===
THREE
.
BackSide
,
gammaInput
:
this
.
gammaInput
,
gammaOutput
:
this
.
gammaOutput
,
physicallyBasedShading
:
this
.
physicallyBasedShading
};
material
.
program
=
shaderBuilder
.
buildProgram
(
shaderID
,
material
.
fragmentShader
,
material
.
vertexShader
,
material
.
uniforms
,
material
.
attributes
,
material
.
defines
,
parameters
);
var
attributes
=
material
.
program
.
attributes
;
if
(
material
.
morphTargets
)
{
material
.
numSupportedMorphTargets
=
0
;
var
id
,
base
=
"
morphTarget
"
;
for
(
i
=
0
;
i
<
this
.
maxMorphTargets
;
i
++
)
{
id
=
base
+
i
;
if
(
attributes
[
id
]
>=
0
)
{
material
.
numSupportedMorphTargets
++
;
}
}
}
if
(
material
.
morphNormals
)
{
material
.
numSupportedMorphNormals
=
0
;
var
id
,
base
=
"
morphNormal
"
;
for
(
i
=
0
;
i
<
this
.
maxMorphNormals
;
i
++
)
{
id
=
base
+
i
;
if
(
attributes
[
id
]
>=
0
)
{
material
.
numSupportedMorphNormals
++
;
}
}
}
material
.
uniformsList
=
[];
for
(
u
in
material
.
uniforms
)
{
material
.
uniformsList
.
push
(
[
material
.
uniforms
[
u
],
u
]
);
}
};
function
setMaterialShaders
(
material
,
shaders
)
{
material
.
uniforms
=
THREE
.
UniformsUtils
.
clone
(
shaders
.
uniforms
);
material
.
vertexShader
=
shaders
.
vertexShader
;
material
.
fragmentShader
=
shaders
.
fragmentShader
;
};
function
setProgram
(
camera
,
lights
,
fog
,
material
,
object
)
{
_usedTextureUnits
=
0
;
if
(
material
.
needsUpdate
)
{
if
(
material
.
program
)
deallocateMaterial
(
material
);
_this
.
initMaterial
(
material
,
lights
,
fog
,
object
);
material
.
needsUpdate
=
false
;
}
if
(
material
.
morphTargets
)
{
if
(
!
object
.
__webglMorphTargetInfluences
)
{
object
.
__webglMorphTargetInfluences
=
new
Float32Array
(
_this
.
maxMorphTargets
);
}
}
var
refreshMaterial
=
false
;
var
program
=
material
.
program
,
p_uniforms
=
program
.
uniforms
,
m_uniforms
=
material
.
uniforms
;
if
(
program
!==
_currentProgram
)
{
renderer
.
useProgram
(
program
);
_currentProgram
=
program
;
refreshMaterial
=
true
;
}
if
(
material
.
id
!==
_currentMaterialId
)
{
_currentMaterialId
=
material
.
id
;
refreshMaterial
=
true
;
}
if
(
refreshMaterial
||
camera
!==
_currentCamera
)
{
renderer
.
uniformMatrix4fv
(
p_uniforms
.
projectionMatrix
,
camera
.
projectionMatrix
.
elements
);
if
(
camera
!==
_currentCamera
)
_currentCamera
=
camera
;
}
// skinning uniforms must be set even if material didn't change
// auto-setting of texture unit for bone texture must go before other textures
// not sure why, but otherwise weird things happen
if
(
material
.
skinning
)
{
if
(
renderer
.
supportsBoneTextures
&&
object
.
useVertexTexture
)
{
if
(
p_uniforms
.
boneTexture
!==
null
)
{
var
textureUnit
=
getTextureUnit
();
renderer
.
uniform1i
(
p_uniforms
.
boneTexture
,
textureUnit
);
renderer
.
setTexture
(
object
.
boneTexture
,
textureUnit
);
}
}
else
{
if
(
p_uniforms
.
boneGlobalMatrices
!==
null
)
{
renderer
.
uniformMatrix4fv
(
p_uniforms
.
boneGlobalMatrices
,
object
.
boneMatrices
);
}
}
}
if
(
refreshMaterial
)
{
// refresh uniforms common to several materials
if
(
fog
&&
material
.
fog
)
{
refreshUniformsFog
(
m_uniforms
,
fog
);
}
if
(
material
instanceof
THREE
.
MeshPhongMaterial
||
material
instanceof
THREE
.
MeshLambertMaterial
||
material
.
lights
)
{
if
(
_lightsNeedUpdate
)
{
setupLights
(
program
,
lights
);
_lightsNeedUpdate
=
false
;
}
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
)
{
refreshUniformsLine
(
m_uniforms
,
material
);
}
else
if
(
material
instanceof
THREE
.
LineDashedMaterial
)
{
refreshUniformsLine
(
m_uniforms
,
material
);
refreshUniformsDash
(
m_uniforms
,
material
);
}
else
if
(
material
instanceof
THREE
.
ParticleBasicMaterial
)
{
refreshUniformsParticle
(
m_uniforms
,
material
);
}
else
if
(
material
instanceof
THREE
.
MeshPhongMaterial
)
{
refreshUniformsPhong
(
m_uniforms
,
material
);
}
else
if
(
material
instanceof
THREE
.
MeshLambertMaterial
)
{
refreshUniformsLambert
(
m_uniforms
,
material
);
}
else
if
(
material
instanceof
THREE
.
MeshDepthMaterial
)
{
m_uniforms
.
mNear
.
value
=
camera
.
near
;
m_uniforms
.
mFar
.
value
=
camera
.
far
;
m_uniforms
.
opacity
.
value
=
material
.
opacity
;
}
else
if
(
material
instanceof
THREE
.
MeshNormalMaterial
)
{
m_uniforms
.
opacity
.
value
=
material
.
opacity
;
}
if
(
object
.
receiveShadow
&&
!
material
.
_shadowPass
)
{
refreshUniformsShadow
(
m_uniforms
,
lights
);
}
// load common uniforms
loadUniformsGeneric
(
program
,
material
.
uniformsList
);
// load material specific uniforms
// (shader material also gets them for the sake of genericity)
if
(
material
instanceof
THREE
.
ShaderMaterial
||
material
instanceof
THREE
.
MeshPhongMaterial
||
material
.
envMap
)
{
if
(
p_uniforms
.
cameraPosition
!==
null
)
{
var
position
=
camera
.
matrixWorld
.
getPosition
();
renderer
.
uniform3f
(
p_uniforms
.
cameraPosition
,
position
.
x
,
position
.
y
,
position
.
z
);
}
}
if
(
material
instanceof
THREE
.
MeshPhongMaterial
||
material
instanceof
THREE
.
MeshLambertMaterial
||
material
instanceof
THREE
.
ShaderMaterial
||
material
.
skinning
)
{
if
(
p_uniforms
.
viewMatrix
!==
null
)
{
renderer
.
uniformMatrix4fv
(
p_uniforms
.
viewMatrix
,
camera
.
matrixWorldInverse
.
elements
);
}
}
}
loadUniformsMatrices
(
p_uniforms
,
object
);
if
(
p_uniforms
.
modelMatrix
!==
null
)
{
renderer
.
uniformMatrix4fv
(
p_uniforms
.
modelMatrix
,
object
.
matrixWorld
.
elements
);
}
return
program
;
};
// Uniforms (refresh uniforms objects)
function
refreshUniformsCommon
(
uniforms
,
material
)
{
uniforms
.
opacity
.
value
=
material
.
opacity
;
if
(
_this
.
gammaInput
)
{
uniforms
.
diffuse
.
value
.
copyGammaToLinear
(
material
.
color
);
}
else
{
uniforms
.
diffuse
.
value
=
material
.
color
;
}
uniforms
.
map
.
value
=
material
.
map
;
uniforms
.
lightMap
.
value
=
material
.
lightMap
;
uniforms
.
specularMap
.
value
=
material
.
specularMap
;
if
(
material
.
bumpMap
)
{
uniforms
.
bumpMap
.
value
=
material
.
bumpMap
;
uniforms
.
bumpScale
.
value
=
material
.
bumpScale
;
}
if
(
material
.
normalMap
)
{
uniforms
.
normalMap
.
value
=
material
.
normalMap
;
uniforms
.
normalScale
.
value
.
copy
(
material
.
normalScale
);
}
// uv repeat and offset setting priorities
// 1. color map
// 2. specular map
// 3. normal map
// 4. bump map
var
uvScaleMap
;
if
(
material
.
map
)
{
uvScaleMap
=
material
.
map
;
}
else
if
(
material
.
specularMap
)
{
uvScaleMap
=
material
.
specularMap
;
}
else
if
(
material
.
normalMap
)
{
uvScaleMap
=
material
.
normalMap
;
}
else
if
(
material
.
bumpMap
)
{
uvScaleMap
=
material
.
bumpMap
;
}
if
(
uvScaleMap
!==
undefined
)
{
var
offset
=
uvScaleMap
.
offset
;
var
repeat
=
uvScaleMap
.
repeat
;
uniforms
.
offsetRepeat
.
value
.
set
(
offset
.
x
,
offset
.
y
,
repeat
.
x
,
repeat
.
y
);
}
uniforms
.
envMap
.
value
=
material
.
envMap
;
uniforms
.
flipEnvMap
.
value
=
(
material
.
envMap
instanceof
THREE
.
WebGLRenderTargetCube
)
?
1
:
-
1
;
if
(
_this
.
gammaInput
)
{
//uniforms.reflectivity.value = material.reflectivity * material.reflectivity;
uniforms
.
reflectivity
.
value
=
material
.
reflectivity
;
}
else
{
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
;
};
function
refreshUniformsLine
(
uniforms
,
material
)
{
uniforms
.
diffuse
.
value
=
material
.
color
;
uniforms
.
opacity
.
value
=
material
.
opacity
;
};
function
refreshUniformsDash
(
uniforms
,
material
)
{
uniforms
.
dashSize
.
value
=
material
.
dashSize
;
uniforms
.
totalSize
.
value
=
material
.
dashSize
+
material
.
gapSize
;
uniforms
.
scale
.
value
=
material
.
scale
;
};
function
refreshUniformsParticle
(
uniforms
,
material
)
{
uniforms
.
psColor
.
value
=
material
.
color
;
uniforms
.
opacity
.
value
=
material
.
opacity
;
uniforms
.
size
.
value
=
material
.
size
;
uniforms
.
scale
.
value
=
renderer
.
getDomElement
().
height
/
2.0
;
// TODO: Cache this.
uniforms
.
map
.
value
=
material
.
map
;
};
function
refreshUniformsFog
(
uniforms
,
fog
)
{
uniforms
.
fogColor
.
value
=
fog
.
color
;
if
(
fog
instanceof
THREE
.
Fog
)
{
uniforms
.
fogNear
.
value
=
fog
.
near
;
uniforms
.
fogFar
.
value
=
fog
.
far
;
}
else
if
(
fog
instanceof
THREE
.
FogExp2
)
{
uniforms
.
fogDensity
.
value
=
fog
.
density
;
}
};
function
refreshUniformsPhong
(
uniforms
,
material
)
{
uniforms
.
shininess
.
value
=
material
.
shininess
;
if
(
_this
.
gammaInput
)
{
uniforms
.
ambient
.
value
.
copyGammaToLinear
(
material
.
ambient
);
uniforms
.
emissive
.
value
.
copyGammaToLinear
(
material
.
emissive
);
uniforms
.
specular
.
value
.
copyGammaToLinear
(
material
.
specular
);
}
else
{
uniforms
.
ambient
.
value
=
material
.
ambient
;
uniforms
.
emissive
.
value
=
material
.
emissive
;
uniforms
.
specular
.
value
=
material
.
specular
;
}
if
(
material
.
wrapAround
)
{
uniforms
.
wrapRGB
.
value
.
copy
(
material
.
wrapRGB
);
}
};
function
refreshUniformsLambert
(
uniforms
,
material
)
{
if
(
_this
.
gammaInput
)
{
uniforms
.
ambient
.
value
.
copyGammaToLinear
(
material
.
ambient
);
uniforms
.
emissive
.
value
.
copyGammaToLinear
(
material
.
emissive
);
}
else
{
uniforms
.
ambient
.
value
=
material
.
ambient
;
uniforms
.
emissive
.
value
=
material
.
emissive
;
}
if
(
material
.
wrapAround
)
{
uniforms
.
wrapRGB
.
value
.
copy
(
material
.
wrapRGB
);
}
};
function
refreshUniformsLights
(
uniforms
,
lights
)
{
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
;
uniforms
.
pointLightDistance
.
value
=
lights
.
point
.
distances
;
uniforms
.
spotLightColor
.
value
=
lights
.
spot
.
colors
;
uniforms
.
spotLightPosition
.
value
=
lights
.
spot
.
positions
;
uniforms
.
spotLightDistance
.
value
=
lights
.
spot
.
distances
;
uniforms
.
spotLightDirection
.
value
=
lights
.
spot
.
directions
;
uniforms
.
spotLightAngleCos
.
value
=
lights
.
spot
.
anglesCos
;
uniforms
.
spotLightExponent
.
value
=
lights
.
spot
.
exponents
;
uniforms
.
hemisphereLightSkyColor
.
value
=
lights
.
hemi
.
skyColors
;
uniforms
.
hemisphereLightGroundColor
.
value
=
lights
.
hemi
.
groundColors
;
uniforms
.
hemisphereLightDirection
.
value
=
lights
.
hemi
.
positions
;
};
function
refreshUniformsShadow
(
uniforms
,
lights
)
{
if
(
uniforms
.
shadowMatrix
)
{
var
j
=
0
;
for
(
var
i
=
0
,
il
=
lights
.
length
;
i
<
il
;
i
++
)
{
var
light
=
lights
[
i
];
if
(
!
light
.
castShadow
)
continue
;
if
(
light
instanceof
THREE
.
SpotLight
||
(
light
instanceof
THREE
.
DirectionalLight
&&
!
light
.
shadowCascade
)
)
{
uniforms
.
shadowMap
.
value
[
j
]
=
light
.
shadowMap
;
uniforms
.
shadowMapSize
.
value
[
j
]
=
light
.
shadowMapSize
;
uniforms
.
shadowMatrix
.
value
[
j
]
=
light
.
shadowMatrix
;
uniforms
.
shadowDarkness
.
value
[
j
]
=
light
.
shadowDarkness
;
uniforms
.
shadowBias
.
value
[
j
]
=
light
.
shadowBias
;
j
++
;
}
}
}
};
// Uniforms (load to GPU)
function
loadUniformsMatrices
(
uniforms
,
object
)
{
renderer
.
uniformMatrix4fv
(
uniforms
.
modelViewMatrix
,
object
.
_modelViewMatrix
.
elements
);
if
(
uniforms
.
normalMatrix
)
{
renderer
.
uniformMatrix3fv
(
uniforms
.
normalMatrix
,
object
.
_normalMatrix
.
elements
);
}
};
function
getTextureUnit
()
{
var
textureUnit
=
_usedTextureUnits
;
if
(
textureUnit
>=
renderer
.
maxTextures
)
{
console
.
warn
(
"
WebGLRenderer: trying to use
"
+
textureUnit
+
"
texture units while this GPU supports only
"
+
renderer
.
maxTextures
);
}
_usedTextureUnits
+=
1
;
return
textureUnit
;
};
function
loadUniformsGeneric
(
program
,
uniforms
)
{
var
uniform
,
value
,
type
,
location
,
texture
,
textureUnit
,
i
,
il
,
j
,
jl
,
offset
;
for
(
j
=
0
,
jl
=
uniforms
.
length
;
j
<
jl
;
j
++
)
{
location
=
program
.
uniforms
[
uniforms
[
j
][
1
]
];
if
(
!
location
)
continue
;
uniform
=
uniforms
[
j
][
0
];
type
=
uniform
.
type
;
value
=
uniform
.
value
;
if
(
type
===
"
i
"
)
{
// single integer
renderer
.
uniform1i
(
location
,
value
);
}
else
if
(
type
===
"
f
"
)
{
// single float
renderer
.
uniform1f
(
location
,
value
);
}
else
if
(
type
===
"
v2
"
)
{
// single THREE.Vector2
renderer
.
uniform2f
(
location
,
value
.
x
,
value
.
y
);
}
else
if
(
type
===
"
v3
"
)
{
// single THREE.Vector3
renderer
.
uniform3f
(
location
,
value
.
x
,
value
.
y
,
value
.
z
);
}
else
if
(
type
===
"
v4
"
)
{
// single THREE.Vector4
renderer
.
uniform4f
(
location
,
value
.
x
,
value
.
y
,
value
.
z
,
value
.
w
);
}
else
if
(
type
===
"
c
"
)
{
// single THREE.Color
renderer
.
uniform3f
(
location
,
value
.
r
,
value
.
g
,
value
.
b
);
}
else
if
(
type
===
"
iv1
"
)
{
// flat array of integers (JS or typed array)
renderer
.
uniform1iv
(
location
,
value
);
}
else
if
(
type
===
"
iv
"
)
{
// flat array of integers with 3 x N size (JS or typed array)
renderer
.
uniform3iv
(
location
,
value
);
}
else
if
(
type
===
"
fv1
"
)
{
// flat array of floats (JS or typed array)
renderer
.
uniform1fv
(
location
,
value
);
}
else
if
(
type
===
"
fv
"
)
{
// flat array of floats with 3 x N size (JS or typed array)
renderer
.
uniform3fv
(
location
,
value
);
}
else
if
(
type
===
"
v2v
"
)
{
// array of THREE.Vector2
if
(
uniform
.
_array
===
undefined
)
{
uniform
.
_array
=
new
Float32Array
(
2
*
value
.
length
);
}
for
(
i
=
0
,
il
=
value
.
length
;
i
<
il
;
i
++
)
{
offset
=
i
*
2
;
uniform
.
_array
[
offset
]
=
value
[
i
].
x
;
uniform
.
_array
[
offset
+
1
]
=
value
[
i
].
y
;
}
renderer
.
uniform2fv
(
location
,
uniform
.
_array
);
}
else
if
(
type
===
"
v3v
"
)
{
// array of THREE.Vector3
if
(
uniform
.
_array
===
undefined
)
{
uniform
.
_array
=
new
Float32Array
(
3
*
value
.
length
);
}
for
(
i
=
0
,
il
=
value
.
length
;
i
<
il
;
i
++
)
{
offset
=
i
*
3
;
uniform
.
_array
[
offset
]
=
value
[
i
].
x
;
uniform
.
_array
[
offset
+
1
]
=
value
[
i
].
y
;
uniform
.
_array
[
offset
+
2
]
=
value
[
i
].
z
;
}
renderer
.
uniform3fv
(
location
,
uniform
.
_array
);
}
else
if
(
type
===
"
v4v
"
)
{
// array of THREE.Vector4
if
(
uniform
.
_array
===
undefined
)
{
uniform
.
_array
=
new
Float32Array
(
4
*
value
.
length
);
}
for
(
i
=
0
,
il
=
value
.
length
;
i
<
il
;
i
++
)
{
offset
=
i
*
4
;
uniform
.
_array
[
offset
]
=
value
[
i
].
x
;
uniform
.
_array
[
offset
+
1
]
=
value
[
i
].
y
;
uniform
.
_array
[
offset
+
2
]
=
value
[
i
].
z
;
uniform
.
_array
[
offset
+
3
]
=
value
[
i
].
w
;
}
renderer
.
uniform4fv
(
location
,
uniform
.
_array
);
}
else
if
(
type
===
"
m4
"
)
{
// single THREE.Matrix4
if
(
uniform
.
_array
===
undefined
)
{
uniform
.
_array
=
new
Float32Array
(
16
);
}
value
.
flattenToArray
(
uniform
.
_array
);
renderer
.
uniformMatrix4fv
(
location
,
uniform
.
_array
);
}
else
if
(
type
===
"
m4v
"
)
{
// array of THREE.Matrix4
if
(
uniform
.
_array
===
undefined
)
{
uniform
.
_array
=
new
Float32Array
(
16
*
value
.
length
);
}
for
(
i
=
0
,
il
=
value
.
length
;
i
<
il
;
i
++
)
{
value
[
i
].
flattenToArrayOffset
(
uniform
.
_array
,
i
*
16
);
}
renderer
.
uniformMatrix4fv
(
location
,
uniform
.
_array
);
}
else
if
(
type
===
"
t
"
)
{
// single THREE.Texture (2d or cube)
texture
=
value
;
textureUnit
=
getTextureUnit
();
renderer
.
uniform1i
(
location
,
textureUnit
);
if
(
!
texture
)
continue
;
if
(
texture
.
image
instanceof
Array
&&
texture
.
image
.
length
===
6
)
{
renderer
.
setCubeTexture
(
texture
,
textureUnit
);
}
else
if
(
texture
instanceof
THREE
.
WebGLRenderTargetCube
)
{
renderer
.
setCubeTextureDynamic
(
texture
,
textureUnit
);
}
else
{
renderer
.
setTexture
(
texture
,
textureUnit
);
}
}
else
if
(
type
===
"
tv
"
)
{
// array of THREE.Texture (2d)
if
(
uniform
.
_array
===
undefined
)
{
uniform
.
_array
=
[];
}
for
(
i
=
0
,
il
=
uniform
.
value
.
length
;
i
<
il
;
i
++
)
{
uniform
.
_array
[
i
]
=
getTextureUnit
();
}
renderer
.
uniform1iv
(
location
,
uniform
.
_array
);
for
(
i
=
0
,
il
=
uniform
.
value
.
length
;
i
<
il
;
i
++
)
{
texture
=
uniform
.
value
[
i
];
textureUnit
=
uniform
.
_array
[
i
];
if
(
!
texture
)
continue
;
renderer
.
setTexture
(
texture
,
textureUnit
);
}
}
}
};
function
setupMatrices
(
object
,
camera
)
{
object
.
_modelViewMatrix
.
multiply
(
camera
.
matrixWorldInverse
,
object
.
matrixWorld
);
object
.
_normalMatrix
.
getInverse
(
object
.
_modelViewMatrix
);
object
.
_normalMatrix
.
transpose
();
};
//
function
setColorGamma
(
array
,
offset
,
color
,
intensitySq
)
{
array
[
offset
]
=
color
.
r
*
color
.
r
*
intensitySq
;
array
[
offset
+
1
]
=
color
.
g
*
color
.
g
*
intensitySq
;
array
[
offset
+
2
]
=
color
.
b
*
color
.
b
*
intensitySq
;
};
function
setColorLinear
(
array
,
offset
,
color
,
intensity
)
{
array
[
offset
]
=
color
.
r
*
intensity
;
array
[
offset
+
1
]
=
color
.
g
*
intensity
;
array
[
offset
+
2
]
=
color
.
b
*
intensity
;
};
function
setupLights
(
program
,
lights
)
{
var
l
,
ll
,
light
,
n
,
r
=
0
,
g
=
0
,
b
=
0
,
color
,
skyColor
,
groundColor
,
intensity
,
intensitySq
,
position
,
distance
,
zlights
=
_lights
,
dirColors
=
zlights
.
directional
.
colors
,
dirPositions
=
zlights
.
directional
.
positions
,
pointColors
=
zlights
.
point
.
colors
,
pointPositions
=
zlights
.
point
.
positions
,
pointDistances
=
zlights
.
point
.
distances
,
spotColors
=
zlights
.
spot
.
colors
,
spotPositions
=
zlights
.
spot
.
positions
,
spotDistances
=
zlights
.
spot
.
distances
,
spotDirections
=
zlights
.
spot
.
directions
,
spotAnglesCos
=
zlights
.
spot
.
anglesCos
,
spotExponents
=
zlights
.
spot
.
exponents
,
hemiSkyColors
=
zlights
.
hemi
.
skyColors
,
hemiGroundColors
=
zlights
.
hemi
.
groundColors
,
hemiPositions
=
zlights
.
hemi
.
positions
,
dirLength
=
0
,
pointLength
=
0
,
spotLength
=
0
,
hemiLength
=
0
,
dirCount
=
0
,
pointCount
=
0
,
spotCount
=
0
,
hemiCount
=
0
,
dirOffset
=
0
,
pointOffset
=
0
,
spotOffset
=
0
,
hemiOffset
=
0
;
for
(
l
=
0
,
ll
=
lights
.
length
;
l
<
ll
;
l
++
)
{
light
=
lights
[
l
];
if
(
light
.
onlyShadow
)
continue
;
color
=
light
.
color
;
intensity
=
light
.
intensity
;
distance
=
light
.
distance
;
if
(
light
instanceof
THREE
.
AmbientLight
)
{
if
(
!
light
.
visible
)
continue
;
if
(
_this
.
gammaInput
)
{
r
+=
color
.
r
*
color
.
r
;
g
+=
color
.
g
*
color
.
g
;
b
+=
color
.
b
*
color
.
b
;
}
else
{
r
+=
color
.
r
;
g
+=
color
.
g
;
b
+=
color
.
b
;
}
}
else
if
(
light
instanceof
THREE
.
DirectionalLight
)
{
dirCount
+=
1
;
if
(
!
light
.
visible
)
continue
;
_direction
.
copy
(
light
.
matrixWorld
.
getPosition
()
);
_direction
.
subSelf
(
light
.
target
.
matrixWorld
.
getPosition
()
);
_direction
.
normalize
();
// skip lights with undefined direction
// these create troubles in OpenGL (making pixel black)
if
(
_direction
.
x
===
0
&&
_direction
.
y
===
0
&&
_direction
.
z
===
0
)
continue
;
dirOffset
=
dirLength
*
3
;
dirPositions
[
dirOffset
]
=
_direction
.
x
;
dirPositions
[
dirOffset
+
1
]
=
_direction
.
y
;
dirPositions
[
dirOffset
+
2
]
=
_direction
.
z
;
if
(
_this
.
gammaInput
)
{
setColorGamma
(
dirColors
,
dirOffset
,
color
,
intensity
*
intensity
);
}
else
{
setColorLinear
(
dirColors
,
dirOffset
,
color
,
intensity
);
}
dirLength
+=
1
;
}
else
if
(
light
instanceof
THREE
.
PointLight
)
{
pointCount
+=
1
;
if
(
!
light
.
visible
)
continue
;
pointOffset
=
pointLength
*
3
;
if
(
_this
.
gammaInput
)
{
setColorGamma
(
pointColors
,
pointOffset
,
color
,
intensity
*
intensity
);
}
else
{
setColorLinear
(
pointColors
,
pointOffset
,
color
,
intensity
);
}
position
=
light
.
matrixWorld
.
getPosition
();
pointPositions
[
pointOffset
]
=
position
.
x
;
pointPositions
[
pointOffset
+
1
]
=
position
.
y
;
pointPositions
[
pointOffset
+
2
]
=
position
.
z
;
pointDistances
[
pointLength
]
=
distance
;
pointLength
+=
1
;
}
else
if
(
light
instanceof
THREE
.
SpotLight
)
{
spotCount
+=
1
;
if
(
!
light
.
visible
)
continue
;
spotOffset
=
spotLength
*
3
;
if
(
_this
.
gammaInput
)
{
setColorGamma
(
spotColors
,
spotOffset
,
color
,
intensity
*
intensity
);
}
else
{
setColorLinear
(
spotColors
,
spotOffset
,
color
,
intensity
);
}
position
=
light
.
matrixWorld
.
getPosition
();
spotPositions
[
spotOffset
]
=
position
.
x
;
spotPositions
[
spotOffset
+
1
]
=
position
.
y
;
spotPositions
[
spotOffset
+
2
]
=
position
.
z
;
spotDistances
[
spotLength
]
=
distance
;
_direction
.
copy
(
position
);
_direction
.
subSelf
(
light
.
target
.
matrixWorld
.
getPosition
()
);
_direction
.
normalize
();
spotDirections
[
spotOffset
]
=
_direction
.
x
;
spotDirections
[
spotOffset
+
1
]
=
_direction
.
y
;
spotDirections
[
spotOffset
+
2
]
=
_direction
.
z
;
spotAnglesCos
[
spotLength
]
=
Math
.
cos
(
light
.
angle
);
spotExponents
[
spotLength
]
=
light
.
exponent
;
spotLength
+=
1
;
}
else
if
(
light
instanceof
THREE
.
HemisphereLight
)
{
hemiCount
+=
1
;
if
(
!
light
.
visible
)
continue
;
_direction
.
copy
(
light
.
matrixWorld
.
getPosition
()
);
_direction
.
normalize
();
// skip lights with undefined direction
// these create troubles in OpenGL (making pixel black)
if
(
_direction
.
x
===
0
&&
_direction
.
y
===
0
&&
_direction
.
z
===
0
)
continue
;
hemiOffset
=
hemiLength
*
3
;
hemiPositions
[
hemiOffset
]
=
_direction
.
x
;
hemiPositions
[
hemiOffset
+
1
]
=
_direction
.
y
;
hemiPositions
[
hemiOffset
+
2
]
=
_direction
.
z
;
skyColor
=
light
.
color
;
groundColor
=
light
.
groundColor
;
if
(
_this
.
gammaInput
)
{
intensitySq
=
intensity
*
intensity
;
setColorGamma
(
hemiSkyColors
,
hemiOffset
,
skyColor
,
intensitySq
);
setColorGamma
(
hemiGroundColors
,
hemiOffset
,
groundColor
,
intensitySq
);
}
else
{
setColorLinear
(
hemiSkyColors
,
hemiOffset
,
skyColor
,
intensity
);
setColorLinear
(
hemiGroundColors
,
hemiOffset
,
groundColor
,
intensity
);
}
hemiLength
+=
1
;
}
}
// null eventual remains from removed lights
// (this is to avoid if in shader)
for
(
l
=
dirLength
*
3
,
ll
=
Math
.
max
(
dirColors
.
length
,
dirCount
*
3
);
l
<
ll
;
l
++
)
dirColors
[
l
]
=
0.0
;
for
(
l
=
pointLength
*
3
,
ll
=
Math
.
max
(
pointColors
.
length
,
pointCount
*
3
);
l
<
ll
;
l
++
)
pointColors
[
l
]
=
0.0
;
for
(
l
=
spotLength
*
3
,
ll
=
Math
.
max
(
spotColors
.
length
,
spotCount
*
3
);
l
<
ll
;
l
++
)
spotColors
[
l
]
=
0.0
;
for
(
l
=
hemiLength
*
3
,
ll
=
Math
.
max
(
hemiSkyColors
.
length
,
hemiCount
*
3
);
l
<
ll
;
l
++
)
hemiSkyColors
[
l
]
=
0.0
;
for
(
l
=
hemiLength
*
3
,
ll
=
Math
.
max
(
hemiGroundColors
.
length
,
hemiCount
*
3
);
l
<
ll
;
l
++
)
hemiGroundColors
[
l
]
=
0.0
;
zlights
.
directional
.
length
=
dirLength
;
zlights
.
point
.
length
=
pointLength
;
zlights
.
spot
.
length
=
spotLength
;
zlights
.
hemi
.
length
=
hemiLength
;
zlights
.
ambient
[
0
]
=
r
;
zlights
.
ambient
[
1
]
=
g
;
zlights
.
ambient
[
2
]
=
b
;
};
// Allocations
function
allocateBones
(
object
)
{
if
(
renderer
.
supportsBoneTextures
&&
object
&&
object
.
useVertexTexture
)
{
return
1024
;
}
else
{
// 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)
var
nVertexUniforms
=
renderer
.
maxVertexUniformVectors
var
nVertexMatrices
=
Math
.
floor
(
(
nVertexUniforms
-
20
)
/
4
);
var
maxBones
=
nVertexMatrices
;
if
(
object
!==
undefined
&&
object
instanceof
THREE
.
SkinnedMesh
)
{
maxBones
=
Math
.
min
(
object
.
bones
.
length
,
maxBones
);
if
(
maxBones
<
object
.
bones
.
length
)
{
console
.
warn
(
"
WebGLRenderer: too many bones -
"
+
object
.
bones
.
length
+
"
, this GPU supports just
"
+
maxBones
+
"
(try OpenGL instead of ANGLE)
"
);
}
}
return
maxBones
;
}
};
function
allocateLights
(
lights
)
{
var
l
,
ll
,
light
,
dirLights
,
pointLights
,
spotLights
,
hemiLights
;
dirLights
=
pointLights
=
spotLights
=
hemiLights
=
0
;
for
(
l
=
0
,
ll
=
lights
.
length
;
l
<
ll
;
l
++
)
{
light
=
lights
[
l
];
if
(
light
.
onlyShadow
)
continue
;
if
(
light
instanceof
THREE
.
DirectionalLight
)
dirLights
++
;
if
(
light
instanceof
THREE
.
PointLight
)
pointLights
++
;
if
(
light
instanceof
THREE
.
SpotLight
)
spotLights
++
;
if
(
light
instanceof
THREE
.
HemisphereLight
)
hemiLights
++
;
}
return
{
'
directional
'
:
dirLights
,
'
point
'
:
pointLights
,
'
spot
'
:
spotLights
,
'
hemi
'
:
hemiLights
};
};
function
allocateShadows
(
lights
)
{
var
l
,
ll
,
light
,
maxShadows
=
0
;
for
(
l
=
0
,
ll
=
lights
.
length
;
l
<
ll
;
l
++
)
{
light
=
lights
[
l
];
if
(
!
light
.
castShadow
)
continue
;
if
(
light
instanceof
THREE
.
SpotLight
)
maxShadows
++
;
if
(
light
instanceof
THREE
.
DirectionalLight
&&
!
light
.
shadowCascade
)
maxShadows
++
;
}
return
maxShadows
;
};
// default plugins (order is important)
this
.
shadowMapPlugin
=
new
THREE
.
ShadowMapPlugin
();
this
.
addPrePlugin
(
this
.
shadowMapPlugin
);
this
.
addPostPlugin
(
new
THREE
.
SpritePlugin
()
);
this
.
addPostPlugin
(
new
THREE
.
LensFlarePlugin
()
);
};
src/renderers/webgl/LowLevelRenderer.js
0 → 100644
浏览文件 @
1efe37f9
/*global THREE:false */
THREE
.
WebGLRenderer2
.
LowLevelRenderer
=
function
(
parameters
){
parameters
=
parameters
||
{};
var
_canvas
=
parameters
.
canvas
!==
undefined
?
parameters
.
canvas
:
document
.
createElement
(
'
canvas
'
),
_precision
=
parameters
.
precision
!==
undefined
?
parameters
.
precision
:
'
highp
'
,
_alpha
=
parameters
.
alpha
!==
undefined
?
parameters
.
alpha
:
true
,
_premultipliedAlpha
=
parameters
.
premultipliedAlpha
!==
undefined
?
parameters
.
premultipliedAlpha
:
true
,
_antialias
=
parameters
.
antialias
!==
undefined
?
parameters
.
antialias
:
false
,
_stencil
=
parameters
.
stencil
!==
undefined
?
parameters
.
stencil
:
true
,
_preserveDrawingBuffer
=
parameters
.
preserveDrawingBuffer
!==
undefined
?
parameters
.
preserveDrawingBuffer
:
false
,
_clearColor
=
parameters
.
clearColor
!==
undefined
?
new
THREE
.
Color
(
parameters
.
clearColor
)
:
new
THREE
.
Color
(
0x000000
),
_clearAlpha
=
parameters
.
clearAlpha
!==
undefined
?
parameters
.
clearAlpha
:
0
,
_autoScaleCubemaps
=
true
;
this
.
devicePixelRatio
=
parameters
.
devicePixelRatio
!==
undefined
?
parameters
.
devicePixelRatio
:
window
.
devicePixelRatio
!==
undefined
?
window
.
devicePixelRatio
:
1
;
var
_currentWidth
=
0
,
_currentHeight
=
0
;
var
_gl
;
var
_glExtensionTextureFloat
;
var
_glExtensionStandardDerivatives
;
var
_glExtensionTextureFilterAnisotropic
;
var
_glExtensionCompressedTextureS3TC
;
initGL
();
setDefaultGLState
();
var
_maxTextures
=
_gl
.
getParameter
(
_gl
.
MAX_TEXTURE_IMAGE_UNITS
);
var
_maxVertexTextures
=
_gl
.
getParameter
(
_gl
.
MAX_VERTEX_TEXTURE_IMAGE_UNITS
);
var
_maxTextureSize
=
_gl
.
getParameter
(
_gl
.
MAX_TEXTURE_SIZE
);
var
_maxCubemapSize
=
_gl
.
getParameter
(
_gl
.
MAX_CUBE_MAP_TEXTURE_SIZE
);
var
_maxAnisotropy
=
_glExtensionTextureFilterAnisotropic
?
_gl
.
getParameter
(
_glExtensionTextureFilterAnisotropic
.
MAX_TEXTURE_MAX_ANISOTROPY_EXT
)
:
0
;
var
_supportsVertexTextures
=
(
_maxVertexTextures
>
0
);
var
_supportsBoneTextures
=
_supportsVertexTextures
&&
_glExtensionTextureFloat
;
var
_compressedTextureFormats
=
_glExtensionCompressedTextureS3TC
?
_gl
.
getParameter
(
_gl
.
COMPRESSED_TEXTURE_FORMATS
)
:
[];
var
_vertexShaderPrecisionHighpFloat
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
VERTEX_SHADER
,
_gl
.
HIGH_FLOAT
);
var
_vertexShaderPrecisionMediumpFloat
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
VERTEX_SHADER
,
_gl
.
MEDIUM_FLOAT
);
var
_vertexShaderPrecisionLowpFloat
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
VERTEX_SHADER
,
_gl
.
LOW_FLOAT
);
var
_fragmentShaderPrecisionHighpFloat
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
FRAGMENT_SHADER
,
_gl
.
HIGH_FLOAT
);
var
_fragmentShaderPrecisionMediumpFloat
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
FRAGMENT_SHADER
,
_gl
.
MEDIUM_FLOAT
);
var
_fragmentShaderPrecisionLowpFloat
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
FRAGMENT_SHADER
,
_gl
.
LOW_FLOAT
);
var
_vertexShaderPrecisionHighpInt
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
VERTEX_SHADER
,
_gl
.
HIGH_INT
);
var
_vertexShaderPrecisionMediumpInt
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
VERTEX_SHADER
,
_gl
.
MEDIUM_INT
);
var
_vertexShaderPrecisionLowpInt
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
VERTEX_SHADER
,
_gl
.
LOW_INT
);
var
_fragmentShaderPrecisionHighpInt
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
FRAGMENT_SHADER
,
_gl
.
HIGH_INT
);
var
_fragmentShaderPrecisionMediumpInt
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
FRAGMENT_SHADER
,
_gl
.
MEDIUM_INT
);
var
_fragmentShaderPrecisionLowpInt
=
_gl
.
getShaderPrecisionFormat
(
_gl
.
FRAGMENT_SHADER
,
_gl
.
LOW_INT
);
// clamp precision to maximum available
var
highpAvailable
=
_vertexShaderPrecisionHighpFloat
.
precision
>
0
&&
_fragmentShaderPrecisionHighpFloat
.
precision
>
0
;
var
mediumpAvailable
=
_vertexShaderPrecisionMediumpFloat
.
precision
>
0
&&
_fragmentShaderPrecisionMediumpFloat
.
precision
>
0
;
if
(
_precision
===
"
highp
"
&&
!
highpAvailable
)
{
if
(
mediumpAvailable
)
{
_precision
=
"
mediump
"
;
console
.
warn
(
"
WebGLRenderer: highp not supported, using mediump
"
);
}
else
{
_precision
=
"
lowp
"
;
console
.
warn
(
"
WebGLRenderer: highp and mediump not supported, using lowp
"
);
}
}
if
(
_precision
===
"
mediump
"
&&
!
mediumpAvailable
)
{
_precision
=
"
lowp
"
;
console
.
warn
(
"
WebGLRenderer: mediump not supported, using lowp
"
);
}
var
_enabledAttributes
=
{},
_oldBlending
,
_oldBlendEquation
,
_oldBlendSrc
,
_oldBlendDst
,
_oldDoubleSided
=
-
1
,
_oldFlipSided
=
-
1
,
_oldDepthTest
=
-
1
,
_oldDepthWrite
=
-
1
,
_oldLineWidth
=
-
1
,
_viewportX
=
0
,
_viewportY
=
0
,
_viewportWidth
=
0
,
_viewportHeight
=
0
,
// GL state cache
_oldPolygonOffset
=
null
,
_oldPolygonOffsetFactor
=
null
,
_oldPolygonOffsetUnits
=
null
,
_currentFramebuffer
=
null
;
function
initGL
()
{
try
{
if
(
!
(
_gl
=
_canvas
.
getContext
(
'
experimental-webgl
'
,
{
alpha
:
_alpha
,
premultipliedAlpha
:
_premultipliedAlpha
,
antialias
:
_antialias
,
stencil
:
_stencil
,
preserveDrawingBuffer
:
_preserveDrawingBuffer
}
)
)
)
{
throw
'
Error creating WebGL context.
'
;
}
}
catch
(
error
)
{
console
.
error
(
error
);
}
_glExtensionTextureFloat
=
_gl
.
getExtension
(
'
OES_texture_float
'
);
_glExtensionStandardDerivatives
=
_gl
.
getExtension
(
'
OES_standard_derivatives
'
);
_glExtensionTextureFilterAnisotropic
=
_gl
.
getExtension
(
'
EXT_texture_filter_anisotropic
'
)
||
_gl
.
getExtension
(
'
MOZ_EXT_texture_filter_anisotropic
'
)
||
_gl
.
getExtension
(
'
WEBKIT_EXT_texture_filter_anisotropic
'
);
_glExtensionCompressedTextureS3TC
=
_gl
.
getExtension
(
'
WEBGL_compressed_texture_s3tc
'
)
||
_gl
.
getExtension
(
'
MOZ_WEBGL_compressed_texture_s3tc
'
)
||
_gl
.
getExtension
(
'
WEBKIT_WEBGL_compressed_texture_s3tc
'
);
if
(
!
_glExtensionTextureFloat
)
{
console
.
log
(
'
THREE.WebGLRenderer: Float textures not supported.
'
);
}
if
(
!
_glExtensionStandardDerivatives
)
{
console
.
log
(
'
THREE.WebGLRenderer: Standard derivatives not supported.
'
);
}
if
(
!
_glExtensionTextureFilterAnisotropic
)
{
console
.
log
(
'
THREE.WebGLRenderer: Anisotropic texture filtering not supported.
'
);
}
if
(
!
_glExtensionCompressedTextureS3TC
)
{
console
.
log
(
'
THREE.WebGLRenderer: S3TC compressed textures not supported.
'
);
}
};
function
setDefaultGLState
()
{
_gl
.
clearColor
(
0
,
0
,
0
,
1
);
_gl
.
clearDepth
(
1
);
_gl
.
clearStencil
(
0
);
_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
.
blendEquation
(
_gl
.
FUNC_ADD
);
_gl
.
blendFunc
(
_gl
.
SRC_ALPHA
,
_gl
.
ONE_MINUS_SRC_ALPHA
);
_gl
.
clearColor
(
_clearColor
.
r
,
_clearColor
.
g
,
_clearColor
.
b
,
_clearAlpha
);
};
// Fallback filters for non-power-of-2 textures
function
filterFallback
(
f
)
{
if
(
f
===
THREE
.
NearestFilter
||
f
===
THREE
.
NearestMipMapNearestFilter
||
f
===
THREE
.
NearestMipMapLinearFilter
)
{
return
_gl
.
NEAREST
;
}
return
_gl
.
LINEAR
;
};
function
getContext
()
{
return
_gl
;
};
function
getDomElement
(){
return
_canvas
;
};
function
getPrecision
()
{
return
_precision
;
};
function
getCurrentWidth
(){
return
_currentWidth
;
};
function
getCurrentHeight
(){
return
_currentHeight
;
};
function
supportsVertexTextures
()
{
return
_supportsVertexTextures
;
};
function
getMaxAnisotropy
()
{
return
_maxAnisotropy
;
};
function
setSize
(
width
,
height
)
{
_canvas
.
width
=
width
;
_canvas
.
height
=
height
;
setViewport
(
0
,
0
,
_canvas
.
width
,
_canvas
.
height
);
};
function
setViewport
(
x
,
y
,
width
,
height
)
{
_viewportX
=
x
!==
undefined
?
x
:
0
;
_viewportY
=
y
!==
undefined
?
y
:
0
;
_viewportWidth
=
width
!==
undefined
?
width
:
_canvas
.
width
;
_viewportHeight
=
height
!==
undefined
?
height
:
_canvas
.
height
;
_gl
.
viewport
(
_viewportX
,
_viewportY
,
_viewportWidth
,
_viewportHeight
);
};
function
setScissor
(
x
,
y
,
width
,
height
)
{
_gl
.
scissor
(
x
,
y
,
width
,
height
);
};
function
enableScissorTest
(
enable
)
{
enable
?
_gl
.
enable
(
_gl
.
SCISSOR_TEST
)
:
_gl
.
disable
(
_gl
.
SCISSOR_TEST
);
};
// Clearing
function
setClearColorHex
(
hex
,
alpha
)
{
_clearColor
.
setHex
(
hex
);
_clearAlpha
=
alpha
;
_gl
.
clearColor
(
_clearColor
.
r
,
_clearColor
.
g
,
_clearColor
.
b
,
_clearAlpha
);
};
function
setClearColor
(
color
,
alpha
)
{
_clearColor
.
copy
(
color
);
_clearAlpha
=
alpha
;
_gl
.
clearColor
(
_clearColor
.
r
,
_clearColor
.
g
,
_clearColor
.
b
,
_clearAlpha
);
};
function
getClearColor
()
{
return
_clearColor
;
};
function
getClearAlpha
()
{
return
_clearAlpha
;
};
function
clear
(
color
,
depth
,
stencil
)
{
var
bits
=
0
;
if
(
color
===
undefined
||
color
)
bits
|=
_gl
.
COLOR_BUFFER_BIT
;
if
(
depth
===
undefined
||
depth
)
bits
|=
_gl
.
DEPTH_BUFFER_BIT
;
if
(
stencil
===
undefined
||
stencil
)
bits
|=
_gl
.
STENCIL_BUFFER_BIT
;
_gl
.
clear
(
bits
);
};
function
clearTarget
(
renderTarget
,
color
,
depth
,
stencil
)
{
setRenderTarget
(
renderTarget
);
clear
(
color
,
depth
,
stencil
);
};
function
deleteBuffer
(
buffer
){
_gl
.
deleteBuffer
(
buffer
);
};
function
deleteTexture
(
texture
){
_gl
.
deleteTexture
(
texture
);
};
function
deleteFramebuffer
(
Framebuffer
){
_gl
.
deleteFramebuffer
(
Framebuffer
);
};
function
deleteRenderbuffer
(
RenderBuffer
){
_gl
.
deleteRenderbuffer
(
RenderBuffer
);
};
function
deleteProgram
(
RenderBuffer
){
_gl
.
deleteProgram
(
RenderBuffer
);
};
function
createBuffer
(){
return
_gl
.
createBuffer
();
};
function
setStaticArrayBuffer
(
buffer
,
data
){
bindArrayBuffer
(
buffer
);
_gl
.
bufferData
(
_gl
.
ARRAY_BUFFER
,
data
,
_gl
.
STATIC_DRAW
);
};
function
setStaticIndexBuffer
(
buffer
,
data
){
bindElementArrayBuffer
(
buffer
);
_gl
.
bufferData
(
_gl
.
ELEMENT_ARRAY_BUFFER
,
data
,
_gl
.
STATIC_DRAW
);
};
function
setDynamicArrayBuffer
(
buffer
,
data
){
bindArrayBuffer
(
buffer
);
_gl
.
bufferData
(
_gl
.
ARRAY_BUFFER
,
data
,
_gl
.
DYNAMIC_DRAW
);
};
function
setDynamicIndexBuffer
(
buffer
,
data
){
bindElementArrayBuffer
(
buffer
);
_gl
.
bufferData
(
_gl
.
ELEMENT_ARRAY_BUFFER
,
data
,
_gl
.
DYNAMIC_DRAW
);
};
function
drawTriangles
(
count
){
_gl
.
drawArrays
(
_gl
.
TRIANGLES
,
0
,
count
);
};
function
drawTriangleStrip
(
count
){
_gl
.
drawArrays
(
_gl
.
TRIANGLE_STRIP
,
0
,
count
);
};
function
drawLines
(
count
){
_gl
.
drawArrays
(
_gl
.
LINES
,
0
,
count
);
};
function
drawLineStrip
(
count
){
_gl
.
drawArrays
(
_gl
.
LINE_STRIP
,
0
,
count
);
};
function
drawPoints
(
count
){
_gl
.
drawArrays
(
_gl
.
POINTS
,
0
,
count
);
};
function
drawTriangleElements
(
buffer
,
count
,
offset
){
bindElementArrayBuffer
(
buffer
);
_gl
.
drawElements
(
_gl
.
TRIANGLES
,
count
,
_gl
.
UNSIGNED_SHORT
,
offset
);
// 2 bytes per Uint16
};
function
drawLineElements
(
buffer
,
count
,
offset
){
bindElementArrayBuffer
(
buffer
);
_gl
.
drawElements
(
_gl
.
LINES
,
count
,
_gl
.
UNSIGNED_SHORT
,
offset
);
// 2 bytes per Uint16
};
var
_boundBuffer
;
function
bindArrayBuffer
(
buffer
){
if
(
_boundBuffer
!=
buffer
){
_gl
.
bindBuffer
(
_gl
.
ARRAY_BUFFER
,
buffer
);
_boundBuffer
=
buffer
;
}
};
function
bindElementArrayBuffer
(
buffer
){
if
(
_boundBuffer
!=
buffer
){
_gl
.
bindBuffer
(
_gl
.
ELEMENT_ARRAY_BUFFER
,
buffer
);
_boundBuffer
=
buffer
;
}
};
function
enableAttribute
(
attribute
)
{
if
(
!
_enabledAttributes
[
attribute
]
)
{
_gl
.
enableVertexAttribArray
(
attribute
);
_enabledAttributes
[
attribute
]
=
true
;
}
};
function
disableAttributes
()
{
for
(
var
attribute
in
_enabledAttributes
)
{
if
(
_enabledAttributes
[
attribute
]
)
{
_gl
.
disableVertexAttribArray
(
attribute
);
_enabledAttributes
[
attribute
]
=
false
;
}
}
};
function
getAttribLocation
(
program
,
id
){
return
_gl
.
getAttribLocation
(
program
,
id
);
}
function
setFloatAttribute
(
index
,
buffer
,
size
,
offset
){
bindArrayBuffer
(
buffer
);
enableAttribute
(
index
);
_gl
.
vertexAttribPointer
(
index
,
size
,
_gl
.
FLOAT
,
false
,
0
,
offset
);
};
function
getUniformLocation
(
program
,
id
){
return
_gl
.
getUniformLocation
(
program
,
id
);
}
function
uniform1i
(
uniform
,
value
){
_gl
.
uniform1i
(
uniform
,
value
);
};
function
uniform1f
(
uniform
,
value
){
_gl
.
uniform1f
(
uniform
,
value
);
};
function
uniform2f
(
uniform
,
value1
,
value2
){
_gl
.
uniform2f
(
uniform
,
value1
,
value2
);
};
function
uniform3f
(
uniform
,
value1
,
value2
,
value3
){
_gl
.
uniform3f
(
uniform
,
value1
,
value2
,
value3
);
};
function
uniform4f
(
uniform
,
value1
,
value2
,
value3
,
value4
){
_gl
.
uniform4f
(
uniform
,
value1
,
value2
,
value3
,
value4
);
};
function
uniform1iv
(
uniform
,
value
){
_gl
.
uniform1iv
(
uniform
,
value
);
};
function
uniform2iv
(
uniform
,
value
){
_gl
.
uniform2iv
(
uniform
,
value
);
};
function
uniform3iv
(
uniform
,
value
){
_gl
.
uniform3iv
(
uniform
,
value
);
};
function
uniform1fv
(
uniform
,
value
){
_gl
.
uniform1fv
(
uniform
,
value
);
};
function
uniform2fv
(
uniform
,
value
){
_gl
.
uniform2fv
(
uniform
,
value
);
};
function
uniform3fv
(
uniform
,
value
){
_gl
.
uniform3fv
(
uniform
,
value
);
};
function
uniform4fv
(
uniform
,
value
){
_gl
.
uniform3fv
(
uniform
,
value
);
};
function
uniformMatrix3fv
(
location
,
value
){
_gl
.
uniformMatrix3fv
(
location
,
false
,
value
);
};
function
uniformMatrix4fv
(
location
,
value
){
_gl
.
uniformMatrix4fv
(
location
,
false
,
value
);
};
function
useProgram
(
program
){
_gl
.
useProgram
(
program
);
};
function
setFaceCulling
(
cullFace
,
frontFaceDirection
)
{
if
(
cullFace
===
THREE
.
CullFaceNone
)
{
_gl
.
disable
(
_gl
.
CULL_FACE
);
}
else
{
if
(
frontFaceDirection
===
THREE
.
FrontFaceDirectionCW
)
{
_gl
.
frontFace
(
_gl
.
CW
);
}
else
{
_gl
.
frontFace
(
_gl
.
CCW
);
}
if
(
cullFace
===
THREE
.
CullFaceBack
)
{
_gl
.
cullFace
(
_gl
.
BACK
);
}
else
if
(
cullFace
===
THREE
.
CullFaceFront
)
{
_gl
.
cullFace
(
_gl
.
FRONT
);
}
else
{
_gl
.
cullFace
(
_gl
.
FRONT_AND_BACK
);
}
_gl
.
enable
(
_gl
.
CULL_FACE
);
}
};
function
setMaterialFaces
(
material
)
{
var
doubleSided
=
material
.
side
===
THREE
.
DoubleSide
;
var
flipSided
=
material
.
side
===
THREE
.
BackSide
;
if
(
_oldDoubleSided
!==
doubleSided
)
{
if
(
doubleSided
)
{
_gl
.
disable
(
_gl
.
CULL_FACE
);
}
else
{
_gl
.
enable
(
_gl
.
CULL_FACE
);
}
_oldDoubleSided
=
doubleSided
;
}
if
(
_oldFlipSided
!==
flipSided
)
{
if
(
flipSided
)
{
_gl
.
frontFace
(
_gl
.
CW
);
}
else
{
_gl
.
frontFace
(
_gl
.
CCW
);
}
_oldFlipSided
=
flipSided
;
}
};
function
setPolygonOffset
(
polygonoffset
,
factor
,
units
)
{
if
(
_oldPolygonOffset
!==
polygonoffset
)
{
if
(
polygonoffset
)
{
_gl
.
enable
(
_gl
.
POLYGON_OFFSET_FILL
);
}
else
{
_gl
.
disable
(
_gl
.
POLYGON_OFFSET_FILL
);
}
_oldPolygonOffset
=
polygonoffset
;
}
if
(
polygonoffset
&&
(
_oldPolygonOffsetFactor
!==
factor
||
_oldPolygonOffsetUnits
!==
units
)
)
{
_gl
.
polygonOffset
(
factor
,
units
);
_oldPolygonOffsetFactor
=
factor
;
_oldPolygonOffsetUnits
=
units
;
}
};
function
setBlending
(
blending
,
blendEquation
,
blendSrc
,
blendDst
)
{
if
(
blending
!==
_oldBlending
)
{
if
(
blending
===
THREE
.
NoBlending
)
{
_gl
.
disable
(
_gl
.
BLEND
);
}
else
if
(
blending
===
THREE
.
AdditiveBlending
)
{
_gl
.
enable
(
_gl
.
BLEND
);
_gl
.
blendEquation
(
_gl
.
FUNC_ADD
);
_gl
.
blendFunc
(
_gl
.
SRC_ALPHA
,
_gl
.
ONE
);
}
else
if
(
blending
===
THREE
.
SubtractiveBlending
)
{
// TODO: Find blendFuncSeparate() combination
_gl
.
enable
(
_gl
.
BLEND
);
_gl
.
blendEquation
(
_gl
.
FUNC_ADD
);
_gl
.
blendFunc
(
_gl
.
ZERO
,
_gl
.
ONE_MINUS_SRC_COLOR
);
}
else
if
(
blending
===
THREE
.
MultiplyBlending
)
{
// TODO: Find blendFuncSeparate() combination
_gl
.
enable
(
_gl
.
BLEND
);
_gl
.
blendEquation
(
_gl
.
FUNC_ADD
);
_gl
.
blendFunc
(
_gl
.
ZERO
,
_gl
.
SRC_COLOR
);
}
else
if
(
blending
===
THREE
.
CustomBlending
)
{
_gl
.
enable
(
_gl
.
BLEND
);
}
else
{
_gl
.
enable
(
_gl
.
BLEND
);
_gl
.
blendEquationSeparate
(
_gl
.
FUNC_ADD
,
_gl
.
FUNC_ADD
);
_gl
.
blendFuncSeparate
(
_gl
.
SRC_ALPHA
,
_gl
.
ONE_MINUS_SRC_ALPHA
,
_gl
.
ONE
,
_gl
.
ONE_MINUS_SRC_ALPHA
);
}
_oldBlending
=
blending
;
}
if
(
blending
===
THREE
.
CustomBlending
)
{
if
(
blendEquation
!==
_oldBlendEquation
)
{
_gl
.
blendEquation
(
paramThreeToGL
(
blendEquation
)
);
_oldBlendEquation
=
blendEquation
;
}
if
(
blendSrc
!==
_oldBlendSrc
||
blendDst
!==
_oldBlendDst
)
{
_gl
.
blendFunc
(
paramThreeToGL
(
blendSrc
),
paramThreeToGL
(
blendDst
)
);
_oldBlendSrc
=
blendSrc
;
_oldBlendDst
=
blendDst
;
}
}
else
{
_oldBlendEquation
=
null
;
_oldBlendSrc
=
null
;
_oldBlendDst
=
null
;
}
};
function
setDepthTest
(
depthTest
)
{
if
(
_oldDepthTest
!==
depthTest
)
{
if
(
depthTest
)
{
_gl
.
enable
(
_gl
.
DEPTH_TEST
);
}
else
{
_gl
.
disable
(
_gl
.
DEPTH_TEST
);
}
_oldDepthTest
=
depthTest
;
}
};
function
setDepthWrite
(
depthWrite
)
{
if
(
_oldDepthWrite
!==
depthWrite
)
{
_gl
.
depthMask
(
depthWrite
);
_oldDepthWrite
=
depthWrite
;
}
};
function
setTexture
(
texture
,
slot
)
{
if
(
texture
.
needsUpdate
)
{
if
(
!
texture
.
__webglInit
)
{
texture
.
__webglInit
=
true
;
//texture.addEventListener( 'dispose', onTextureDispose );
texture
.
__webglTexture
=
_gl
.
createTexture
();
//_this.info.memory.textures ++;
}
_gl
.
activeTexture
(
_gl
.
TEXTURE0
+
slot
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_2D
,
texture
.
__webglTexture
);
_gl
.
pixelStorei
(
_gl
.
UNPACK_FLIP_Y_WEBGL
,
texture
.
flipY
);
_gl
.
pixelStorei
(
_gl
.
UNPACK_PREMULTIPLY_ALPHA_WEBGL
,
texture
.
premultiplyAlpha
);
_gl
.
pixelStorei
(
_gl
.
UNPACK_ALIGNMENT
,
texture
.
unpackAlignment
);
var
image
=
texture
.
image
,
isImagePowerOfTwo
=
isPowerOfTwo
(
image
.
width
)
&&
isPowerOfTwo
(
image
.
height
),
glFormat
=
paramThreeToGL
(
texture
.
format
),
glType
=
paramThreeToGL
(
texture
.
type
);
setTextureParameters
(
_gl
.
TEXTURE_2D
,
texture
,
isImagePowerOfTwo
);
var
mipmap
,
mipmaps
=
texture
.
mipmaps
;
if
(
texture
instanceof
THREE
.
DataTexture
)
{
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if
(
mipmaps
.
length
>
0
&&
isImagePowerOfTwo
)
{
for
(
var
i
=
0
,
il
=
mipmaps
.
length
;
i
<
il
;
i
++
)
{
mipmap
=
mipmaps
[
i
];
_gl
.
texImage2D
(
_gl
.
TEXTURE_2D
,
i
,
glFormat
,
mipmap
.
width
,
mipmap
.
height
,
0
,
glFormat
,
glType
,
mipmap
.
data
);
}
texture
.
generateMipmaps
=
false
;
}
else
{
_gl
.
texImage2D
(
_gl
.
TEXTURE_2D
,
0
,
glFormat
,
image
.
width
,
image
.
height
,
0
,
glFormat
,
glType
,
image
.
data
);
}
}
else
if
(
texture
instanceof
THREE
.
CompressedTexture
)
{
// compressed textures can only use manually created mipmaps
// WebGL can't generate mipmaps for DDS textures
for
(
var
i
=
0
,
il
=
mipmaps
.
length
;
i
<
il
;
i
++
)
{
mipmap
=
mipmaps
[
i
];
_gl
.
compressedTexImage2D
(
_gl
.
TEXTURE_2D
,
i
,
glFormat
,
mipmap
.
width
,
mipmap
.
height
,
0
,
mipmap
.
data
);
}
}
else
{
// regular Texture (image, video, canvas)
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if
(
mipmaps
.
length
>
0
&&
isImagePowerOfTwo
)
{
for
(
var
i
=
0
,
il
=
mipmaps
.
length
;
i
<
il
;
i
++
)
{
mipmap
=
mipmaps
[
i
];
_gl
.
texImage2D
(
_gl
.
TEXTURE_2D
,
i
,
glFormat
,
glFormat
,
glType
,
mipmap
);
}
texture
.
generateMipmaps
=
false
;
}
else
{
_gl
.
texImage2D
(
_gl
.
TEXTURE_2D
,
0
,
glFormat
,
glFormat
,
glType
,
texture
.
image
);
}
}
if
(
texture
.
generateMipmaps
&&
isImagePowerOfTwo
)
_gl
.
generateMipmap
(
_gl
.
TEXTURE_2D
);
texture
.
needsUpdate
=
false
;
if
(
texture
.
onUpdate
)
texture
.
onUpdate
();
}
else
{
_gl
.
activeTexture
(
_gl
.
TEXTURE0
+
slot
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_2D
,
texture
.
__webglTexture
);
}
};
function
setCubeTexture
(
texture
,
slot
)
{
if
(
texture
.
image
.
length
===
6
)
{
if
(
texture
.
needsUpdate
)
{
if
(
!
texture
.
image
.
__webglTextureCube
)
{
texture
.
image
.
__webglTextureCube
=
_gl
.
createTexture
();
}
_gl
.
activeTexture
(
_gl
.
TEXTURE0
+
slot
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
texture
.
image
.
__webglTextureCube
);
_gl
.
pixelStorei
(
_gl
.
UNPACK_FLIP_Y_WEBGL
,
texture
.
flipY
);
var
isCompressed
=
texture
instanceof
THREE
.
CompressedTexture
;
var
cubeImage
=
[];
for
(
var
i
=
0
;
i
<
6
;
i
++
)
{
if
(
_autoScaleCubemaps
&&
!
isCompressed
)
{
cubeImage
[
i
]
=
clampToMaxSize
(
texture
.
image
[
i
],
_maxCubemapSize
);
}
else
{
cubeImage
[
i
]
=
texture
.
image
[
i
];
}
}
var
image
=
cubeImage
[
0
],
isImagePowerOfTwo
=
isPowerOfTwo
(
image
.
width
)
&&
isPowerOfTwo
(
image
.
height
),
glFormat
=
paramThreeToGL
(
texture
.
format
),
glType
=
paramThreeToGL
(
texture
.
type
);
setTextureParameters
(
_gl
.
TEXTURE_CUBE_MAP
,
texture
,
isImagePowerOfTwo
);
for
(
var
i
=
0
;
i
<
6
;
i
++
)
{
if
(
isCompressed
)
{
var
mipmap
,
mipmaps
=
cubeImage
[
i
].
mipmaps
;
for
(
var
j
=
0
,
jl
=
mipmaps
.
length
;
j
<
jl
;
j
++
)
{
mipmap
=
mipmaps
[
j
];
_gl
.
compressedTexImage2D
(
_gl
.
TEXTURE_CUBE_MAP_POSITIVE_X
+
i
,
j
,
glFormat
,
mipmap
.
width
,
mipmap
.
height
,
0
,
mipmap
.
data
);
}
}
else
{
_gl
.
texImage2D
(
_gl
.
TEXTURE_CUBE_MAP_POSITIVE_X
+
i
,
0
,
glFormat
,
glFormat
,
glType
,
cubeImage
[
i
]
);
}
}
if
(
texture
.
generateMipmaps
&&
isImagePowerOfTwo
)
{
_gl
.
generateMipmap
(
_gl
.
TEXTURE_CUBE_MAP
);
}
texture
.
needsUpdate
=
false
;
if
(
texture
.
onUpdate
)
texture
.
onUpdate
();
}
else
{
_gl
.
activeTexture
(
_gl
.
TEXTURE0
+
slot
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
texture
.
image
.
__webglTextureCube
);
}
}
};
// Textures
function
isPowerOfTwo
(
value
)
{
return
(
value
&
(
value
-
1
)
)
===
0
;
};
function
setTextureParameters
(
textureType
,
texture
,
isImagePowerOfTwo
)
{
if
(
isImagePowerOfTwo
)
{
_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
)
);
}
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
)
);
}
if
(
_glExtensionTextureFilterAnisotropic
&&
texture
.
type
!==
THREE
.
FloatType
)
{
if
(
texture
.
anisotropy
>
1
||
texture
.
__oldAnisotropy
)
{
_gl
.
texParameterf
(
textureType
,
_glExtensionTextureFilterAnisotropic
.
TEXTURE_MAX_ANISOTROPY_EXT
,
Math
.
min
(
texture
.
anisotropy
,
_maxAnisotropy
)
);
texture
.
__oldAnisotropy
=
texture
.
anisotropy
;
}
}
};
function
setupFrameBuffer
(
framebuffer
,
renderTarget
,
textureTarget
)
{
_gl
.
bindFramebuffer
(
_gl
.
FRAMEBUFFER
,
framebuffer
);
_gl
.
framebufferTexture2D
(
_gl
.
FRAMEBUFFER
,
_gl
.
COLOR_ATTACHMENT0
,
textureTarget
,
renderTarget
.
__webglTexture
,
0
);
};
function
setupRenderBuffer
(
renderbuffer
,
renderTarget
)
{
_gl
.
bindRenderbuffer
(
_gl
.
RENDERBUFFER
,
renderbuffer
);
if
(
renderTarget
.
depthBuffer
&&
!
renderTarget
.
stencilBuffer
)
{
_gl
.
renderbufferStorage
(
_gl
.
RENDERBUFFER
,
_gl
.
DEPTH_COMPONENT16
,
renderTarget
.
width
,
renderTarget
.
height
);
_gl
.
framebufferRenderbuffer
(
_gl
.
FRAMEBUFFER
,
_gl
.
DEPTH_ATTACHMENT
,
_gl
.
RENDERBUFFER
,
renderbuffer
);
/* For some reason this is not working. Defaulting to RGBA4.
} else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
*/
}
else
if
(
renderTarget
.
depthBuffer
&&
renderTarget
.
stencilBuffer
)
{
_gl
.
renderbufferStorage
(
_gl
.
RENDERBUFFER
,
_gl
.
DEPTH_STENCIL
,
renderTarget
.
width
,
renderTarget
.
height
);
_gl
.
framebufferRenderbuffer
(
_gl
.
FRAMEBUFFER
,
_gl
.
DEPTH_STENCIL_ATTACHMENT
,
_gl
.
RENDERBUFFER
,
renderbuffer
);
}
else
{
_gl
.
renderbufferStorage
(
_gl
.
RENDERBUFFER
,
_gl
.
RGBA4
,
renderTarget
.
width
,
renderTarget
.
height
);
}
};
function
setRenderTarget
(
renderTarget
)
{
var
isCube
=
(
renderTarget
instanceof
THREE
.
WebGLRenderTargetCube
);
if
(
renderTarget
&&
!
renderTarget
.
__webglFramebuffer
)
{
if
(
renderTarget
.
depthBuffer
===
undefined
)
renderTarget
.
depthBuffer
=
true
;
if
(
renderTarget
.
stencilBuffer
===
undefined
)
renderTarget
.
stencilBuffer
=
true
;
//renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
renderTarget
.
__webglTexture
=
_gl
.
createTexture
();
//_this.info.memory.textures ++;
// Setup texture, create render and frame buffers
var
isTargetPowerOfTwo
=
isPowerOfTwo
(
renderTarget
.
width
)
&&
isPowerOfTwo
(
renderTarget
.
height
),
glFormat
=
paramThreeToGL
(
renderTarget
.
format
),
glType
=
paramThreeToGL
(
renderTarget
.
type
);
if
(
isCube
)
{
renderTarget
.
__webglFramebuffer
=
[];
renderTarget
.
__webglRenderbuffer
=
[];
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
renderTarget
.
__webglTexture
);
setTextureParameters
(
_gl
.
TEXTURE_CUBE_MAP
,
renderTarget
,
isTargetPowerOfTwo
);
for
(
var
i
=
0
;
i
<
6
;
i
++
)
{
renderTarget
.
__webglFramebuffer
[
i
]
=
_gl
.
createFramebuffer
();
renderTarget
.
__webglRenderbuffer
[
i
]
=
_gl
.
createRenderbuffer
();
_gl
.
texImage2D
(
_gl
.
TEXTURE_CUBE_MAP_POSITIVE_X
+
i
,
0
,
glFormat
,
renderTarget
.
width
,
renderTarget
.
height
,
0
,
glFormat
,
glType
,
null
);
setupFrameBuffer
(
renderTarget
.
__webglFramebuffer
[
i
],
renderTarget
,
_gl
.
TEXTURE_CUBE_MAP_POSITIVE_X
+
i
);
setupRenderBuffer
(
renderTarget
.
__webglRenderbuffer
[
i
],
renderTarget
);
}
if
(
isTargetPowerOfTwo
)
_gl
.
generateMipmap
(
_gl
.
TEXTURE_CUBE_MAP
);
}
else
{
renderTarget
.
__webglFramebuffer
=
_gl
.
createFramebuffer
();
if
(
renderTarget
.
shareDepthFrom
)
{
renderTarget
.
__webglRenderbuffer
=
renderTarget
.
shareDepthFrom
.
__webglRenderbuffer
;
}
else
{
renderTarget
.
__webglRenderbuffer
=
_gl
.
createRenderbuffer
();
}
_gl
.
bindTexture
(
_gl
.
TEXTURE_2D
,
renderTarget
.
__webglTexture
);
setTextureParameters
(
_gl
.
TEXTURE_2D
,
renderTarget
,
isTargetPowerOfTwo
);
_gl
.
texImage2D
(
_gl
.
TEXTURE_2D
,
0
,
glFormat
,
renderTarget
.
width
,
renderTarget
.
height
,
0
,
glFormat
,
glType
,
null
);
setupFrameBuffer
(
renderTarget
.
__webglFramebuffer
,
renderTarget
,
_gl
.
TEXTURE_2D
);
if
(
renderTarget
.
shareDepthFrom
)
{
if
(
renderTarget
.
depthBuffer
&&
!
renderTarget
.
stencilBuffer
)
{
_gl
.
framebufferRenderbuffer
(
_gl
.
FRAMEBUFFER
,
_gl
.
DEPTH_ATTACHMENT
,
_gl
.
RENDERBUFFER
,
renderTarget
.
__webglRenderbuffer
);
}
else
if
(
renderTarget
.
depthBuffer
&&
renderTarget
.
stencilBuffer
)
{
_gl
.
framebufferRenderbuffer
(
_gl
.
FRAMEBUFFER
,
_gl
.
DEPTH_STENCIL_ATTACHMENT
,
_gl
.
RENDERBUFFER
,
renderTarget
.
__webglRenderbuffer
);
}
}
else
{
setupRenderBuffer
(
renderTarget
.
__webglRenderbuffer
,
renderTarget
);
}
if
(
isTargetPowerOfTwo
)
_gl
.
generateMipmap
(
_gl
.
TEXTURE_2D
);
}
// Release everything
if
(
isCube
)
{
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
null
);
}
else
{
_gl
.
bindTexture
(
_gl
.
TEXTURE_2D
,
null
);
}
_gl
.
bindRenderbuffer
(
_gl
.
RENDERBUFFER
,
null
);
_gl
.
bindFramebuffer
(
_gl
.
FRAMEBUFFER
,
null
);
}
var
framebuffer
,
width
,
height
,
vx
,
vy
;
if
(
renderTarget
)
{
if
(
isCube
)
{
framebuffer
=
renderTarget
.
__webglFramebuffer
[
renderTarget
.
activeCubeFace
];
}
else
{
framebuffer
=
renderTarget
.
__webglFramebuffer
;
}
width
=
renderTarget
.
width
;
height
=
renderTarget
.
height
;
vx
=
0
;
vy
=
0
;
}
else
{
framebuffer
=
null
;
width
=
_viewportWidth
;
height
=
_viewportHeight
;
vx
=
_viewportX
;
vy
=
_viewportY
;
}
if
(
framebuffer
!==
_currentFramebuffer
)
{
_gl
.
bindFramebuffer
(
_gl
.
FRAMEBUFFER
,
framebuffer
);
_gl
.
viewport
(
vx
,
vy
,
width
,
height
);
_currentFramebuffer
=
framebuffer
;
}
_currentWidth
=
width
;
_currentHeight
=
height
;
};
function
clampToMaxSize
(
image
,
maxSize
)
{
if
(
image
.
width
<=
maxSize
&&
image
.
height
<=
maxSize
)
{
return
image
;
}
// Warning: Scaling through the canvas will only work with images that use
// premultiplied alpha.
var
maxDimension
=
Math
.
max
(
image
.
width
,
image
.
height
);
var
newWidth
=
Math
.
floor
(
image
.
width
*
maxSize
/
maxDimension
);
var
newHeight
=
Math
.
floor
(
image
.
height
*
maxSize
/
maxDimension
);
var
canvas
=
document
.
createElement
(
'
canvas
'
);
canvas
.
width
=
newWidth
;
canvas
.
height
=
newHeight
;
var
ctx
=
canvas
.
getContext
(
"
2d
"
);
ctx
.
drawImage
(
image
,
0
,
0
,
image
.
width
,
image
.
height
,
0
,
0
,
newWidth
,
newHeight
);
return
canvas
;
};
function
updateRenderTargetMipmap
(
renderTarget
)
{
if
(
renderTarget
instanceof
THREE
.
WebGLRenderTargetCube
)
{
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
renderTarget
.
__webglTexture
);
_gl
.
generateMipmap
(
_gl
.
TEXTURE_CUBE_MAP
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
null
);
}
else
{
_gl
.
bindTexture
(
_gl
.
TEXTURE_2D
,
renderTarget
.
__webglTexture
);
_gl
.
generateMipmap
(
_gl
.
TEXTURE_2D
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_2D
,
null
);
}
};
function
setCubeTextureDynamic
(
texture
,
slot
)
{
_gl
.
activeTexture
(
_gl
.
TEXTURE0
+
slot
);
_gl
.
bindTexture
(
_gl
.
TEXTURE_CUBE_MAP
,
texture
.
__webglTexture
);
};
// Map three.js constants to WebGL constants
function
paramThreeToGL
(
p
)
{
if
(
p
===
THREE
.
RepeatWrapping
)
return
_gl
.
REPEAT
;
if
(
p
===
THREE
.
ClampToEdgeWrapping
)
return
_gl
.
CLAMP_TO_EDGE
;
if
(
p
===
THREE
.
MirroredRepeatWrapping
)
return
_gl
.
MIRRORED_REPEAT
;
if
(
p
===
THREE
.
NearestFilter
)
return
_gl
.
NEAREST
;
if
(
p
===
THREE
.
NearestMipMapNearestFilter
)
return
_gl
.
NEAREST_MIPMAP_NEAREST
;
if
(
p
===
THREE
.
NearestMipMapLinearFilter
)
return
_gl
.
NEAREST_MIPMAP_LINEAR
;
if
(
p
===
THREE
.
LinearFilter
)
return
_gl
.
LINEAR
;
if
(
p
===
THREE
.
LinearMipMapNearestFilter
)
return
_gl
.
LINEAR_MIPMAP_NEAREST
;
if
(
p
===
THREE
.
LinearMipMapLinearFilter
)
return
_gl
.
LINEAR_MIPMAP_LINEAR
;
if
(
p
===
THREE
.
UnsignedByteType
)
return
_gl
.
UNSIGNED_BYTE
;
if
(
p
===
THREE
.
UnsignedShort4444Type
)
return
_gl
.
UNSIGNED_SHORT_4_4_4_4
;
if
(
p
===
THREE
.
UnsignedShort5551Type
)
return
_gl
.
UNSIGNED_SHORT_5_5_5_1
;
if
(
p
===
THREE
.
UnsignedShort565Type
)
return
_gl
.
UNSIGNED_SHORT_5_6_5
;
if
(
p
===
THREE
.
ByteType
)
return
_gl
.
BYTE
;
if
(
p
===
THREE
.
ShortType
)
return
_gl
.
SHORT
;
if
(
p
===
THREE
.
UnsignedShortType
)
return
_gl
.
UNSIGNED_SHORT
;
if
(
p
===
THREE
.
IntType
)
return
_gl
.
INT
;
if
(
p
===
THREE
.
UnsignedIntType
)
return
_gl
.
UNSIGNED_INT
;
if
(
p
===
THREE
.
FloatType
)
return
_gl
.
FLOAT
;
if
(
p
===
THREE
.
AlphaFormat
)
return
_gl
.
ALPHA
;
if
(
p
===
THREE
.
RGBFormat
)
return
_gl
.
RGB
;
if
(
p
===
THREE
.
RGBAFormat
)
return
_gl
.
RGBA
;
if
(
p
===
THREE
.
LuminanceFormat
)
return
_gl
.
LUMINANCE
;
if
(
p
===
THREE
.
LuminanceAlphaFormat
)
return
_gl
.
LUMINANCE_ALPHA
;
if
(
p
===
THREE
.
AddEquation
)
return
_gl
.
FUNC_ADD
;
if
(
p
===
THREE
.
SubtractEquation
)
return
_gl
.
FUNC_SUBTRACT
;
if
(
p
===
THREE
.
ReverseSubtractEquation
)
return
_gl
.
FUNC_REVERSE_SUBTRACT
;
if
(
p
===
THREE
.
ZeroFactor
)
return
_gl
.
ZERO
;
if
(
p
===
THREE
.
OneFactor
)
return
_gl
.
ONE
;
if
(
p
===
THREE
.
SrcColorFactor
)
return
_gl
.
SRC_COLOR
;
if
(
p
===
THREE
.
OneMinusSrcColorFactor
)
return
_gl
.
ONE_MINUS_SRC_COLOR
;
if
(
p
===
THREE
.
SrcAlphaFactor
)
return
_gl
.
SRC_ALPHA
;
if
(
p
===
THREE
.
OneMinusSrcAlphaFactor
)
return
_gl
.
ONE_MINUS_SRC_ALPHA
;
if
(
p
===
THREE
.
DstAlphaFactor
)
return
_gl
.
DST_ALPHA
;
if
(
p
===
THREE
.
OneMinusDstAlphaFactor
)
return
_gl
.
ONE_MINUS_DST_ALPHA
;
if
(
p
===
THREE
.
DstColorFactor
)
return
_gl
.
DST_COLOR
;
if
(
p
===
THREE
.
OneMinusDstColorFactor
)
return
_gl
.
ONE_MINUS_DST_COLOR
;
if
(
p
===
THREE
.
SrcAlphaSaturateFactor
)
return
_gl
.
SRC_ALPHA_SATURATE
;
if
(
_glExtensionCompressedTextureS3TC
!==
undefined
)
{
if
(
p
===
THREE
.
RGB_S3TC_DXT1_Format
)
return
_glExtensionCompressedTextureS3TC
.
COMPRESSED_RGB_S3TC_DXT1_EXT
;
if
(
p
===
THREE
.
RGBA_S3TC_DXT1_Format
)
return
_glExtensionCompressedTextureS3TC
.
COMPRESSED_RGBA_S3TC_DXT1_EXT
;
if
(
p
===
THREE
.
RGBA_S3TC_DXT3_Format
)
return
_glExtensionCompressedTextureS3TC
.
COMPRESSED_RGBA_S3TC_DXT3_EXT
;
if
(
p
===
THREE
.
RGBA_S3TC_DXT5_Format
)
return
_glExtensionCompressedTextureS3TC
.
COMPRESSED_RGBA_S3TC_DXT5_EXT
;
}
return
0
;
};
function
compileShader
(
vertexShader
,
fragmentShader
){
var
program
=
_gl
.
createProgram
();
var
glFragmentShader
=
getShader
(
"
fragment
"
,
fragmentShader
);
var
glVertexShader
=
getShader
(
"
vertex
"
,
vertexShader
);
_gl
.
attachShader
(
program
,
glVertexShader
);
_gl
.
attachShader
(
program
,
glFragmentShader
);
_gl
.
linkProgram
(
program
);
if
(
!
_gl
.
getProgramParameter
(
program
,
_gl
.
LINK_STATUS
)
)
{
console
.
error
(
"
Could not initialise shader
\n
"
+
"
VALIDATE_STATUS:
"
+
_gl
.
getProgramParameter
(
program
,
_gl
.
VALIDATE_STATUS
)
+
"
, gl error [
"
+
_gl
.
getError
()
+
"
]
"
);
}
// clean up
_gl
.
deleteShader
(
glFragmentShader
);
_gl
.
deleteShader
(
glVertexShader
);
return
program
;
};
function
resetState
(){
_oldBlending
=
-
1
;
_oldDepthTest
=
-
1
;
_oldDepthWrite
=
-
1
;
_oldDoubleSided
=
-
1
;
_oldFlipSided
=
-
1
;
}
function
getShader
(
type
,
string
)
{
var
shader
;
if
(
type
===
"
fragment
"
)
{
shader
=
_gl
.
createShader
(
_gl
.
FRAGMENT_SHADER
);
}
else
if
(
type
===
"
vertex
"
)
{
shader
=
_gl
.
createShader
(
_gl
.
VERTEX_SHADER
);
}
_gl
.
shaderSource
(
shader
,
string
);
_gl
.
compileShader
(
shader
);
if
(
!
_gl
.
getShaderParameter
(
shader
,
_gl
.
COMPILE_STATUS
)
)
{
console
.
error
(
_gl
.
getShaderInfoLog
(
shader
)
);
console
.
error
(
addLineNumbers
(
string
)
);
return
null
;
}
return
shader
;
};
function
addLineNumbers
(
string
)
{
var
chunks
=
string
.
split
(
"
\n
"
);
for
(
var
i
=
0
,
il
=
chunks
.
length
;
i
<
il
;
i
++
)
{
// Chrome reports shader errors on lines
// starting counting from 1
chunks
[
i
]
=
(
i
+
1
)
+
"
:
"
+
chunks
[
i
];
}
return
chunks
.
join
(
"
\n
"
);
};
function
setLineWidth
(
width
)
{
if
(
width
!==
_oldLineWidth
)
{
_gl
.
lineWidth
(
width
);
_oldLineWidth
=
width
;
}
};
this
.
context
=
_gl
;
this
.
autoScaleCubemaps
=
_autoScaleCubemaps
;
this
.
supportsBoneTextures
=
_supportsBoneTextures
;
this
.
precision
=
_precision
;
this
.
maxVertexUniformVectors
=
_gl
.
getParameter
(
_gl
.
MAX_VERTEX_UNIFORM_VECTORS
);
// Methods
this
.
getContext
=
getContext
;
this
.
getDomElement
=
getDomElement
;
this
.
getPrecision
=
getPrecision
;
this
.
getCurrentWidth
=
getCurrentWidth
;
this
.
getCurrentHeight
=
getCurrentHeight
;
this
.
supportsVertexTextures
=
supportsVertexTextures
;
this
.
getMaxAnisotropy
=
getMaxAnisotropy
;
this
.
setRenderTarget
=
setRenderTarget
;
this
.
setSize
=
setSize
;
this
.
setViewport
=
setViewport
;
this
.
setScissor
=
setScissor
;
this
.
enableScissorTest
=
enableScissorTest
;
this
.
setClearColorHex
=
setClearColorHex
;
this
.
setClearColor
=
setClearColor
;
this
.
getClearColor
=
getClearColor
;
this
.
getClearAlpha
=
getClearAlpha
;
this
.
clear
=
clear
;
this
.
clearTarget
=
clearTarget
;
this
.
deleteBuffer
=
deleteBuffer
;
this
.
deleteTexture
=
deleteTexture
;
this
.
deleteFramebuffer
=
deleteFramebuffer
;
this
.
deleteRenderbuffer
=
deleteRenderbuffer
;
this
.
deleteProgram
=
deleteProgram
;
this
.
createBuffer
=
createBuffer
;
this
.
setStaticArrayBuffer
=
setStaticArrayBuffer
;
this
.
setStaticIndexBuffer
=
setStaticIndexBuffer
;
this
.
setDynamicArrayBuffer
=
setDynamicArrayBuffer
;
this
.
setDynamicIndexBuffer
=
setDynamicIndexBuffer
;
this
.
drawTriangles
=
drawTriangles
;
this
.
drawTriangleStrip
=
drawTriangleStrip
;
this
.
drawLines
=
drawLines
;
this
.
drawLineStrip
=
drawLineStrip
;
this
.
drawPoints
=
drawPoints
;
this
.
drawTriangleElements
=
drawTriangleElements
;
this
.
drawLineElements
=
drawLineElements
;
this
.
bindArrayBuffer
=
bindArrayBuffer
;
this
.
bindElementArrayBuffer
=
bindElementArrayBuffer
;
this
.
enableAttribute
=
enableAttribute
;
this
.
disableAttributes
=
disableAttributes
;
this
.
getAttribLocation
=
getAttribLocation
;
this
.
setFloatAttribute
=
setFloatAttribute
;
this
.
getUniformLocation
=
getUniformLocation
;
this
.
uniform1i
=
uniform1i
;
this
.
uniform1f
=
uniform1f
;
this
.
uniform2f
=
uniform2f
;
this
.
uniform3f
=
uniform3f
;
this
.
uniform4f
=
uniform4f
;
this
.
uniform1iv
=
uniform1iv
;
this
.
uniform2iv
=
uniform2iv
;
this
.
uniform3iv
=
uniform3iv
;
this
.
uniform1fv
=
uniform1fv
;
this
.
uniform2fv
=
uniform2fv
;
this
.
uniform3fv
=
uniform3fv
;
this
.
uniform4fv
=
uniform4fv
;
this
.
uniformMatrix3fv
=
uniformMatrix3fv
;
this
.
uniformMatrix4fv
=
uniformMatrix4fv
;
this
.
useProgram
=
useProgram
;
this
.
compileShader
=
compileShader
;
this
.
setFaceCulling
=
setFaceCulling
;
this
.
setMaterialFaces
=
setMaterialFaces
;
this
.
setPolygonOffset
=
setPolygonOffset
;
this
.
setBlending
=
setBlending
;
this
.
setDepthTest
=
setDepthTest
;
this
.
setDepthWrite
=
setDepthWrite
;
this
.
setTexture
=
setTexture
;
this
.
setCubeTexture
=
setCubeTexture
;
this
.
updateRenderTargetMipmap
=
updateRenderTargetMipmap
;
this
.
setCubeTextureDynamic
=
setCubeTextureDynamic
;
this
.
paramThreeToGL
=
paramThreeToGL
;
this
.
setLineWidth
=
setLineWidth
;
this
.
resetState
=
resetState
;
};
src/renderers/webgl/ShaderBuilder.js
0 → 100644
浏览文件 @
1efe37f9
THREE
.
WebGLRenderer2
.
ShaderBuilder
=
function
(
renderer
,
info
){
this
.
renderer
=
renderer
;
this
.
info
=
info
;
this
.
programs
=
[],
this
.
programs_counter
=
0
;
}
THREE
.
WebGLRenderer2
.
ShaderBuilder
.
prototype
.
buildProgram
=
function
(
shaderID
,
fragmentShader
,
vertexShader
,
uniforms
,
attributes
,
defines
,
parameters
)
{
var
renderer
=
this
.
renderer
;
var
p
,
pl
,
d
,
program
,
code
;
var
chunks
=
[];
// Generate code
if
(
shaderID
)
{
chunks
.
push
(
shaderID
);
}
else
{
chunks
.
push
(
fragmentShader
);
chunks
.
push
(
vertexShader
);
}
for
(
d
in
defines
)
{
chunks
.
push
(
d
);
chunks
.
push
(
defines
[
d
]
);
}
for
(
p
in
parameters
)
{
chunks
.
push
(
p
);
chunks
.
push
(
parameters
[
p
]
);
}
code
=
chunks
.
join
();
// Check if code has been already compiled
for
(
p
=
0
,
pl
=
this
.
programs
.
length
;
p
<
pl
;
p
++
)
{
var
programInfo
=
this
.
programs
[
p
];
if
(
programInfo
.
code
===
code
)
{
//console.log( "Code already compiled." /*: \n\n" + code*/ );
programInfo
.
usedTimes
++
;
return
programInfo
.
program
;
}
}
var
shadowMapTypeDefine
=
"
SHADOWMAP_TYPE_BASIC
"
;
if
(
parameters
.
shadowMapType
===
THREE
.
PCFShadowMap
)
{
shadowMapTypeDefine
=
"
SHADOWMAP_TYPE_PCF
"
;
}
else
if
(
parameters
.
shadowMapType
===
THREE
.
PCFSoftShadowMap
)
{
shadowMapTypeDefine
=
"
SHADOWMAP_TYPE_PCF_SOFT
"
;
}
//console.log( "building new program " );
//
var
customDefines
=
this
.
generateDefines
(
defines
);
//
var
prefix_vertex
=
[
"
precision
"
+
renderer
.
precision
+
"
float;
"
,
customDefines
,
renderer
.
supportsVertexTextures
?
"
#define VERTEX_TEXTURES
"
:
""
,
parameters
.
gammaInput
?
"
#define GAMMA_INPUT
"
:
""
,
parameters
.
gammaOutput
?
"
#define GAMMA_OUTPUT
"
:
""
,
parameters
.
physicallyBasedShading
?
"
#define PHYSICALLY_BASED_SHADING
"
:
""
,
"
#define MAX_DIR_LIGHTS
"
+
parameters
.
maxDirLights
,
"
#define MAX_POINT_LIGHTS
"
+
parameters
.
maxPointLights
,
"
#define MAX_SPOT_LIGHTS
"
+
parameters
.
maxSpotLights
,
"
#define MAX_HEMI_LIGHTS
"
+
parameters
.
maxHemiLights
,
"
#define MAX_SHADOWS
"
+
parameters
.
maxShadows
,
"
#define MAX_BONES
"
+
parameters
.
maxBones
,
parameters
.
map
?
"
#define USE_MAP
"
:
""
,
parameters
.
envMap
?
"
#define USE_ENVMAP
"
:
""
,
parameters
.
lightMap
?
"
#define USE_LIGHTMAP
"
:
""
,
parameters
.
bumpMap
?
"
#define USE_BUMPMAP
"
:
""
,
parameters
.
normalMap
?
"
#define USE_NORMALMAP
"
:
""
,
parameters
.
specularMap
?
"
#define USE_SPECULARMAP
"
:
""
,
parameters
.
vertexColors
?
"
#define USE_COLOR
"
:
""
,
parameters
.
skinning
?
"
#define USE_SKINNING
"
:
""
,
parameters
.
useVertexTexture
?
"
#define BONE_TEXTURE
"
:
""
,
parameters
.
boneTextureWidth
?
"
#define N_BONE_PIXEL_X
"
+
parameters
.
boneTextureWidth
.
toFixed
(
1
)
:
""
,
parameters
.
boneTextureHeight
?
"
#define N_BONE_PIXEL_Y
"
+
parameters
.
boneTextureHeight
.
toFixed
(
1
)
:
""
,
parameters
.
morphTargets
?
"
#define USE_MORPHTARGETS
"
:
""
,
parameters
.
morphNormals
?
"
#define USE_MORPHNORMALS
"
:
""
,
parameters
.
perPixel
?
"
#define PHONG_PER_PIXEL
"
:
""
,
parameters
.
wrapAround
?
"
#define WRAP_AROUND
"
:
""
,
parameters
.
doubleSided
?
"
#define DOUBLE_SIDED
"
:
""
,
parameters
.
flipSided
?
"
#define FLIP_SIDED
"
:
""
,
parameters
.
shadowMapEnabled
?
"
#define USE_SHADOWMAP
"
:
""
,
parameters
.
shadowMapEnabled
?
"
#define
"
+
shadowMapTypeDefine
:
""
,
parameters
.
shadowMapDebug
?
"
#define SHADOWMAP_DEBUG
"
:
""
,
parameters
.
shadowMapCascade
?
"
#define SHADOWMAP_CASCADE
"
:
""
,
parameters
.
sizeAttenuation
?
"
#define USE_SIZEATTENUATION
"
:
""
,
"
uniform mat4 modelMatrix;
"
,
"
uniform mat4 modelViewMatrix;
"
,
"
uniform mat4 projectionMatrix;
"
,
"
uniform mat4 viewMatrix;
"
,
"
uniform mat3 normalMatrix;
"
,
"
uniform vec3 cameraPosition;
"
,
"
attribute vec3 position;
"
,
"
attribute vec3 normal;
"
,
"
attribute vec2 uv;
"
,
"
attribute vec2 uv2;
"
,
"
#ifdef USE_COLOR
"
,
"
attribute vec3 color;
"
,
"
#endif
"
,
"
#ifdef USE_MORPHTARGETS
"
,
"
attribute vec3 morphTarget0;
"
,
"
attribute vec3 morphTarget1;
"
,
"
attribute vec3 morphTarget2;
"
,
"
attribute vec3 morphTarget3;
"
,
"
#ifdef USE_MORPHNORMALS
"
,
"
attribute vec3 morphNormal0;
"
,
"
attribute vec3 morphNormal1;
"
,
"
attribute vec3 morphNormal2;
"
,
"
attribute vec3 morphNormal3;
"
,
"
#else
"
,
"
attribute vec3 morphTarget4;
"
,
"
attribute vec3 morphTarget5;
"
,
"
attribute vec3 morphTarget6;
"
,
"
attribute vec3 morphTarget7;
"
,
"
#endif
"
,
"
#endif
"
,
"
#ifdef USE_SKINNING
"
,
"
attribute vec4 skinIndex;
"
,
"
attribute vec4 skinWeight;
"
,
"
#endif
"
,
""
].
join
(
"
\n
"
);
var
prefix_fragment
=
[
"
precision
"
+
renderer
.
precision
+
"
float;
"
,
(
parameters
.
bumpMap
||
parameters
.
normalMap
)
?
"
#extension GL_OES_standard_derivatives : enable
"
:
""
,
customDefines
,
"
#define MAX_DIR_LIGHTS
"
+
parameters
.
maxDirLights
,
"
#define MAX_POINT_LIGHTS
"
+
parameters
.
maxPointLights
,
"
#define MAX_SPOT_LIGHTS
"
+
parameters
.
maxSpotLights
,
"
#define MAX_HEMI_LIGHTS
"
+
parameters
.
maxHemiLights
,
"
#define MAX_SHADOWS
"
+
parameters
.
maxShadows
,
parameters
.
alphaTest
?
"
#define ALPHATEST
"
+
parameters
.
alphaTest
:
""
,
parameters
.
gammaInput
?
"
#define GAMMA_INPUT
"
:
""
,
parameters
.
gammaOutput
?
"
#define GAMMA_OUTPUT
"
:
""
,
(
parameters
.
useFog
&&
parameters
.
fog
)
?
"
#define USE_FOG
"
:
""
,
(
parameters
.
useFog
&&
parameters
.
fogExp
)
?
"
#define FOG_EXP2
"
:
""
,
parameters
.
map
?
"
#define USE_MAP
"
:
""
,
parameters
.
envMap
?
"
#define USE_ENVMAP
"
:
""
,
parameters
.
lightMap
?
"
#define USE_LIGHTMAP
"
:
""
,
parameters
.
bumpMap
?
"
#define USE_BUMPMAP
"
:
""
,
parameters
.
normalMap
?
"
#define USE_NORMALMAP
"
:
""
,
parameters
.
specularMap
?
"
#define USE_SPECULARMAP
"
:
""
,
parameters
.
vertexColors
?
"
#define USE_COLOR
"
:
""
,
parameters
.
metal
?
"
#define METAL
"
:
""
,
parameters
.
perPixel
?
"
#define PHONG_PER_PIXEL
"
:
""
,
parameters
.
wrapAround
?
"
#define WRAP_AROUND
"
:
""
,
parameters
.
doubleSided
?
"
#define DOUBLE_SIDED
"
:
""
,
parameters
.
flipSided
?
"
#define FLIP_SIDED
"
:
""
,
parameters
.
shadowMapEnabled
?
"
#define USE_SHADOWMAP
"
:
""
,
parameters
.
shadowMapEnabled
?
"
#define
"
+
shadowMapTypeDefine
:
""
,
parameters
.
shadowMapDebug
?
"
#define SHADOWMAP_DEBUG
"
:
""
,
parameters
.
shadowMapCascade
?
"
#define SHADOWMAP_CASCADE
"
:
""
,
"
uniform mat4 viewMatrix;
"
,
"
uniform vec3 cameraPosition;
"
,
""
].
join
(
"
\n
"
);
program
=
renderer
.
compileShader
(
prefix_vertex
+
vertexShader
,
prefix_fragment
+
fragmentShader
);
//console.log( prefix_fragment + fragmentShader );
//console.log( prefix_vertex + vertexShader );
program
.
uniforms
=
{};
program
.
attributes
=
{};
var
identifiers
,
u
,
a
,
i
;
// cache uniform locations
identifiers
=
[
'
viewMatrix
'
,
'
modelViewMatrix
'
,
'
projectionMatrix
'
,
'
normalMatrix
'
,
'
modelMatrix
'
,
'
cameraPosition
'
,
'
morphTargetInfluences
'
];
if
(
parameters
.
useVertexTexture
)
{
identifiers
.
push
(
'
boneTexture
'
);
}
else
{
identifiers
.
push
(
'
boneGlobalMatrices
'
);
}
for
(
u
in
uniforms
)
{
identifiers
.
push
(
u
);
}
this
.
cacheUniformLocations
(
program
,
identifiers
);
// cache attributes locations
identifiers
=
[
"
position
"
,
"
normal
"
,
"
uv
"
,
"
uv2
"
,
"
tangent
"
,
"
color
"
,
"
skinIndex
"
,
"
skinWeight
"
,
"
lineDistance
"
];
for
(
i
=
0
;
i
<
parameters
.
maxMorphTargets
;
i
++
)
{
identifiers
.
push
(
"
morphTarget
"
+
i
);
}
for
(
i
=
0
;
i
<
parameters
.
maxMorphNormals
;
i
++
)
{
identifiers
.
push
(
"
morphNormal
"
+
i
);
}
for
(
a
in
attributes
)
{
identifiers
.
push
(
a
);
}
this
.
cacheAttributeLocations
(
program
,
identifiers
);
program
.
id
=
this
.
programs_counter
++
;
this
.
programs
.
push
(
{
program
:
program
,
code
:
code
,
usedTimes
:
1
}
);
this
.
info
.
memory
.
programs
=
this
.
programs
.
length
;
return
program
;
};
THREE
.
WebGLRenderer2
.
ShaderBuilder
.
prototype
.
generateDefines
=
function
(
defines
)
{
var
value
,
chunk
,
chunks
=
[];
for
(
var
d
in
defines
)
{
value
=
defines
[
d
];
if
(
value
===
false
)
continue
;
chunk
=
"
#define
"
+
d
+
"
"
+
value
;
chunks
.
push
(
chunk
);
}
return
chunks
.
join
(
"
\n
"
);
};
// Shader parameters cache
THREE
.
WebGLRenderer2
.
ShaderBuilder
.
prototype
.
cacheUniformLocations
=
function
(
program
,
identifiers
)
{
var
i
,
l
,
id
,
renderer
=
this
.
renderer
;
for
(
i
=
0
,
l
=
identifiers
.
length
;
i
<
l
;
i
++
)
{
id
=
identifiers
[
i
];
program
.
uniforms
[
id
]
=
renderer
.
getUniformLocation
(
program
,
id
);
}
};
THREE
.
WebGLRenderer2
.
ShaderBuilder
.
prototype
.
cacheAttributeLocations
=
function
(
program
,
identifiers
)
{
var
i
,
l
,
id
,
renderer
=
this
.
renderer
;
for
(
i
=
0
,
l
=
identifiers
.
length
;
i
<
l
;
i
++
)
{
id
=
identifiers
[
i
];
program
.
attributes
[
id
]
=
renderer
.
getAttribLocation
(
program
,
id
);
}
};
THREE
.
WebGLRenderer2
.
ShaderBuilder
.
prototype
.
removeProgram
=
function
(
program
)
{
var
i
,
il
,
programInfo
;
var
deleteProgram
=
false
;
var
programs
=
this
.
programs
;
for
(
i
=
0
,
il
=
programs
.
length
;
i
<
il
;
i
++
)
{
programInfo
=
programs
[
i
];
if
(
programInfo
.
program
===
program
)
{
programInfo
.
usedTimes
--
;
if
(
programInfo
.
usedTimes
===
0
)
{
deleteProgram
=
true
;
}
break
;
}
}
if
(
deleteProgram
===
true
)
{
// avoid using array.splice, this is costlier than creating new array from scratch
var
newPrograms
=
[];
for
(
i
=
0
,
il
=
programs
.
length
;
i
<
il
;
i
++
)
{
programInfo
=
programs
[
i
];
if
(
programInfo
.
program
!==
program
)
{
newPrograms
.
push
(
programInfo
);
}
}
programs
=
newPrograms
;
this
.
renderer
.
deleteProgram
(
program
);
this
.
info
.
memory
.
programs
--
;
}
}
\ No newline at end of file
src/renderers/webgl/objects/LineRenderer.js
0 → 100644
浏览文件 @
1efe37f9
THREE
.
WebGLRenderer2
.
LineRenderer
=
function
(
lowlevelrenderer
,
info
){
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
call
(
this
,
lowlevelrenderer
,
info
);
};
THREE
.
WebGLRenderer2
.
LineRenderer
.
prototype
=
Object
.
create
(
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
prototype
);
THREE
.
WebGLRenderer2
.
LineRenderer
.
prototype
.
createBuffers
=
function
(
geometry
)
{
var
renderer
=
this
.
renderer
;
geometry
.
__webglVertexBuffer
=
renderer
.
createBuffer
();
geometry
.
__webglColorBuffer
=
renderer
.
createBuffer
();
geometry
.
__webglLineDistanceBuffer
=
renderer
.
createBuffer
();
this
.
info
.
memory
.
geometries
++
;
};
THREE
.
WebGLRenderer2
.
LineRenderer
.
prototype
.
initBuffers
=
function
(
geometry
,
object
)
{
var
nvertices
=
geometry
.
vertices
.
length
;
geometry
.
__vertexArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__colorArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__lineDistanceArray
=
new
Float32Array
(
nvertices
*
1
);
geometry
.
__webglLineCount
=
nvertices
;
this
.
initCustomAttributes
(
geometry
,
object
);
};
THREE
.
WebGLRenderer2
.
LineRenderer
.
prototype
.
setBuffers
=
function
(
geometry
,
object
)
{
var
renderer
=
this
.
renderer
;
var
v
,
c
,
d
,
vertex
,
offset
,
color
,
vertices
=
geometry
.
vertices
,
colors
=
geometry
.
colors
,
lineDistances
=
geometry
.
lineDistances
,
vl
=
vertices
.
length
,
cl
=
colors
.
length
,
dl
=
lineDistances
.
length
,
vertexArray
=
geometry
.
__vertexArray
,
colorArray
=
geometry
.
__colorArray
,
lineDistanceArray
=
geometry
.
__lineDistanceArray
,
dirtyVertices
=
geometry
.
verticesNeedUpdate
,
dirtyColors
=
geometry
.
colorsNeedUpdate
,
dirtyLineDistances
=
geometry
.
lineDistancesNeedUpdate
,
customAttributes
=
geometry
.
__webglCustomAttributesList
,
i
,
il
,
a
,
ca
,
cal
,
value
,
customAttribute
;
if
(
dirtyVertices
)
{
for
(
v
=
0
;
v
<
vl
;
v
++
)
{
vertex
=
vertices
[
v
];
offset
=
v
*
3
;
vertexArray
[
offset
]
=
vertex
.
x
;
vertexArray
[
offset
+
1
]
=
vertex
.
y
;
vertexArray
[
offset
+
2
]
=
vertex
.
z
;
}
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglVertexBuffer
,
vertexArray
);
}
if
(
dirtyColors
)
{
for
(
c
=
0
;
c
<
cl
;
c
++
)
{
color
=
colors
[
c
];
offset
=
c
*
3
;
colorArray
[
offset
]
=
color
.
r
;
colorArray
[
offset
+
1
]
=
color
.
g
;
colorArray
[
offset
+
2
]
=
color
.
b
;
}
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglColorBuffer
,
colorArray
);
}
if
(
dirtyLineDistances
)
{
for
(
d
=
0
;
d
<
dl
;
d
++
)
{
lineDistanceArray
[
d
]
=
lineDistances
[
d
];
}
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglLineDistanceBuffer
,
lineDistanceArray
);
}
if
(
customAttributes
)
{
for
(
i
=
0
,
il
=
customAttributes
.
length
;
i
<
il
;
i
++
)
{
customAttribute
=
customAttributes
[
i
];
if
(
customAttribute
.
needsUpdate
&&
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
)
{
offset
=
0
;
cal
=
customAttribute
.
value
.
length
;
if
(
customAttribute
.
size
===
1
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
customAttribute
.
array
[
ca
]
=
customAttribute
.
value
[
ca
];
}
}
else
if
(
customAttribute
.
size
===
2
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
offset
+=
2
;
}
}
else
if
(
customAttribute
.
size
===
3
)
{
if
(
customAttribute
.
type
===
"
c
"
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
r
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
g
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
b
;
offset
+=
3
;
}
}
else
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
offset
+=
3
;
}
}
}
else
if
(
customAttribute
.
size
===
4
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
customAttribute
.
array
[
offset
+
3
]
=
value
.
w
;
offset
+=
4
;
}
}
renderer
.
setDynamicArrayBuffer
(
customAttribute
.
buffer
,
customAttribute
.
array
);
}
}
}
};
\ No newline at end of file
src/renderers/webgl/objects/MeshRenderer.js
0 → 100644
浏览文件 @
1efe37f9
THREE
.
WebGLRenderer2
.
MeshRenderer
=
function
(
lowlevelrenderer
,
info
){
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
call
(
this
,
lowlevelrenderer
,
info
);
};
THREE
.
WebGLRenderer2
.
MeshRenderer
.
prototype
=
Object
.
create
(
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
prototype
);
THREE
.
WebGLRenderer2
.
MeshRenderer
.
prototype
.
createBuffers
=
function
(
geometryGroup
)
{
var
renderer
=
this
.
renderer
;
geometryGroup
.
__webglVertexBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglNormalBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglTangentBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglColorBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglUVBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglUV2Buffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglSkinIndicesBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglSkinWeightsBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglFaceBuffer
=
renderer
.
createBuffer
();
geometryGroup
.
__webglLineBuffer
=
renderer
.
createBuffer
();
var
m
,
ml
;
if
(
geometryGroup
.
numMorphTargets
)
{
geometryGroup
.
__webglMorphTargetsBuffers
=
[];
for
(
m
=
0
,
ml
=
geometryGroup
.
numMorphTargets
;
m
<
ml
;
m
++
)
{
geometryGroup
.
__webglMorphTargetsBuffers
.
push
(
renderer
.
createBuffer
()
);
}
}
if
(
geometryGroup
.
numMorphNormals
)
{
geometryGroup
.
__webglMorphNormalsBuffers
=
[];
for
(
m
=
0
,
ml
=
geometryGroup
.
numMorphNormals
;
m
<
ml
;
m
++
)
{
geometryGroup
.
__webglMorphNormalsBuffers
.
push
(
renderer
.
createBuffer
()
);
}
}
this
.
info
.
memory
.
geometries
++
;
};
THREE
.
WebGLRenderer2
.
MeshRenderer
.
prototype
.
initBuffers
=
function
(
geometryGroup
,
object
)
{
var
geometry
=
object
.
geometry
,
faces3
=
geometryGroup
.
faces3
,
faces4
=
geometryGroup
.
faces4
,
nvertices
=
faces3
.
length
*
3
+
faces4
.
length
*
4
,
ntris
=
faces3
.
length
*
1
+
faces4
.
length
*
2
,
nlines
=
faces3
.
length
*
3
+
faces4
.
length
*
4
,
material
=
this
.
getBufferMaterial
(
object
,
geometryGroup
),
uvType
=
this
.
bufferGuessUVType
(
material
),
normalType
=
this
.
bufferGuessNormalType
(
material
),
vertexColorType
=
this
.
bufferGuessVertexColorType
(
material
);
//console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material );
geometryGroup
.
__vertexArray
=
new
Float32Array
(
nvertices
*
3
);
if
(
normalType
)
{
geometryGroup
.
__normalArray
=
new
Float32Array
(
nvertices
*
3
);
}
if
(
geometry
.
hasTangents
)
{
geometryGroup
.
__tangentArray
=
new
Float32Array
(
nvertices
*
4
);
}
if
(
vertexColorType
)
{
geometryGroup
.
__colorArray
=
new
Float32Array
(
nvertices
*
3
);
}
if
(
uvType
)
{
if
(
geometry
.
faceUvs
.
length
>
0
||
geometry
.
faceVertexUvs
.
length
>
0
)
{
geometryGroup
.
__uvArray
=
new
Float32Array
(
nvertices
*
2
);
}
if
(
geometry
.
faceUvs
.
length
>
1
||
geometry
.
faceVertexUvs
.
length
>
1
)
{
geometryGroup
.
__uv2Array
=
new
Float32Array
(
nvertices
*
2
);
}
}
if
(
object
.
geometry
.
skinWeights
.
length
&&
object
.
geometry
.
skinIndices
.
length
)
{
geometryGroup
.
__skinIndexArray
=
new
Float32Array
(
nvertices
*
4
);
geometryGroup
.
__skinWeightArray
=
new
Float32Array
(
nvertices
*
4
);
}
geometryGroup
.
__faceArray
=
new
Uint16Array
(
ntris
*
3
);
geometryGroup
.
__lineArray
=
new
Uint16Array
(
nlines
*
2
);
var
m
,
ml
;
if
(
geometryGroup
.
numMorphTargets
)
{
geometryGroup
.
__morphTargetsArrays
=
[];
for
(
m
=
0
,
ml
=
geometryGroup
.
numMorphTargets
;
m
<
ml
;
m
++
)
{
geometryGroup
.
__morphTargetsArrays
.
push
(
new
Float32Array
(
nvertices
*
3
)
);
}
}
if
(
geometryGroup
.
numMorphNormals
)
{
geometryGroup
.
__morphNormalsArrays
=
[];
for
(
m
=
0
,
ml
=
geometryGroup
.
numMorphNormals
;
m
<
ml
;
m
++
)
{
geometryGroup
.
__morphNormalsArrays
.
push
(
new
Float32Array
(
nvertices
*
3
)
);
}
}
geometryGroup
.
__webglFaceCount
=
ntris
*
3
;
geometryGroup
.
__webglLineCount
=
nlines
*
2
;
// custom attributes
if
(
material
.
attributes
)
{
if
(
geometryGroup
.
__webglCustomAttributesList
===
undefined
)
{
geometryGroup
.
__webglCustomAttributesList
=
[];
}
for
(
var
a
in
material
.
attributes
)
{
// Do a shallow copy of the attribute object so different geometryGroup chunks use different
// attribute buffers which are correctly indexed in the setMeshBuffers function
var
originalAttribute
=
material
.
attributes
[
a
];
var
attribute
=
{};
for
(
var
property
in
originalAttribute
)
{
attribute
[
property
]
=
originalAttribute
[
property
];
}
if
(
!
attribute
.
__webglInitialized
||
attribute
.
createUniqueBuffers
)
{
attribute
.
__webglInitialized
=
true
;
var
size
=
1
;
// "f" and "i"
if
(
attribute
.
type
===
"
v2
"
)
size
=
2
;
else
if
(
attribute
.
type
===
"
v3
"
)
size
=
3
;
else
if
(
attribute
.
type
===
"
v4
"
)
size
=
4
;
else
if
(
attribute
.
type
===
"
c
"
)
size
=
3
;
attribute
.
size
=
size
;
attribute
.
array
=
new
Float32Array
(
nvertices
*
size
);
attribute
.
buffer
=
this
.
renderer
.
createBuffer
();
attribute
.
buffer
.
belongsToAttribute
=
a
;
originalAttribute
.
needsUpdate
=
true
;
attribute
.
__original
=
originalAttribute
;
}
geometryGroup
.
__webglCustomAttributesList
.
push
(
attribute
);
}
}
geometryGroup
.
__inittedArrays
=
true
;
};
THREE
.
WebGLRenderer2
.
MeshRenderer
.
prototype
.
setBuffers
=
function
(
geometryGroup
,
object
,
dispose
,
material
)
{
if
(
!
geometryGroup
.
__inittedArrays
)
{
return
;
}
var
renderer
=
this
.
renderer
;
var
normalType
=
this
.
bufferGuessNormalType
(
material
),
vertexColorType
=
this
.
bufferGuessVertexColorType
(
material
),
uvType
=
this
.
bufferGuessUVType
(
material
),
needsSmoothNormals
=
(
normalType
===
THREE
.
SmoothShading
);
var
f
,
fl
,
fi
,
face
,
vertexNormals
,
faceNormal
,
normal
,
vertexColors
,
faceColor
,
vertexTangents
,
uv
,
uv2
,
v1
,
v2
,
v3
,
v4
,
t1
,
t2
,
t3
,
t4
,
n1
,
n2
,
n3
,
n4
,
c1
,
c2
,
c3
,
c4
,
sw1
,
sw2
,
sw3
,
sw4
,
si1
,
si2
,
si3
,
si4
,
sa1
,
sa2
,
sa3
,
sa4
,
sb1
,
sb2
,
sb3
,
sb4
,
m
,
ml
,
i
,
il
,
vn
,
uvi
,
uv2i
,
vk
,
vkl
,
vka
,
nka
,
chf
,
faceVertexNormals
,
a
,
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
,
offset_custom
=
0
,
offset_customSrc
=
0
,
value
,
vertexArray
=
geometryGroup
.
__vertexArray
,
uvArray
=
geometryGroup
.
__uvArray
,
uv2Array
=
geometryGroup
.
__uv2Array
,
normalArray
=
geometryGroup
.
__normalArray
,
tangentArray
=
geometryGroup
.
__tangentArray
,
colorArray
=
geometryGroup
.
__colorArray
,
skinIndexArray
=
geometryGroup
.
__skinIndexArray
,
skinWeightArray
=
geometryGroup
.
__skinWeightArray
,
morphTargetsArrays
=
geometryGroup
.
__morphTargetsArrays
,
morphNormalsArrays
=
geometryGroup
.
__morphNormalsArrays
,
customAttributes
=
geometryGroup
.
__webglCustomAttributesList
,
customAttribute
,
faceArray
=
geometryGroup
.
__faceArray
,
lineArray
=
geometryGroup
.
__lineArray
,
geometry
=
object
.
geometry
,
// this is shared for all chunks
dirtyVertices
=
geometry
.
verticesNeedUpdate
,
dirtyElements
=
geometry
.
elementsNeedUpdate
,
dirtyUvs
=
geometry
.
uvsNeedUpdate
,
dirtyNormals
=
geometry
.
normalsNeedUpdate
,
dirtyTangents
=
geometry
.
tangentsNeedUpdate
,
dirtyColors
=
geometry
.
colorsNeedUpdate
,
dirtyMorphTargets
=
geometry
.
morphTargetsNeedUpdate
,
vertices
=
geometry
.
vertices
,
chunk_faces3
=
geometryGroup
.
faces3
,
chunk_faces4
=
geometryGroup
.
faces4
,
obj_faces
=
geometry
.
faces
,
obj_uvs
=
geometry
.
faceVertexUvs
[
0
],
obj_uvs2
=
geometry
.
faceVertexUvs
[
1
],
obj_colors
=
geometry
.
colors
,
obj_skinIndices
=
geometry
.
skinIndices
,
obj_skinWeights
=
geometry
.
skinWeights
,
morphTargets
=
geometry
.
morphTargets
,
morphNormals
=
geometry
.
morphNormals
;
if
(
dirtyVertices
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
v1
=
vertices
[
face
.
a
];
v2
=
vertices
[
face
.
b
];
v3
=
vertices
[
face
.
c
];
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
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
v1
=
vertices
[
face
.
a
];
v2
=
vertices
[
face
.
b
];
v3
=
vertices
[
face
.
c
];
v4
=
vertices
[
face
.
d
];
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
;
}
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglVertexBuffer
,
vertexArray
);
}
if
(
dirtyMorphTargets
)
{
for
(
vk
=
0
,
vkl
=
morphTargets
.
length
;
vk
<
vkl
;
vk
++
)
{
offset_morphTarget
=
0
;
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
chf
=
chunk_faces3
[
f
];
face
=
obj_faces
[
chf
];
// morph positions
v1
=
morphTargets
[
vk
].
vertices
[
face
.
a
];
v2
=
morphTargets
[
vk
].
vertices
[
face
.
b
];
v3
=
morphTargets
[
vk
].
vertices
[
face
.
c
];
vka
=
morphTargetsArrays
[
vk
];
vka
[
offset_morphTarget
]
=
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
;
// morph normals
if
(
material
.
morphNormals
)
{
if
(
needsSmoothNormals
)
{
faceVertexNormals
=
morphNormals
[
vk
].
vertexNormals
[
chf
];
n1
=
faceVertexNormals
.
a
;
n2
=
faceVertexNormals
.
b
;
n3
=
faceVertexNormals
.
c
;
}
else
{
n1
=
morphNormals
[
vk
].
faceNormals
[
chf
];
n2
=
n1
;
n3
=
n1
;
}
nka
=
morphNormalsArrays
[
vk
];
nka
[
offset_morphTarget
]
=
n1
.
x
;
nka
[
offset_morphTarget
+
1
]
=
n1
.
y
;
nka
[
offset_morphTarget
+
2
]
=
n1
.
z
;
nka
[
offset_morphTarget
+
3
]
=
n2
.
x
;
nka
[
offset_morphTarget
+
4
]
=
n2
.
y
;
nka
[
offset_morphTarget
+
5
]
=
n2
.
z
;
nka
[
offset_morphTarget
+
6
]
=
n3
.
x
;
nka
[
offset_morphTarget
+
7
]
=
n3
.
y
;
nka
[
offset_morphTarget
+
8
]
=
n3
.
z
;
}
//
offset_morphTarget
+=
9
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
chf
=
chunk_faces4
[
f
];
face
=
obj_faces
[
chf
];
// morph positions
v1
=
morphTargets
[
vk
].
vertices
[
face
.
a
];
v2
=
morphTargets
[
vk
].
vertices
[
face
.
b
];
v3
=
morphTargets
[
vk
].
vertices
[
face
.
c
];
v4
=
morphTargets
[
vk
].
vertices
[
face
.
d
];
vka
=
morphTargetsArrays
[
vk
];
vka
[
offset_morphTarget
]
=
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
;
// morph normals
if
(
material
.
morphNormals
)
{
if
(
needsSmoothNormals
)
{
faceVertexNormals
=
morphNormals
[
vk
].
vertexNormals
[
chf
];
n1
=
faceVertexNormals
.
a
;
n2
=
faceVertexNormals
.
b
;
n3
=
faceVertexNormals
.
c
;
n4
=
faceVertexNormals
.
d
;
}
else
{
n1
=
morphNormals
[
vk
].
faceNormals
[
chf
];
n2
=
n1
;
n3
=
n1
;
n4
=
n1
;
}
nka
=
morphNormalsArrays
[
vk
];
nka
[
offset_morphTarget
]
=
n1
.
x
;
nka
[
offset_morphTarget
+
1
]
=
n1
.
y
;
nka
[
offset_morphTarget
+
2
]
=
n1
.
z
;
nka
[
offset_morphTarget
+
3
]
=
n2
.
x
;
nka
[
offset_morphTarget
+
4
]
=
n2
.
y
;
nka
[
offset_morphTarget
+
5
]
=
n2
.
z
;
nka
[
offset_morphTarget
+
6
]
=
n3
.
x
;
nka
[
offset_morphTarget
+
7
]
=
n3
.
y
;
nka
[
offset_morphTarget
+
8
]
=
n3
.
z
;
nka
[
offset_morphTarget
+
9
]
=
n4
.
x
;
nka
[
offset_morphTarget
+
10
]
=
n4
.
y
;
nka
[
offset_morphTarget
+
11
]
=
n4
.
z
;
}
//
offset_morphTarget
+=
12
;
}
this
.
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglMorphTargetsBuffers
[
vk
],
morphTargetsArrays
[
vk
]);
if
(
material
.
morphNormals
)
{
this
.
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglMorphNormalsBuffers
[
vk
],
morphNormalsArrays
[
vk
]);
}
}
}
if
(
obj_skinWeights
.
length
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
// weights
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
;
offset_skin
+=
12
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
// 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
;
offset_skin
+=
16
;
}
if
(
offset_skin
>
0
)
{
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglSkinIndicesBuffer
,
skinIndexArray
);
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglSkinWeightsBuffer
,
skinWeightArray
);
}
}
if
(
dirtyColors
&&
vertexColorType
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
vertexColors
=
face
.
vertexColors
;
faceColor
=
face
.
color
;
if
(
vertexColors
.
length
===
3
&&
vertexColorType
===
THREE
.
VertexColors
)
{
c1
=
vertexColors
[
0
];
c2
=
vertexColors
[
1
];
c3
=
vertexColors
[
2
];
}
else
{
c1
=
faceColor
;
c2
=
faceColor
;
c3
=
faceColor
;
}
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
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
vertexColors
=
face
.
vertexColors
;
faceColor
=
face
.
color
;
if
(
vertexColors
.
length
===
4
&&
vertexColorType
===
THREE
.
VertexColors
)
{
c1
=
vertexColors
[
0
];
c2
=
vertexColors
[
1
];
c3
=
vertexColors
[
2
];
c4
=
vertexColors
[
3
];
}
else
{
c1
=
faceColor
;
c2
=
faceColor
;
c3
=
faceColor
;
c4
=
faceColor
;
}
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
(
offset_color
>
0
)
{
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglColorBuffer
,
colorArray
);
}
}
if
(
dirtyTangents
&&
geometry
.
hasTangents
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
vertexTangents
=
face
.
vertexTangents
;
t1
=
vertexTangents
[
0
];
t2
=
vertexTangents
[
1
];
t3
=
vertexTangents
[
2
];
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
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
vertexTangents
=
face
.
vertexTangents
;
t1
=
vertexTangents
[
0
];
t2
=
vertexTangents
[
1
];
t3
=
vertexTangents
[
2
];
t4
=
vertexTangents
[
3
];
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
;
}
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglTangentBuffer
,
tangentArray
);
}
if
(
dirtyNormals
&&
normalType
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
vertexNormals
=
face
.
vertexNormals
;
faceNormal
=
face
.
normal
;
if
(
vertexNormals
.
length
===
3
&&
needsSmoothNormals
)
{
for
(
i
=
0
;
i
<
3
;
i
++
)
{
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
=
0
;
i
<
3
;
i
++
)
{
normalArray
[
offset_normal
]
=
faceNormal
.
x
;
normalArray
[
offset_normal
+
1
]
=
faceNormal
.
y
;
normalArray
[
offset_normal
+
2
]
=
faceNormal
.
z
;
offset_normal
+=
3
;
}
}
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
vertexNormals
=
face
.
vertexNormals
;
faceNormal
=
face
.
normal
;
if
(
vertexNormals
.
length
===
4
&&
needsSmoothNormals
)
{
for
(
i
=
0
;
i
<
4
;
i
++
)
{
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
=
0
;
i
<
4
;
i
++
)
{
normalArray
[
offset_normal
]
=
faceNormal
.
x
;
normalArray
[
offset_normal
+
1
]
=
faceNormal
.
y
;
normalArray
[
offset_normal
+
2
]
=
faceNormal
.
z
;
offset_normal
+=
3
;
}
}
}
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglNormalBuffer
,
normalArray
);
}
if
(
dirtyUvs
&&
obj_uvs
&&
uvType
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
fi
=
chunk_faces3
[
f
];
uv
=
obj_uvs
[
fi
];
if
(
uv
===
undefined
)
continue
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
uvi
=
uv
[
i
];
uvArray
[
offset_uv
]
=
uvi
.
x
;
uvArray
[
offset_uv
+
1
]
=
uvi
.
y
;
offset_uv
+=
2
;
}
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
fi
=
chunk_faces4
[
f
];
uv
=
obj_uvs
[
fi
];
if
(
uv
===
undefined
)
continue
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
uvi
=
uv
[
i
];
uvArray
[
offset_uv
]
=
uvi
.
x
;
uvArray
[
offset_uv
+
1
]
=
uvi
.
y
;
offset_uv
+=
2
;
}
}
if
(
offset_uv
>
0
)
{
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglUVBuffer
,
uvArray
);
}
}
if
(
dirtyUvs
&&
obj_uvs2
&&
uvType
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
fi
=
chunk_faces3
[
f
];
uv2
=
obj_uvs2
[
fi
];
if
(
uv2
===
undefined
)
continue
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
uv2i
=
uv2
[
i
];
uv2Array
[
offset_uv2
]
=
uv2i
.
x
;
uv2Array
[
offset_uv2
+
1
]
=
uv2i
.
y
;
offset_uv2
+=
2
;
}
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
fi
=
chunk_faces4
[
f
];
uv2
=
obj_uvs2
[
fi
];
if
(
uv2
===
undefined
)
continue
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
uv2i
=
uv2
[
i
];
uv2Array
[
offset_uv2
]
=
uv2i
.
x
;
uv2Array
[
offset_uv2
+
1
]
=
uv2i
.
y
;
offset_uv2
+=
2
;
}
}
if
(
offset_uv2
>
0
)
{
renderer
.
setDynamicArrayBuffer
(
geometryGroup
.
__webglUV2Buffer
,
uv2Array
);
}
}
if
(
dirtyElements
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
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
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
faceArray
[
offset_face
]
=
vertexIndex
;
faceArray
[
offset_face
+
1
]
=
vertexIndex
+
1
;
faceArray
[
offset_face
+
2
]
=
vertexIndex
+
3
;
faceArray
[
offset_face
+
3
]
=
vertexIndex
+
1
;
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
;
}
renderer
.
setDynamicIndexBuffer
(
geometryGroup
.
__webglFaceBuffer
,
faceArray
);
renderer
.
setDynamicIndexBuffer
(
geometryGroup
.
__webglLineBuffer
,
lineArray
);
}
if
(
customAttributes
)
{
for
(
i
=
0
,
il
=
customAttributes
.
length
;
i
<
il
;
i
++
)
{
customAttribute
=
customAttributes
[
i
];
if
(
!
customAttribute
.
__original
.
needsUpdate
)
continue
;
offset_custom
=
0
;
offset_customSrc
=
0
;
if
(
customAttribute
.
size
===
1
)
{
if
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
customAttribute
.
array
[
offset_custom
]
=
customAttribute
.
value
[
face
.
a
];
customAttribute
.
array
[
offset_custom
+
1
]
=
customAttribute
.
value
[
face
.
b
];
customAttribute
.
array
[
offset_custom
+
2
]
=
customAttribute
.
value
[
face
.
c
];
offset_custom
+=
3
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
customAttribute
.
array
[
offset_custom
]
=
customAttribute
.
value
[
face
.
a
];
customAttribute
.
array
[
offset_custom
+
1
]
=
customAttribute
.
value
[
face
.
b
];
customAttribute
.
array
[
offset_custom
+
2
]
=
customAttribute
.
value
[
face
.
c
];
customAttribute
.
array
[
offset_custom
+
3
]
=
customAttribute
.
value
[
face
.
d
];
offset_custom
+=
4
;
}
}
else
if
(
customAttribute
.
boundTo
===
"
faces
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces3
[
f
]
];
customAttribute
.
array
[
offset_custom
]
=
value
;
customAttribute
.
array
[
offset_custom
+
1
]
=
value
;
customAttribute
.
array
[
offset_custom
+
2
]
=
value
;
offset_custom
+=
3
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces4
[
f
]
];
customAttribute
.
array
[
offset_custom
]
=
value
;
customAttribute
.
array
[
offset_custom
+
1
]
=
value
;
customAttribute
.
array
[
offset_custom
+
2
]
=
value
;
customAttribute
.
array
[
offset_custom
+
3
]
=
value
;
offset_custom
+=
4
;
}
}
}
else
if
(
customAttribute
.
size
===
2
)
{
if
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
v1
=
customAttribute
.
value
[
face
.
a
];
v2
=
customAttribute
.
value
[
face
.
b
];
v3
=
customAttribute
.
value
[
face
.
c
];
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v3
.
y
;
offset_custom
+=
6
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
v1
=
customAttribute
.
value
[
face
.
a
];
v2
=
customAttribute
.
value
[
face
.
b
];
v3
=
customAttribute
.
value
[
face
.
c
];
v4
=
customAttribute
.
value
[
face
.
d
];
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v4
.
x
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v4
.
y
;
offset_custom
+=
8
;
}
}
else
if
(
customAttribute
.
boundTo
===
"
faces
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces3
[
f
]
];
v1
=
value
;
v2
=
value
;
v3
=
value
;
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v3
.
y
;
offset_custom
+=
6
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces4
[
f
]
];
v1
=
value
;
v2
=
value
;
v3
=
value
;
v4
=
value
;
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v4
.
x
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v4
.
y
;
offset_custom
+=
8
;
}
}
}
else
if
(
customAttribute
.
size
===
3
)
{
var
pp
;
if
(
customAttribute
.
type
===
"
c
"
)
{
pp
=
[
"
r
"
,
"
g
"
,
"
b
"
];
}
else
{
pp
=
[
"
x
"
,
"
y
"
,
"
z
"
];
}
if
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
v1
=
customAttribute
.
value
[
face
.
a
];
v2
=
customAttribute
.
value
[
face
.
b
];
v3
=
customAttribute
.
value
[
face
.
c
];
customAttribute
.
array
[
offset_custom
]
=
v1
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
6
]
=
v3
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
7
]
=
v3
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
[
pp
[
2
]
];
offset_custom
+=
9
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
v1
=
customAttribute
.
value
[
face
.
a
];
v2
=
customAttribute
.
value
[
face
.
b
];
v3
=
customAttribute
.
value
[
face
.
c
];
v4
=
customAttribute
.
value
[
face
.
d
];
customAttribute
.
array
[
offset_custom
]
=
v1
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
6
]
=
v3
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
7
]
=
v3
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
9
]
=
v4
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
10
]
=
v4
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
11
]
=
v4
[
pp
[
2
]
];
offset_custom
+=
12
;
}
}
else
if
(
customAttribute
.
boundTo
===
"
faces
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces3
[
f
]
];
v1
=
value
;
v2
=
value
;
v3
=
value
;
customAttribute
.
array
[
offset_custom
]
=
v1
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
6
]
=
v3
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
7
]
=
v3
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
[
pp
[
2
]
];
offset_custom
+=
9
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces4
[
f
]
];
v1
=
value
;
v2
=
value
;
v3
=
value
;
v4
=
value
;
customAttribute
.
array
[
offset_custom
]
=
v1
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
6
]
=
v3
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
7
]
=
v3
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
9
]
=
v4
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
10
]
=
v4
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
11
]
=
v4
[
pp
[
2
]
];
offset_custom
+=
12
;
}
}
else
if
(
customAttribute
.
boundTo
===
"
faceVertices
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces3
[
f
]
];
v1
=
value
[
0
];
v2
=
value
[
1
];
v3
=
value
[
2
];
customAttribute
.
array
[
offset_custom
]
=
v1
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
6
]
=
v3
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
7
]
=
v3
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
[
pp
[
2
]
];
offset_custom
+=
9
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces4
[
f
]
];
v1
=
value
[
0
];
v2
=
value
[
1
];
v3
=
value
[
2
];
v4
=
value
[
3
];
customAttribute
.
array
[
offset_custom
]
=
v1
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
3
]
=
v2
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
6
]
=
v3
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
7
]
=
v3
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
[
pp
[
2
]
];
customAttribute
.
array
[
offset_custom
+
9
]
=
v4
[
pp
[
0
]
];
customAttribute
.
array
[
offset_custom
+
10
]
=
v4
[
pp
[
1
]
];
customAttribute
.
array
[
offset_custom
+
11
]
=
v4
[
pp
[
2
]
];
offset_custom
+=
12
;
}
}
}
else
if
(
customAttribute
.
size
===
4
)
{
if
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces3
[
f
]
];
v1
=
customAttribute
.
value
[
face
.
a
];
v2
=
customAttribute
.
value
[
face
.
b
];
v3
=
customAttribute
.
value
[
face
.
c
];
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
.
z
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v1
.
w
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v2
.
z
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v2
.
w
;
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
9
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
10
]
=
v3
.
z
;
customAttribute
.
array
[
offset_custom
+
11
]
=
v3
.
w
;
offset_custom
+=
12
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
face
=
obj_faces
[
chunk_faces4
[
f
]
];
v1
=
customAttribute
.
value
[
face
.
a
];
v2
=
customAttribute
.
value
[
face
.
b
];
v3
=
customAttribute
.
value
[
face
.
c
];
v4
=
customAttribute
.
value
[
face
.
d
];
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
.
z
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v1
.
w
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v2
.
z
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v2
.
w
;
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
9
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
10
]
=
v3
.
z
;
customAttribute
.
array
[
offset_custom
+
11
]
=
v3
.
w
;
customAttribute
.
array
[
offset_custom
+
12
]
=
v4
.
x
;
customAttribute
.
array
[
offset_custom
+
13
]
=
v4
.
y
;
customAttribute
.
array
[
offset_custom
+
14
]
=
v4
.
z
;
customAttribute
.
array
[
offset_custom
+
15
]
=
v4
.
w
;
offset_custom
+=
16
;
}
}
else
if
(
customAttribute
.
boundTo
===
"
faces
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces3
[
f
]
];
v1
=
value
;
v2
=
value
;
v3
=
value
;
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
.
z
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v1
.
w
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v2
.
z
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v2
.
w
;
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
9
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
10
]
=
v3
.
z
;
customAttribute
.
array
[
offset_custom
+
11
]
=
v3
.
w
;
offset_custom
+=
12
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces4
[
f
]
];
v1
=
value
;
v2
=
value
;
v3
=
value
;
v4
=
value
;
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
.
z
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v1
.
w
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v2
.
z
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v2
.
w
;
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
9
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
10
]
=
v3
.
z
;
customAttribute
.
array
[
offset_custom
+
11
]
=
v3
.
w
;
customAttribute
.
array
[
offset_custom
+
12
]
=
v4
.
x
;
customAttribute
.
array
[
offset_custom
+
13
]
=
v4
.
y
;
customAttribute
.
array
[
offset_custom
+
14
]
=
v4
.
z
;
customAttribute
.
array
[
offset_custom
+
15
]
=
v4
.
w
;
offset_custom
+=
16
;
}
}
else
if
(
customAttribute
.
boundTo
===
"
faceVertices
"
)
{
for
(
f
=
0
,
fl
=
chunk_faces3
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces3
[
f
]
];
v1
=
value
[
0
];
v2
=
value
[
1
];
v3
=
value
[
2
];
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
.
z
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v1
.
w
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v2
.
z
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v2
.
w
;
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
9
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
10
]
=
v3
.
z
;
customAttribute
.
array
[
offset_custom
+
11
]
=
v3
.
w
;
offset_custom
+=
12
;
}
for
(
f
=
0
,
fl
=
chunk_faces4
.
length
;
f
<
fl
;
f
++
)
{
value
=
customAttribute
.
value
[
chunk_faces4
[
f
]
];
v1
=
value
[
0
];
v2
=
value
[
1
];
v3
=
value
[
2
];
v4
=
value
[
3
];
customAttribute
.
array
[
offset_custom
]
=
v1
.
x
;
customAttribute
.
array
[
offset_custom
+
1
]
=
v1
.
y
;
customAttribute
.
array
[
offset_custom
+
2
]
=
v1
.
z
;
customAttribute
.
array
[
offset_custom
+
3
]
=
v1
.
w
;
customAttribute
.
array
[
offset_custom
+
4
]
=
v2
.
x
;
customAttribute
.
array
[
offset_custom
+
5
]
=
v2
.
y
;
customAttribute
.
array
[
offset_custom
+
6
]
=
v2
.
z
;
customAttribute
.
array
[
offset_custom
+
7
]
=
v2
.
w
;
customAttribute
.
array
[
offset_custom
+
8
]
=
v3
.
x
;
customAttribute
.
array
[
offset_custom
+
9
]
=
v3
.
y
;
customAttribute
.
array
[
offset_custom
+
10
]
=
v3
.
z
;
customAttribute
.
array
[
offset_custom
+
11
]
=
v3
.
w
;
customAttribute
.
array
[
offset_custom
+
12
]
=
v4
.
x
;
customAttribute
.
array
[
offset_custom
+
13
]
=
v4
.
y
;
customAttribute
.
array
[
offset_custom
+
14
]
=
v4
.
z
;
customAttribute
.
array
[
offset_custom
+
15
]
=
v4
.
w
;
offset_custom
+=
16
;
}
}
}
renderer
.
setDynamicArrayBuffer
(
customAttribute
.
buffer
,
customAttribute
.
array
);
}
}
if
(
dispose
)
{
delete
geometryGroup
.
__inittedArrays
;
delete
geometryGroup
.
__colorArray
;
delete
geometryGroup
.
__normalArray
;
delete
geometryGroup
.
__tangentArray
;
delete
geometryGroup
.
__uvArray
;
delete
geometryGroup
.
__uv2Array
;
delete
geometryGroup
.
__faceArray
;
delete
geometryGroup
.
__vertexArray
;
delete
geometryGroup
.
__lineArray
;
delete
geometryGroup
.
__skinIndexArray
;
delete
geometryGroup
.
__skinWeightArray
;
}
};
\ No newline at end of file
src/renderers/webgl/objects/Object3DRenderer.js
0 → 100644
浏览文件 @
1efe37f9
THREE
.
WebGLRenderer2
.
Object3DRenderer
=
function
(
lowlevelrenderer
,
info
){
this
.
renderer
=
lowlevelrenderer
;
this
.
info
=
info
;
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
getBufferMaterial
=
function
(
object
,
geometryGroup
)
{
return
object
.
material
instanceof
THREE
.
MeshFaceMaterial
?
object
.
material
.
materials
[
geometryGroup
.
materialIndex
]
:
object
.
material
;
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
bufferGuessUVType
=
function
(
material
)
{
// material must use some texture to require uvs
if
(
material
.
map
||
material
.
lightMap
||
material
.
bumpMap
||
material
.
normalMap
||
material
.
specularMap
||
material
instanceof
THREE
.
ShaderMaterial
)
{
return
true
;
}
return
false
;
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
bufferGuessNormalType
=
function
(
material
)
{
// only MeshBasicMaterial and MeshDepthMaterial don't need normals
if
(
(
material
instanceof
THREE
.
MeshBasicMaterial
&&
!
material
.
envMap
)
||
material
instanceof
THREE
.
MeshDepthMaterial
)
{
return
false
;
}
if
(
this
.
materialNeedsSmoothNormals
(
material
)
)
{
return
THREE
.
SmoothShading
;
}
else
{
return
THREE
.
FlatShading
;
}
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
materialNeedsSmoothNormals
=
function
(
material
)
{
return
material
&&
material
.
shading
!==
undefined
&&
material
.
shading
===
THREE
.
SmoothShading
;
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
bufferGuessVertexColorType
=
function
(
material
)
{
if
(
material
.
vertexColors
)
{
return
material
.
vertexColors
;
}
return
false
;
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
initCustomAttributes
=
function
(
geometry
,
object
)
{
var
nvertices
=
geometry
.
vertices
.
length
;
var
material
=
object
.
material
;
if
(
material
.
attributes
)
{
if
(
geometry
.
__webglCustomAttributesList
===
undefined
)
{
geometry
.
__webglCustomAttributesList
=
[];
}
for
(
var
a
in
material
.
attributes
)
{
var
attribute
=
material
.
attributes
[
a
];
if
(
!
attribute
.
__webglInitialized
||
attribute
.
createUniqueBuffers
)
{
attribute
.
__webglInitialized
=
true
;
var
size
=
1
;
// "f" and "i"
if
(
attribute
.
type
===
"
v2
"
)
size
=
2
;
else
if
(
attribute
.
type
===
"
v3
"
)
size
=
3
;
else
if
(
attribute
.
type
===
"
v4
"
)
size
=
4
;
else
if
(
attribute
.
type
===
"
c
"
)
size
=
3
;
attribute
.
size
=
size
;
attribute
.
array
=
new
Float32Array
(
nvertices
*
size
);
attribute
.
buffer
=
this
.
renderer
.
createBuffer
();
attribute
.
buffer
.
belongsToAttribute
=
a
;
attribute
.
needsUpdate
=
true
;
}
geometry
.
__webglCustomAttributesList
.
push
(
attribute
);
}
}
};
THREE
.
WebGLRenderer2
.
Object3DRenderer
.
prototype
.
numericalSort
=
function
(
a
,
b
)
{
return
b
[
0
]
-
a
[
0
];
};
\ No newline at end of file
src/renderers/webgl/objects/ParticleRenderer.js
0 → 100644
浏览文件 @
1efe37f9
THREE
.
WebGLRenderer2
.
ParticleRenderer
=
function
(
lowlevelrenderer
,
info
){
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
call
(
this
,
lowlevelrenderer
,
info
);
};
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
prototype
=
Object
.
create
(
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
prototype
);
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
prototype
.
createBuffers
=
function
(
geometry
)
{
var
renderer
=
this
.
renderer
;
geometry
.
__webglVertexBuffer
=
renderer
.
createBuffer
();
geometry
.
__webglColorBuffer
=
renderer
.
createBuffer
();
this
.
info
.
memory
.
geometries
++
;
};
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
prototype
.
initBuffers
=
function
(
geometry
,
object
)
{
var
nvertices
=
geometry
.
vertices
.
length
;
geometry
.
__vertexArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__colorArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__sortArray
=
[];
geometry
.
__webglParticleCount
=
nvertices
;
this
.
initCustomAttributes
(
geometry
,
object
);
};
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
prototype
.
setBuffers
=
function
(
geometry
,
object
,
projectionScreenMatrix
)
{
var
renderer
=
this
.
renderer
;
var
v
,
c
,
vertex
,
offset
,
index
,
color
,
vertices
=
geometry
.
vertices
,
vl
=
vertices
.
length
,
colors
=
geometry
.
colors
,
cl
=
colors
.
length
,
vertexArray
=
geometry
.
__vertexArray
,
colorArray
=
geometry
.
__colorArray
,
sortArray
=
geometry
.
__sortArray
,
dirtyVertices
=
geometry
.
verticesNeedUpdate
,
dirtyElements
=
geometry
.
elementsNeedUpdate
,
dirtyColors
=
geometry
.
colorsNeedUpdate
,
customAttributes
=
geometry
.
__webglCustomAttributesList
,
i
,
il
,
a
,
ca
,
cal
,
value
,
customAttribute
;
var
_projScreenMatrixPS
=
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
_m1
,
_vector3
=
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
_v1
;
if
(
object
.
sortParticles
)
{
_projScreenMatrixPS
.
copy
(
projectionScreenMatrix
);
_projScreenMatrixPS
.
multiplySelf
(
object
.
matrixWorld
);
for
(
v
=
0
;
v
<
vl
;
v
++
)
{
vertex
=
vertices
[
v
];
_vector3
.
copy
(
vertex
);
_vector3
.
applyMatrix4
(
_projScreenMatrixPS
);
sortArray
[
v
]
=
[
_vector3
.
z
,
v
];
}
sortArray
.
sort
(
this
.
numericalSort
);
for
(
v
=
0
;
v
<
vl
;
v
++
)
{
vertex
=
vertices
[
sortArray
[
v
][
1
]
];
offset
=
v
*
3
;
vertexArray
[
offset
]
=
vertex
.
x
;
vertexArray
[
offset
+
1
]
=
vertex
.
y
;
vertexArray
[
offset
+
2
]
=
vertex
.
z
;
}
for
(
c
=
0
;
c
<
cl
;
c
++
)
{
offset
=
c
*
3
;
color
=
colors
[
sortArray
[
c
][
1
]
];
colorArray
[
offset
]
=
color
.
r
;
colorArray
[
offset
+
1
]
=
color
.
g
;
colorArray
[
offset
+
2
]
=
color
.
b
;
}
if
(
customAttributes
)
{
for
(
i
=
0
,
il
=
customAttributes
.
length
;
i
<
il
;
i
++
)
{
customAttribute
=
customAttributes
[
i
];
if
(
!
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
)
continue
;
offset
=
0
;
cal
=
customAttribute
.
value
.
length
;
if
(
customAttribute
.
size
===
1
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
index
=
sortArray
[
ca
][
1
];
customAttribute
.
array
[
ca
]
=
customAttribute
.
value
[
index
];
}
}
else
if
(
customAttribute
.
size
===
2
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
index
=
sortArray
[
ca
][
1
];
value
=
customAttribute
.
value
[
index
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
offset
+=
2
;
}
}
else
if
(
customAttribute
.
size
===
3
)
{
if
(
customAttribute
.
type
===
"
c
"
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
index
=
sortArray
[
ca
][
1
];
value
=
customAttribute
.
value
[
index
];
customAttribute
.
array
[
offset
]
=
value
.
r
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
g
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
b
;
offset
+=
3
;
}
}
else
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
index
=
sortArray
[
ca
][
1
];
value
=
customAttribute
.
value
[
index
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
offset
+=
3
;
}
}
}
else
if
(
customAttribute
.
size
===
4
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
index
=
sortArray
[
ca
][
1
];
value
=
customAttribute
.
value
[
index
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
customAttribute
.
array
[
offset
+
3
]
=
value
.
w
;
offset
+=
4
;
}
}
}
}
}
else
{
if
(
dirtyVertices
)
{
for
(
v
=
0
;
v
<
vl
;
v
++
)
{
vertex
=
vertices
[
v
];
offset
=
v
*
3
;
vertexArray
[
offset
]
=
vertex
.
x
;
vertexArray
[
offset
+
1
]
=
vertex
.
y
;
vertexArray
[
offset
+
2
]
=
vertex
.
z
;
}
}
if
(
dirtyColors
)
{
for
(
c
=
0
;
c
<
cl
;
c
++
)
{
color
=
colors
[
c
];
offset
=
c
*
3
;
colorArray
[
offset
]
=
color
.
r
;
colorArray
[
offset
+
1
]
=
color
.
g
;
colorArray
[
offset
+
2
]
=
color
.
b
;
}
}
if
(
customAttributes
)
{
for
(
i
=
0
,
il
=
customAttributes
.
length
;
i
<
il
;
i
++
)
{
customAttribute
=
customAttributes
[
i
];
if
(
customAttribute
.
needsUpdate
&&
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
)
{
cal
=
customAttribute
.
value
.
length
;
offset
=
0
;
if
(
customAttribute
.
size
===
1
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
customAttribute
.
array
[
ca
]
=
customAttribute
.
value
[
ca
];
}
}
else
if
(
customAttribute
.
size
===
2
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
offset
+=
2
;
}
}
else
if
(
customAttribute
.
size
===
3
)
{
if
(
customAttribute
.
type
===
"
c
"
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
r
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
g
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
b
;
offset
+=
3
;
}
}
else
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
offset
+=
3
;
}
}
}
else
if
(
customAttribute
.
size
===
4
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
customAttribute
.
array
[
offset
+
3
]
=
value
.
w
;
offset
+=
4
;
}
}
}
}
}
}
if
(
dirtyVertices
||
object
.
sortParticles
)
{
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglVertexBuffer
,
vertexArray
);
}
if
(
dirtyColors
||
object
.
sortParticles
)
{
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglColorBuffer
,
colorArray
);
}
if
(
customAttributes
)
{
for
(
i
=
0
,
il
=
customAttributes
.
length
;
i
<
il
;
i
++
)
{
customAttribute
=
customAttributes
[
i
];
if
(
customAttribute
.
needsUpdate
||
object
.
sortParticles
)
{
renderer
.
setDynamicArrayBuffer
(
customAttribute
.
buffer
,
customAttribute
.
array
);
}
}
}
};
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
_m1
=
new
THREE
.
Matrix4
();
THREE
.
WebGLRenderer2
.
ParticleRenderer
.
_v1
=
new
THREE
.
Vector3
();
\ No newline at end of file
src/renderers/webgl/objects/RibbonRenderer.js
0 → 100644
浏览文件 @
1efe37f9
THREE
.
WebGLRenderer2
.
RibbonRenderer
=
function
(
lowlevelrenderer
,
info
){
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
call
(
this
,
lowlevelrenderer
,
info
);
};
THREE
.
WebGLRenderer2
.
RibbonRenderer
.
prototype
=
Object
.
create
(
THREE
.
WebGLRenderer2
.
Object3DObjectRenderer
.
prototype
);
THREE
.
WebGLRenderer2
.
RibbonRenderer
.
prototype
.
createBuffers
=
function
(
geometry
)
{
var
renderer
=
this
.
renderer
;
geometry
.
__webglVertexBuffer
=
renderer
.
createBuffer
();
geometry
.
__webglColorBuffer
=
renderer
.
createBuffer
();
geometry
.
__webglNormalBuffer
=
renderer
.
createBuffer
();
this
.
info
.
memory
.
geometries
++
;
};
THREE
.
WebGLRenderer2
.
RibbonRenderer
.
prototype
.
initBuffers
=
function
(
geometry
,
object
)
{
var
nvertices
=
geometry
.
vertices
.
length
;
geometry
.
__vertexArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__colorArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__normalArray
=
new
Float32Array
(
nvertices
*
3
);
geometry
.
__webglVertexCount
=
nvertices
;
this
.
initCustomAttributes
(
geometry
,
object
);
};
THREE
.
WebGLRenderer2
.
RibbonRenderer
.
prototype
.
setBuffers
=
function
(
geometry
,
object
,
projectionScreenMatrix
)
{
var
renderer
=
this
.
renderer
;
var
v
,
c
,
n
,
vertex
,
offset
,
color
,
normal
,
i
,
il
,
ca
,
cal
,
customAttribute
,
value
,
vertices
=
geometry
.
vertices
,
colors
=
geometry
.
colors
,
normals
=
geometry
.
normals
,
vl
=
vertices
.
length
,
cl
=
colors
.
length
,
nl
=
normals
.
length
,
vertexArray
=
geometry
.
__vertexArray
,
colorArray
=
geometry
.
__colorArray
,
normalArray
=
geometry
.
__normalArray
,
dirtyVertices
=
geometry
.
verticesNeedUpdate
,
dirtyColors
=
geometry
.
colorsNeedUpdate
,
dirtyNormals
=
geometry
.
normalsNeedUpdate
,
customAttributes
=
geometry
.
__webglCustomAttributesList
;
if
(
dirtyVertices
)
{
for
(
v
=
0
;
v
<
vl
;
v
++
)
{
vertex
=
vertices
[
v
];
offset
=
v
*
3
;
vertexArray
[
offset
]
=
vertex
.
x
;
vertexArray
[
offset
+
1
]
=
vertex
.
y
;
vertexArray
[
offset
+
2
]
=
vertex
.
z
;
}
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglVertexBuffer
,
vertexArray
);
}
if
(
dirtyColors
)
{
for
(
c
=
0
;
c
<
cl
;
c
++
)
{
color
=
colors
[
c
];
offset
=
c
*
3
;
colorArray
[
offset
]
=
color
.
r
;
colorArray
[
offset
+
1
]
=
color
.
g
;
colorArray
[
offset
+
2
]
=
color
.
b
;
}
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglColorBuffer
,
colorArray
);
}
if
(
dirtyNormals
)
{
for
(
n
=
0
;
n
<
nl
;
n
++
)
{
normal
=
normals
[
n
];
offset
=
n
*
3
;
normalArray
[
offset
]
=
normal
.
x
;
normalArray
[
offset
+
1
]
=
normal
.
y
;
normalArray
[
offset
+
2
]
=
normal
.
z
;
}
renderer
.
setDynamicArrayBuffer
(
geometry
.
__webglNormalBuffer
,
normalArray
);
}
if
(
customAttributes
)
{
for
(
i
=
0
,
il
=
customAttributes
.
length
;
i
<
il
;
i
++
)
{
customAttribute
=
customAttributes
[
i
];
if
(
customAttribute
.
needsUpdate
&&
(
customAttribute
.
boundTo
===
undefined
||
customAttribute
.
boundTo
===
"
vertices
"
)
)
{
offset
=
0
;
cal
=
customAttribute
.
value
.
length
;
if
(
customAttribute
.
size
===
1
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
customAttribute
.
array
[
ca
]
=
customAttribute
.
value
[
ca
];
}
}
else
if
(
customAttribute
.
size
===
2
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
offset
+=
2
;
}
}
else
if
(
customAttribute
.
size
===
3
)
{
if
(
customAttribute
.
type
===
"
c
"
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
r
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
g
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
b
;
offset
+=
3
;
}
}
else
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
offset
+=
3
;
}
}
}
else
if
(
customAttribute
.
size
===
4
)
{
for
(
ca
=
0
;
ca
<
cal
;
ca
++
)
{
value
=
customAttribute
.
value
[
ca
];
customAttribute
.
array
[
offset
]
=
value
.
x
;
customAttribute
.
array
[
offset
+
1
]
=
value
.
y
;
customAttribute
.
array
[
offset
+
2
]
=
value
.
z
;
customAttribute
.
array
[
offset
+
3
]
=
value
.
w
;
offset
+=
4
;
}
}
renderer
.
setDynamicArrayBuffer
(
customAttribute
.
buffer
,
customAttribute
.
array
);
}
}
}
};
\ No newline at end of file
utils/includes/common.json
浏览文件 @
1efe37f9
...
@@ -73,8 +73,16 @@
...
@@ -73,8 +73,16 @@
"../src/scenes/Fog.js"
,
"../src/scenes/Fog.js"
,
"../src/scenes/FogExp2.js"
,
"../src/scenes/FogExp2.js"
,
"../src/renderers/CanvasRenderer.js"
,
"../src/renderers/CanvasRenderer.js"
,
"../src/renderers/WebGLShaders.js"
,
"../src/renderers/WebGLRenderer.js"
,
"../src/renderers/WebGLRenderer.js"
,
"../src/renderers/WebGLShaders.js"
,
"../src/renderers/WebGLRenderer2.js"
,
"../src/renderers/webgl/LowLevelRenderer.js"
,
"../src/renderers/webgl/ShaderBuilder.js"
,
"../src/renderers/webgl/objects/Object3DRenderer.js"
,
"../src/renderers/webgl/objects/MeshRenderer.js"
,
"../src/renderers/webgl/objects/ParticleRenderer.js"
,
"../src/renderers/webgl/objects/LineRenderer.js"
,
"../src/renderers/webgl/objects/RibbonRenderer.js"
,
"../src/renderers/WebGLRenderTarget.js"
,
"../src/renderers/WebGLRenderTarget.js"
,
"../src/renderers/WebGLRenderTargetCube.js"
,
"../src/renderers/WebGLRenderTargetCube.js"
,
"../src/renderers/renderables/RenderableVertex.js"
,
"../src/renderers/renderables/RenderableVertex.js"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录