Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Ablesons
three.js
提交
d695b757
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,发现更多精彩内容 >>
提交
d695b757
编写于
1月 03, 2019
作者:
M
Mr.doob
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added first converted files.
上级
eebed390
变更
5
展开全部
隐藏空白更改
内联
并排
Showing
5 changed file
with
7162 addition
and
0 deletion
+7162
-0
examples/jsm/controls/MapControls.js
examples/jsm/controls/MapControls.js
+1166
-0
examples/jsm/controls/OrbitControls.js
examples/jsm/controls/OrbitControls.js
+1062
-0
examples/jsm/controls/TrackballControls.js
examples/jsm/controls/TrackballControls.js
+628
-0
examples/jsm/loaders/GLTFLoader.js
examples/jsm/loaders/GLTFLoader.js
+3490
-0
examples/jsm/loaders/OBJLoader.js
examples/jsm/loaders/OBJLoader.js
+816
-0
未找到文件。
examples/jsm/controls/MapControls.js
0 → 100644
浏览文件 @
d695b757
此差异已折叠。
点击以展开。
examples/jsm/controls/OrbitControls.js
0 → 100644
浏览文件 @
d695b757
此差异已折叠。
点击以展开。
examples/jsm/controls/TrackballControls.js
0 → 100644
浏览文件 @
d695b757
/**
* @author Eberhard Graether / http://egraether.com/
* @author Mark Lundin / http://mark-lundin.com
* @author Simone Manini / http://daron1337.github.io
* @author Luca Antiga / http://lantiga.github.io
*/
import
{
EventDispatcher
,
Quaternion
,
Vector2
,
Vector3
}
from
"
../../../build/three.module.js
"
;
var
TrackballControls
=
function
(
object
,
domElement
)
{
var
_this
=
this
;
var
STATE
=
{
NONE
:
-
1
,
ROTATE
:
0
,
ZOOM
:
1
,
PAN
:
2
,
TOUCH_ROTATE
:
3
,
TOUCH_ZOOM_PAN
:
4
};
this
.
object
=
object
;
this
.
domElement
=
(
domElement
!==
undefined
)
?
domElement
:
document
;
// API
this
.
enabled
=
true
;
this
.
screen
=
{
left
:
0
,
top
:
0
,
width
:
0
,
height
:
0
};
this
.
rotateSpeed
=
1.0
;
this
.
zoomSpeed
=
1.2
;
this
.
panSpeed
=
0.3
;
this
.
noRotate
=
false
;
this
.
noZoom
=
false
;
this
.
noPan
=
false
;
this
.
staticMoving
=
false
;
this
.
dynamicDampingFactor
=
0.2
;
this
.
minDistance
=
0
;
this
.
maxDistance
=
Infinity
;
this
.
keys
=
[
65
/*A*/
,
83
/*S*/
,
68
/*D*/
];
// internals
this
.
target
=
new
Vector3
();
var
EPS
=
0.000001
;
var
lastPosition
=
new
Vector3
();
var
_state
=
STATE
.
NONE
,
_prevState
=
STATE
.
NONE
,
_eye
=
new
Vector3
(),
_movePrev
=
new
Vector2
(),
_moveCurr
=
new
Vector2
(),
_lastAxis
=
new
Vector3
(),
_lastAngle
=
0
,
_zoomStart
=
new
Vector2
(),
_zoomEnd
=
new
Vector2
(),
_touchZoomDistanceStart
=
0
,
_touchZoomDistanceEnd
=
0
,
_panStart
=
new
Vector2
(),
_panEnd
=
new
Vector2
();
// for reset
this
.
target0
=
this
.
target
.
clone
();
this
.
position0
=
this
.
object
.
position
.
clone
();
this
.
up0
=
this
.
object
.
up
.
clone
();
// events
var
changeEvent
=
{
type
:
'
change
'
};
var
startEvent
=
{
type
:
'
start
'
};
var
endEvent
=
{
type
:
'
end
'
};
// methods
this
.
handleResize
=
function
()
{
if
(
this
.
domElement
===
document
)
{
this
.
screen
.
left
=
0
;
this
.
screen
.
top
=
0
;
this
.
screen
.
width
=
window
.
innerWidth
;
this
.
screen
.
height
=
window
.
innerHeight
;
}
else
{
var
box
=
this
.
domElement
.
getBoundingClientRect
();
// adjustments come from similar code in the jquery offset() function
var
d
=
this
.
domElement
.
ownerDocument
.
documentElement
;
this
.
screen
.
left
=
box
.
left
+
window
.
pageXOffset
-
d
.
clientLeft
;
this
.
screen
.
top
=
box
.
top
+
window
.
pageYOffset
-
d
.
clientTop
;
this
.
screen
.
width
=
box
.
width
;
this
.
screen
.
height
=
box
.
height
;
}
};
var
getMouseOnScreen
=
(
function
()
{
var
vector
=
new
Vector2
();
return
function
getMouseOnScreen
(
pageX
,
pageY
)
{
vector
.
set
(
(
pageX
-
_this
.
screen
.
left
)
/
_this
.
screen
.
width
,
(
pageY
-
_this
.
screen
.
top
)
/
_this
.
screen
.
height
);
return
vector
;
};
}()
);
var
getMouseOnCircle
=
(
function
()
{
var
vector
=
new
Vector2
();
return
function
getMouseOnCircle
(
pageX
,
pageY
)
{
vector
.
set
(
(
(
pageX
-
_this
.
screen
.
width
*
0.5
-
_this
.
screen
.
left
)
/
(
_this
.
screen
.
width
*
0.5
)
),
(
(
_this
.
screen
.
height
+
2
*
(
_this
.
screen
.
top
-
pageY
)
)
/
_this
.
screen
.
width
)
// screen.width intentional
);
return
vector
;
};
}()
);
this
.
rotateCamera
=
(
function
()
{
var
axis
=
new
Vector3
(),
quaternion
=
new
Quaternion
(),
eyeDirection
=
new
Vector3
(),
objectUpDirection
=
new
Vector3
(),
objectSidewaysDirection
=
new
Vector3
(),
moveDirection
=
new
Vector3
(),
angle
;
return
function
rotateCamera
()
{
moveDirection
.
set
(
_moveCurr
.
x
-
_movePrev
.
x
,
_moveCurr
.
y
-
_movePrev
.
y
,
0
);
angle
=
moveDirection
.
length
();
if
(
angle
)
{
_eye
.
copy
(
_this
.
object
.
position
).
sub
(
_this
.
target
);
eyeDirection
.
copy
(
_eye
).
normalize
();
objectUpDirection
.
copy
(
_this
.
object
.
up
).
normalize
();
objectSidewaysDirection
.
crossVectors
(
objectUpDirection
,
eyeDirection
).
normalize
();
objectUpDirection
.
setLength
(
_moveCurr
.
y
-
_movePrev
.
y
);
objectSidewaysDirection
.
setLength
(
_moveCurr
.
x
-
_movePrev
.
x
);
moveDirection
.
copy
(
objectUpDirection
.
add
(
objectSidewaysDirection
)
);
axis
.
crossVectors
(
moveDirection
,
_eye
).
normalize
();
angle
*=
_this
.
rotateSpeed
;
quaternion
.
setFromAxisAngle
(
axis
,
angle
);
_eye
.
applyQuaternion
(
quaternion
);
_this
.
object
.
up
.
applyQuaternion
(
quaternion
);
_lastAxis
.
copy
(
axis
);
_lastAngle
=
angle
;
}
else
if
(
!
_this
.
staticMoving
&&
_lastAngle
)
{
_lastAngle
*=
Math
.
sqrt
(
1.0
-
_this
.
dynamicDampingFactor
);
_eye
.
copy
(
_this
.
object
.
position
).
sub
(
_this
.
target
);
quaternion
.
setFromAxisAngle
(
_lastAxis
,
_lastAngle
);
_eye
.
applyQuaternion
(
quaternion
);
_this
.
object
.
up
.
applyQuaternion
(
quaternion
);
}
_movePrev
.
copy
(
_moveCurr
);
};
}()
);
this
.
zoomCamera
=
function
()
{
var
factor
;
if
(
_state
===
STATE
.
TOUCH_ZOOM_PAN
)
{
factor
=
_touchZoomDistanceStart
/
_touchZoomDistanceEnd
;
_touchZoomDistanceStart
=
_touchZoomDistanceEnd
;
_eye
.
multiplyScalar
(
factor
);
}
else
{
factor
=
1.0
+
(
_zoomEnd
.
y
-
_zoomStart
.
y
)
*
_this
.
zoomSpeed
;
if
(
factor
!==
1.0
&&
factor
>
0.0
)
{
_eye
.
multiplyScalar
(
factor
);
}
if
(
_this
.
staticMoving
)
{
_zoomStart
.
copy
(
_zoomEnd
);
}
else
{
_zoomStart
.
y
+=
(
_zoomEnd
.
y
-
_zoomStart
.
y
)
*
this
.
dynamicDampingFactor
;
}
}
};
this
.
panCamera
=
(
function
()
{
var
mouseChange
=
new
Vector2
(),
objectUp
=
new
Vector3
(),
pan
=
new
Vector3
();
return
function
panCamera
()
{
mouseChange
.
copy
(
_panEnd
).
sub
(
_panStart
);
if
(
mouseChange
.
lengthSq
()
)
{
mouseChange
.
multiplyScalar
(
_eye
.
length
()
*
_this
.
panSpeed
);
pan
.
copy
(
_eye
).
cross
(
_this
.
object
.
up
).
setLength
(
mouseChange
.
x
);
pan
.
add
(
objectUp
.
copy
(
_this
.
object
.
up
).
setLength
(
mouseChange
.
y
)
);
_this
.
object
.
position
.
add
(
pan
);
_this
.
target
.
add
(
pan
);
if
(
_this
.
staticMoving
)
{
_panStart
.
copy
(
_panEnd
);
}
else
{
_panStart
.
add
(
mouseChange
.
subVectors
(
_panEnd
,
_panStart
).
multiplyScalar
(
_this
.
dynamicDampingFactor
)
);
}
}
};
}()
);
this
.
checkDistances
=
function
()
{
if
(
!
_this
.
noZoom
||
!
_this
.
noPan
)
{
if
(
_eye
.
lengthSq
()
>
_this
.
maxDistance
*
_this
.
maxDistance
)
{
_this
.
object
.
position
.
addVectors
(
_this
.
target
,
_eye
.
setLength
(
_this
.
maxDistance
)
);
_zoomStart
.
copy
(
_zoomEnd
);
}
if
(
_eye
.
lengthSq
()
<
_this
.
minDistance
*
_this
.
minDistance
)
{
_this
.
object
.
position
.
addVectors
(
_this
.
target
,
_eye
.
setLength
(
_this
.
minDistance
)
);
_zoomStart
.
copy
(
_zoomEnd
);
}
}
};
this
.
update
=
function
()
{
_eye
.
subVectors
(
_this
.
object
.
position
,
_this
.
target
);
if
(
!
_this
.
noRotate
)
{
_this
.
rotateCamera
();
}
if
(
!
_this
.
noZoom
)
{
_this
.
zoomCamera
();
}
if
(
!
_this
.
noPan
)
{
_this
.
panCamera
();
}
_this
.
object
.
position
.
addVectors
(
_this
.
target
,
_eye
);
_this
.
checkDistances
();
_this
.
object
.
lookAt
(
_this
.
target
);
if
(
lastPosition
.
distanceToSquared
(
_this
.
object
.
position
)
>
EPS
)
{
_this
.
dispatchEvent
(
changeEvent
);
lastPosition
.
copy
(
_this
.
object
.
position
);
}
};
this
.
reset
=
function
()
{
_state
=
STATE
.
NONE
;
_prevState
=
STATE
.
NONE
;
_this
.
target
.
copy
(
_this
.
target0
);
_this
.
object
.
position
.
copy
(
_this
.
position0
);
_this
.
object
.
up
.
copy
(
_this
.
up0
);
_eye
.
subVectors
(
_this
.
object
.
position
,
_this
.
target
);
_this
.
object
.
lookAt
(
_this
.
target
);
_this
.
dispatchEvent
(
changeEvent
);
lastPosition
.
copy
(
_this
.
object
.
position
);
};
// listeners
function
keydown
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
window
.
removeEventListener
(
'
keydown
'
,
keydown
);
_prevState
=
_state
;
if
(
_state
!==
STATE
.
NONE
)
{
return
;
}
else
if
(
event
.
keyCode
===
_this
.
keys
[
STATE
.
ROTATE
]
&&
!
_this
.
noRotate
)
{
_state
=
STATE
.
ROTATE
;
}
else
if
(
event
.
keyCode
===
_this
.
keys
[
STATE
.
ZOOM
]
&&
!
_this
.
noZoom
)
{
_state
=
STATE
.
ZOOM
;
}
else
if
(
event
.
keyCode
===
_this
.
keys
[
STATE
.
PAN
]
&&
!
_this
.
noPan
)
{
_state
=
STATE
.
PAN
;
}
}
function
keyup
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
_state
=
_prevState
;
window
.
addEventListener
(
'
keydown
'
,
keydown
,
false
);
}
function
mousedown
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
event
.
preventDefault
();
event
.
stopPropagation
();
if
(
_state
===
STATE
.
NONE
)
{
_state
=
event
.
button
;
}
if
(
_state
===
STATE
.
ROTATE
&&
!
_this
.
noRotate
)
{
_moveCurr
.
copy
(
getMouseOnCircle
(
event
.
pageX
,
event
.
pageY
)
);
_movePrev
.
copy
(
_moveCurr
);
}
else
if
(
_state
===
STATE
.
ZOOM
&&
!
_this
.
noZoom
)
{
_zoomStart
.
copy
(
getMouseOnScreen
(
event
.
pageX
,
event
.
pageY
)
);
_zoomEnd
.
copy
(
_zoomStart
);
}
else
if
(
_state
===
STATE
.
PAN
&&
!
_this
.
noPan
)
{
_panStart
.
copy
(
getMouseOnScreen
(
event
.
pageX
,
event
.
pageY
)
);
_panEnd
.
copy
(
_panStart
);
}
document
.
addEventListener
(
'
mousemove
'
,
mousemove
,
false
);
document
.
addEventListener
(
'
mouseup
'
,
mouseup
,
false
);
_this
.
dispatchEvent
(
startEvent
);
}
function
mousemove
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
event
.
preventDefault
();
event
.
stopPropagation
();
if
(
_state
===
STATE
.
ROTATE
&&
!
_this
.
noRotate
)
{
_movePrev
.
copy
(
_moveCurr
);
_moveCurr
.
copy
(
getMouseOnCircle
(
event
.
pageX
,
event
.
pageY
)
);
}
else
if
(
_state
===
STATE
.
ZOOM
&&
!
_this
.
noZoom
)
{
_zoomEnd
.
copy
(
getMouseOnScreen
(
event
.
pageX
,
event
.
pageY
)
);
}
else
if
(
_state
===
STATE
.
PAN
&&
!
_this
.
noPan
)
{
_panEnd
.
copy
(
getMouseOnScreen
(
event
.
pageX
,
event
.
pageY
)
);
}
}
function
mouseup
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
event
.
preventDefault
();
event
.
stopPropagation
();
_state
=
STATE
.
NONE
;
document
.
removeEventListener
(
'
mousemove
'
,
mousemove
);
document
.
removeEventListener
(
'
mouseup
'
,
mouseup
);
_this
.
dispatchEvent
(
endEvent
);
}
function
mousewheel
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
if
(
_this
.
noZoom
===
true
)
return
;
event
.
preventDefault
();
event
.
stopPropagation
();
switch
(
event
.
deltaMode
)
{
case
2
:
// Zoom in pages
_zoomStart
.
y
-=
event
.
deltaY
*
0.025
;
break
;
case
1
:
// Zoom in lines
_zoomStart
.
y
-=
event
.
deltaY
*
0.01
;
break
;
default
:
// undefined, 0, assume pixels
_zoomStart
.
y
-=
event
.
deltaY
*
0.00025
;
break
;
}
_this
.
dispatchEvent
(
startEvent
);
_this
.
dispatchEvent
(
endEvent
);
}
function
touchstart
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
event
.
preventDefault
();
switch
(
event
.
touches
.
length
)
{
case
1
:
_state
=
STATE
.
TOUCH_ROTATE
;
_moveCurr
.
copy
(
getMouseOnCircle
(
event
.
touches
[
0
].
pageX
,
event
.
touches
[
0
].
pageY
)
);
_movePrev
.
copy
(
_moveCurr
);
break
;
default
:
// 2 or more
_state
=
STATE
.
TOUCH_ZOOM_PAN
;
var
dx
=
event
.
touches
[
0
].
pageX
-
event
.
touches
[
1
].
pageX
;
var
dy
=
event
.
touches
[
0
].
pageY
-
event
.
touches
[
1
].
pageY
;
_touchZoomDistanceEnd
=
_touchZoomDistanceStart
=
Math
.
sqrt
(
dx
*
dx
+
dy
*
dy
);
var
x
=
(
event
.
touches
[
0
].
pageX
+
event
.
touches
[
1
].
pageX
)
/
2
;
var
y
=
(
event
.
touches
[
0
].
pageY
+
event
.
touches
[
1
].
pageY
)
/
2
;
_panStart
.
copy
(
getMouseOnScreen
(
x
,
y
)
);
_panEnd
.
copy
(
_panStart
);
break
;
}
_this
.
dispatchEvent
(
startEvent
);
}
function
touchmove
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
event
.
preventDefault
();
event
.
stopPropagation
();
switch
(
event
.
touches
.
length
)
{
case
1
:
_movePrev
.
copy
(
_moveCurr
);
_moveCurr
.
copy
(
getMouseOnCircle
(
event
.
touches
[
0
].
pageX
,
event
.
touches
[
0
].
pageY
)
);
break
;
default
:
// 2 or more
var
dx
=
event
.
touches
[
0
].
pageX
-
event
.
touches
[
1
].
pageX
;
var
dy
=
event
.
touches
[
0
].
pageY
-
event
.
touches
[
1
].
pageY
;
_touchZoomDistanceEnd
=
Math
.
sqrt
(
dx
*
dx
+
dy
*
dy
);
var
x
=
(
event
.
touches
[
0
].
pageX
+
event
.
touches
[
1
].
pageX
)
/
2
;
var
y
=
(
event
.
touches
[
0
].
pageY
+
event
.
touches
[
1
].
pageY
)
/
2
;
_panEnd
.
copy
(
getMouseOnScreen
(
x
,
y
)
);
break
;
}
}
function
touchend
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
switch
(
event
.
touches
.
length
)
{
case
0
:
_state
=
STATE
.
NONE
;
break
;
case
1
:
_state
=
STATE
.
TOUCH_ROTATE
;
_moveCurr
.
copy
(
getMouseOnCircle
(
event
.
touches
[
0
].
pageX
,
event
.
touches
[
0
].
pageY
)
);
_movePrev
.
copy
(
_moveCurr
);
break
;
}
_this
.
dispatchEvent
(
endEvent
);
}
function
contextmenu
(
event
)
{
if
(
_this
.
enabled
===
false
)
return
;
event
.
preventDefault
();
}
this
.
dispose
=
function
()
{
this
.
domElement
.
removeEventListener
(
'
contextmenu
'
,
contextmenu
,
false
);
this
.
domElement
.
removeEventListener
(
'
mousedown
'
,
mousedown
,
false
);
this
.
domElement
.
removeEventListener
(
'
wheel
'
,
mousewheel
,
false
);
this
.
domElement
.
removeEventListener
(
'
touchstart
'
,
touchstart
,
false
);
this
.
domElement
.
removeEventListener
(
'
touchend
'
,
touchend
,
false
);
this
.
domElement
.
removeEventListener
(
'
touchmove
'
,
touchmove
,
false
);
document
.
removeEventListener
(
'
mousemove
'
,
mousemove
,
false
);
document
.
removeEventListener
(
'
mouseup
'
,
mouseup
,
false
);
window
.
removeEventListener
(
'
keydown
'
,
keydown
,
false
);
window
.
removeEventListener
(
'
keyup
'
,
keyup
,
false
);
};
this
.
domElement
.
addEventListener
(
'
contextmenu
'
,
contextmenu
,
false
);
this
.
domElement
.
addEventListener
(
'
mousedown
'
,
mousedown
,
false
);
this
.
domElement
.
addEventListener
(
'
wheel
'
,
mousewheel
,
false
);
this
.
domElement
.
addEventListener
(
'
touchstart
'
,
touchstart
,
false
);
this
.
domElement
.
addEventListener
(
'
touchend
'
,
touchend
,
false
);
this
.
domElement
.
addEventListener
(
'
touchmove
'
,
touchmove
,
false
);
window
.
addEventListener
(
'
keydown
'
,
keydown
,
false
);
window
.
addEventListener
(
'
keyup
'
,
keyup
,
false
);
this
.
handleResize
();
// force an update at start
this
.
update
();
};
TrackballControls
.
prototype
=
Object
.
create
(
EventDispatcher
.
prototype
);
TrackballControls
.
prototype
.
constructor
=
THREE
.
TrackballControls
;
export
{
TrackballControls
}
\ No newline at end of file
examples/jsm/loaders/GLTFLoader.js
0 → 100644
浏览文件 @
d695b757
此差异已折叠。
点击以展开。
examples/jsm/loaders/OBJLoader.js
0 → 100644
浏览文件 @
d695b757
/**
* @author mrdoob / http://mrdoob.com/
*/
import
{
BufferGeometry
,
DefaultLoadingManager
,
FileLoader
,
Float32BufferAttribute
,
Group
,
LineBasicMaterial
,
LineSegments
,
Material
,
Mesh
,
MeshPhongMaterial
,
NoColors
,
Points
,
PointsMaterial
,
VertexColors
}
from
"
../../../build/three.module.js
"
;
var
OBJLoader
=
(
function
()
{
// o object_name | g group_name
var
object_pattern
=
/^
[
og
]\s
*
(
.+
)?
/
;
// mtllib file_reference
var
material_library_pattern
=
/^mtllib /
;
// usemtl material_name
var
material_use_pattern
=
/^usemtl /
;
function
ParserState
()
{
var
state
=
{
objects
:
[],
object
:
{},
vertices
:
[],
normals
:
[],
colors
:
[],
uvs
:
[],
materialLibraries
:
[],
startObject
:
function
(
name
,
fromDeclaration
)
{
// If the current object (initial from reset) is not from a g/o declaration in the parsed
// file. We need to use it for the first parsed g/o to keep things in sync.
if
(
this
.
object
&&
this
.
object
.
fromDeclaration
===
false
)
{
this
.
object
.
name
=
name
;
this
.
object
.
fromDeclaration
=
(
fromDeclaration
!==
false
);
return
;
}
var
previousMaterial
=
(
this
.
object
&&
typeof
this
.
object
.
currentMaterial
===
'
function
'
?
this
.
object
.
currentMaterial
()
:
undefined
);
if
(
this
.
object
&&
typeof
this
.
object
.
_finalize
===
'
function
'
)
{
this
.
object
.
_finalize
(
true
);
}
this
.
object
=
{
name
:
name
||
''
,
fromDeclaration
:
(
fromDeclaration
!==
false
),
geometry
:
{
vertices
:
[],
normals
:
[],
colors
:
[],
uvs
:
[]
},
materials
:
[],
smooth
:
true
,
startMaterial
:
function
(
name
,
libraries
)
{
var
previous
=
this
.
_finalize
(
false
);
// New usemtl declaration overwrites an inherited material, except if faces were declared
// after the material, then it must be preserved for proper MultiMaterial continuation.
if
(
previous
&&
(
previous
.
inherited
||
previous
.
groupCount
<=
0
)
)
{
this
.
materials
.
splice
(
previous
.
index
,
1
);
}
var
material
=
{
index
:
this
.
materials
.
length
,
name
:
name
||
''
,
mtllib
:
(
Array
.
isArray
(
libraries
)
&&
libraries
.
length
>
0
?
libraries
[
libraries
.
length
-
1
]
:
''
),
smooth
:
(
previous
!==
undefined
?
previous
.
smooth
:
this
.
smooth
),
groupStart
:
(
previous
!==
undefined
?
previous
.
groupEnd
:
0
),
groupEnd
:
-
1
,
groupCount
:
-
1
,
inherited
:
false
,
clone
:
function
(
index
)
{
var
cloned
=
{
index
:
(
typeof
index
===
'
number
'
?
index
:
this
.
index
),
name
:
this
.
name
,
mtllib
:
this
.
mtllib
,
smooth
:
this
.
smooth
,
groupStart
:
0
,
groupEnd
:
-
1
,
groupCount
:
-
1
,
inherited
:
false
};
cloned
.
clone
=
this
.
clone
.
bind
(
cloned
);
return
cloned
;
}
};
this
.
materials
.
push
(
material
);
return
material
;
},
currentMaterial
:
function
()
{
if
(
this
.
materials
.
length
>
0
)
{
return
this
.
materials
[
this
.
materials
.
length
-
1
];
}
return
undefined
;
},
_finalize
:
function
(
end
)
{
var
lastMultiMaterial
=
this
.
currentMaterial
();
if
(
lastMultiMaterial
&&
lastMultiMaterial
.
groupEnd
===
-
1
)
{
lastMultiMaterial
.
groupEnd
=
this
.
geometry
.
vertices
.
length
/
3
;
lastMultiMaterial
.
groupCount
=
lastMultiMaterial
.
groupEnd
-
lastMultiMaterial
.
groupStart
;
lastMultiMaterial
.
inherited
=
false
;
}
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
if
(
end
&&
this
.
materials
.
length
>
1
)
{
for
(
var
mi
=
this
.
materials
.
length
-
1
;
mi
>=
0
;
mi
--
)
{
if
(
this
.
materials
[
mi
].
groupCount
<=
0
)
{
this
.
materials
.
splice
(
mi
,
1
);
}
}
}
// Guarantee at least one empty material, this makes the creation later more straight forward.
if
(
end
&&
this
.
materials
.
length
===
0
)
{
this
.
materials
.
push
(
{
name
:
''
,
smooth
:
this
.
smooth
}
);
}
return
lastMultiMaterial
;
}
};
// Inherit previous objects material.
// Spec tells us that a declared material must be set to all objects until a new material is declared.
// If a usemtl declaration is encountered while this new object is being parsed, it will
// overwrite the inherited material. Exception being that there was already face declarations
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
if
(
previousMaterial
&&
previousMaterial
.
name
&&
typeof
previousMaterial
.
clone
===
'
function
'
)
{
var
declared
=
previousMaterial
.
clone
(
0
);
declared
.
inherited
=
true
;
this
.
object
.
materials
.
push
(
declared
);
}
this
.
objects
.
push
(
this
.
object
);
},
finalize
:
function
()
{
if
(
this
.
object
&&
typeof
this
.
object
.
_finalize
===
'
function
'
)
{
this
.
object
.
_finalize
(
true
);
}
},
parseVertexIndex
:
function
(
value
,
len
)
{
var
index
=
parseInt
(
value
,
10
);
return
(
index
>=
0
?
index
-
1
:
index
+
len
/
3
)
*
3
;
},
parseNormalIndex
:
function
(
value
,
len
)
{
var
index
=
parseInt
(
value
,
10
);
return
(
index
>=
0
?
index
-
1
:
index
+
len
/
3
)
*
3
;
},
parseUVIndex
:
function
(
value
,
len
)
{
var
index
=
parseInt
(
value
,
10
);
return
(
index
>=
0
?
index
-
1
:
index
+
len
/
2
)
*
2
;
},
addVertex
:
function
(
a
,
b
,
c
)
{
var
src
=
this
.
vertices
;
var
dst
=
this
.
object
.
geometry
.
vertices
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
],
src
[
a
+
2
]
);
dst
.
push
(
src
[
b
+
0
],
src
[
b
+
1
],
src
[
b
+
2
]
);
dst
.
push
(
src
[
c
+
0
],
src
[
c
+
1
],
src
[
c
+
2
]
);
},
addVertexPoint
:
function
(
a
)
{
var
src
=
this
.
vertices
;
var
dst
=
this
.
object
.
geometry
.
vertices
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
],
src
[
a
+
2
]
);
},
addVertexLine
:
function
(
a
)
{
var
src
=
this
.
vertices
;
var
dst
=
this
.
object
.
geometry
.
vertices
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
],
src
[
a
+
2
]
);
},
addNormal
:
function
(
a
,
b
,
c
)
{
var
src
=
this
.
normals
;
var
dst
=
this
.
object
.
geometry
.
normals
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
],
src
[
a
+
2
]
);
dst
.
push
(
src
[
b
+
0
],
src
[
b
+
1
],
src
[
b
+
2
]
);
dst
.
push
(
src
[
c
+
0
],
src
[
c
+
1
],
src
[
c
+
2
]
);
},
addColor
:
function
(
a
,
b
,
c
)
{
var
src
=
this
.
colors
;
var
dst
=
this
.
object
.
geometry
.
colors
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
],
src
[
a
+
2
]
);
dst
.
push
(
src
[
b
+
0
],
src
[
b
+
1
],
src
[
b
+
2
]
);
dst
.
push
(
src
[
c
+
0
],
src
[
c
+
1
],
src
[
c
+
2
]
);
},
addUV
:
function
(
a
,
b
,
c
)
{
var
src
=
this
.
uvs
;
var
dst
=
this
.
object
.
geometry
.
uvs
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
]
);
dst
.
push
(
src
[
b
+
0
],
src
[
b
+
1
]
);
dst
.
push
(
src
[
c
+
0
],
src
[
c
+
1
]
);
},
addUVLine
:
function
(
a
)
{
var
src
=
this
.
uvs
;
var
dst
=
this
.
object
.
geometry
.
uvs
;
dst
.
push
(
src
[
a
+
0
],
src
[
a
+
1
]
);
},
addFace
:
function
(
a
,
b
,
c
,
ua
,
ub
,
uc
,
na
,
nb
,
nc
)
{
var
vLen
=
this
.
vertices
.
length
;
var
ia
=
this
.
parseVertexIndex
(
a
,
vLen
);
var
ib
=
this
.
parseVertexIndex
(
b
,
vLen
);
var
ic
=
this
.
parseVertexIndex
(
c
,
vLen
);
this
.
addVertex
(
ia
,
ib
,
ic
);
if
(
ua
!==
undefined
&&
ua
!==
''
)
{
var
uvLen
=
this
.
uvs
.
length
;
ia
=
this
.
parseUVIndex
(
ua
,
uvLen
);
ib
=
this
.
parseUVIndex
(
ub
,
uvLen
);
ic
=
this
.
parseUVIndex
(
uc
,
uvLen
);
this
.
addUV
(
ia
,
ib
,
ic
);
}
if
(
na
!==
undefined
&&
na
!==
''
)
{
// Normals are many times the same. If so, skip function call and parseInt.
var
nLen
=
this
.
normals
.
length
;
ia
=
this
.
parseNormalIndex
(
na
,
nLen
);
ib
=
na
===
nb
?
ia
:
this
.
parseNormalIndex
(
nb
,
nLen
);
ic
=
na
===
nc
?
ia
:
this
.
parseNormalIndex
(
nc
,
nLen
);
this
.
addNormal
(
ia
,
ib
,
ic
);
}
if
(
this
.
colors
.
length
>
0
)
{
this
.
addColor
(
ia
,
ib
,
ic
);
}
},
addPointGeometry
:
function
(
vertices
)
{
this
.
object
.
geometry
.
type
=
'
Points
'
;
var
vLen
=
this
.
vertices
.
length
;
for
(
var
vi
=
0
,
l
=
vertices
.
length
;
vi
<
l
;
vi
++
)
{
this
.
addVertexPoint
(
this
.
parseVertexIndex
(
vertices
[
vi
],
vLen
)
);
}
},
addLineGeometry
:
function
(
vertices
,
uvs
)
{
this
.
object
.
geometry
.
type
=
'
Line
'
;
var
vLen
=
this
.
vertices
.
length
;
var
uvLen
=
this
.
uvs
.
length
;
for
(
var
vi
=
0
,
l
=
vertices
.
length
;
vi
<
l
;
vi
++
)
{
this
.
addVertexLine
(
this
.
parseVertexIndex
(
vertices
[
vi
],
vLen
)
);
}
for
(
var
uvi
=
0
,
l
=
uvs
.
length
;
uvi
<
l
;
uvi
++
)
{
this
.
addUVLine
(
this
.
parseUVIndex
(
uvs
[
uvi
],
uvLen
)
);
}
}
};
state
.
startObject
(
''
,
false
);
return
state
;
}
//
function
OBJLoader
(
manager
)
{
this
.
manager
=
(
manager
!==
undefined
)
?
manager
:
DefaultLoadingManager
;
this
.
materials
=
null
;
}
OBJLoader
.
prototype
=
{
constructor
:
OBJLoader
,
load
:
function
(
url
,
onLoad
,
onProgress
,
onError
)
{
var
scope
=
this
;
var
loader
=
new
FileLoader
(
scope
.
manager
);
loader
.
setPath
(
this
.
path
);
loader
.
load
(
url
,
function
(
text
)
{
onLoad
(
scope
.
parse
(
text
)
);
},
onProgress
,
onError
);
},
setPath
:
function
(
value
)
{
this
.
path
=
value
;
return
this
;
},
setMaterials
:
function
(
materials
)
{
this
.
materials
=
materials
;
return
this
;
},
parse
:
function
(
text
)
{
console
.
time
(
'
OBJLoader
'
);
var
state
=
new
ParserState
();
if
(
text
.
indexOf
(
'
\r\n
'
)
!==
-
1
)
{
// This is faster than String.split with regex that splits on both
text
=
text
.
replace
(
/
\r\n
/g
,
'
\n
'
);
}
if
(
text
.
indexOf
(
'
\\\n
'
)
!==
-
1
)
{
// join lines separated by a line continuation character (\)
text
=
text
.
replace
(
/
\\\n
/g
,
''
);
}
var
lines
=
text
.
split
(
'
\n
'
);
var
line
=
''
,
lineFirstChar
=
''
;
var
lineLength
=
0
;
var
result
=
[];
// Faster to just trim left side of the line. Use if available.
var
trimLeft
=
(
typeof
''
.
trimLeft
===
'
function
'
);
for
(
var
i
=
0
,
l
=
lines
.
length
;
i
<
l
;
i
++
)
{
line
=
lines
[
i
];
line
=
trimLeft
?
line
.
trimLeft
()
:
line
.
trim
();
lineLength
=
line
.
length
;
if
(
lineLength
===
0
)
continue
;
lineFirstChar
=
line
.
charAt
(
0
);
// @todo invoke passed in handler if any
if
(
lineFirstChar
===
'
#
'
)
continue
;
if
(
lineFirstChar
===
'
v
'
)
{
var
data
=
line
.
split
(
/
\s
+/
);
switch
(
data
[
0
]
)
{
case
'
v
'
:
state
.
vertices
.
push
(
parseFloat
(
data
[
1
]
),
parseFloat
(
data
[
2
]
),
parseFloat
(
data
[
3
]
)
);
if
(
data
.
length
===
8
)
{
state
.
colors
.
push
(
parseFloat
(
data
[
4
]
),
parseFloat
(
data
[
5
]
),
parseFloat
(
data
[
6
]
)
);
}
break
;
case
'
vn
'
:
state
.
normals
.
push
(
parseFloat
(
data
[
1
]
),
parseFloat
(
data
[
2
]
),
parseFloat
(
data
[
3
]
)
);
break
;
case
'
vt
'
:
state
.
uvs
.
push
(
parseFloat
(
data
[
1
]
),
parseFloat
(
data
[
2
]
)
);
break
;
}
}
else
if
(
lineFirstChar
===
'
f
'
)
{
var
lineData
=
line
.
substr
(
1
).
trim
();
var
vertexData
=
lineData
.
split
(
/
\s
+/
);
var
faceVertices
=
[];
// Parse the face vertex data into an easy to work with format
for
(
var
j
=
0
,
jl
=
vertexData
.
length
;
j
<
jl
;
j
++
)
{
var
vertex
=
vertexData
[
j
];
if
(
vertex
.
length
>
0
)
{
var
vertexParts
=
vertex
.
split
(
'
/
'
);
faceVertices
.
push
(
vertexParts
);
}
}
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
var
v1
=
faceVertices
[
0
];
for
(
var
j
=
1
,
jl
=
faceVertices
.
length
-
1
;
j
<
jl
;
j
++
)
{
var
v2
=
faceVertices
[
j
];
var
v3
=
faceVertices
[
j
+
1
];
state
.
addFace
(
v1
[
0
],
v2
[
0
],
v3
[
0
],
v1
[
1
],
v2
[
1
],
v3
[
1
],
v1
[
2
],
v2
[
2
],
v3
[
2
]
);
}
}
else
if
(
lineFirstChar
===
'
l
'
)
{
var
lineParts
=
line
.
substring
(
1
).
trim
().
split
(
"
"
);
var
lineVertices
=
[],
lineUVs
=
[];
if
(
line
.
indexOf
(
"
/
"
)
===
-
1
)
{
lineVertices
=
lineParts
;
}
else
{
for
(
var
li
=
0
,
llen
=
lineParts
.
length
;
li
<
llen
;
li
++
)
{
var
parts
=
lineParts
[
li
].
split
(
"
/
"
);
if
(
parts
[
0
]
!==
""
)
lineVertices
.
push
(
parts
[
0
]
);
if
(
parts
[
1
]
!==
""
)
lineUVs
.
push
(
parts
[
1
]
);
}
}
state
.
addLineGeometry
(
lineVertices
,
lineUVs
);
}
else
if
(
lineFirstChar
===
'
p
'
)
{
var
lineData
=
line
.
substr
(
1
).
trim
();
var
pointData
=
lineData
.
split
(
"
"
);
state
.
addPointGeometry
(
pointData
);
}
else
if
(
(
result
=
object_pattern
.
exec
(
line
)
)
!==
null
)
{
// o object_name
// or
// g group_name
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
// var name = result[ 0 ].substr( 1 ).trim();
var
name
=
(
"
"
+
result
[
0
].
substr
(
1
).
trim
()
).
substr
(
1
);
state
.
startObject
(
name
);
}
else
if
(
material_use_pattern
.
test
(
line
)
)
{
// material
state
.
object
.
startMaterial
(
line
.
substring
(
7
).
trim
(),
state
.
materialLibraries
);
}
else
if
(
material_library_pattern
.
test
(
line
)
)
{
// mtl file
state
.
materialLibraries
.
push
(
line
.
substring
(
7
).
trim
()
);
}
else
if
(
lineFirstChar
===
'
s
'
)
{
result
=
line
.
split
(
'
'
);
// smooth shading
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
// but does not define a usemtl for each face set.
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
// This requires some care to not create extra material on each smooth value for "normal" obj files.
// where explicit usemtl defines geometry groups.
// Example asset: examples/models/obj/cerberus/Cerberus.obj
/*
* http://paulbourke.net/dataformats/obj/
* or
* http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
*
* From chapter "Grouping" Syntax explanation "s group_number":
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
* than 0."
*/
if
(
result
.
length
>
1
)
{
var
value
=
result
[
1
].
trim
().
toLowerCase
();
state
.
object
.
smooth
=
(
value
!==
'
0
'
&&
value
!==
'
off
'
);
}
else
{
// ZBrush can produce "s" lines #11707
state
.
object
.
smooth
=
true
;
}
var
material
=
state
.
object
.
currentMaterial
();
if
(
material
)
material
.
smooth
=
state
.
object
.
smooth
;
}
else
{
// Handle null terminated files without exception
if
(
line
===
'
\
0
'
)
continue
;
throw
new
Error
(
'
THREE.OBJLoader: Unexpected line: "
'
+
line
+
'
"
'
);
}
}
state
.
finalize
();
var
container
=
new
Group
();
container
.
materialLibraries
=
[].
concat
(
state
.
materialLibraries
);
for
(
var
i
=
0
,
l
=
state
.
objects
.
length
;
i
<
l
;
i
++
)
{
var
object
=
state
.
objects
[
i
];
var
geometry
=
object
.
geometry
;
var
materials
=
object
.
materials
;
var
isLine
=
(
geometry
.
type
===
'
Line
'
);
var
isPoints
=
(
geometry
.
type
===
'
Points
'
);
var
hasVertexColors
=
false
;
// Skip o/g line declarations that did not follow with any faces
if
(
geometry
.
vertices
.
length
===
0
)
continue
;
var
buffergeometry
=
new
BufferGeometry
();
buffergeometry
.
addAttribute
(
'
position
'
,
new
Float32BufferAttribute
(
geometry
.
vertices
,
3
)
);
if
(
geometry
.
normals
.
length
>
0
)
{
buffergeometry
.
addAttribute
(
'
normal
'
,
new
Float32BufferAttribute
(
geometry
.
normals
,
3
)
);
}
else
{
buffergeometry
.
computeVertexNormals
();
}
if
(
geometry
.
colors
.
length
>
0
)
{
hasVertexColors
=
true
;
buffergeometry
.
addAttribute
(
'
color
'
,
new
Float32BufferAttribute
(
geometry
.
colors
,
3
)
);
}
if
(
geometry
.
uvs
.
length
>
0
)
{
buffergeometry
.
addAttribute
(
'
uv
'
,
new
Float32BufferAttribute
(
geometry
.
uvs
,
2
)
);
}
// Create materials
var
createdMaterials
=
[];
for
(
var
mi
=
0
,
miLen
=
materials
.
length
;
mi
<
miLen
;
mi
++
)
{
var
sourceMaterial
=
materials
[
mi
];
var
material
=
undefined
;
if
(
this
.
materials
!==
null
)
{
material
=
this
.
materials
.
create
(
sourceMaterial
.
name
);
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
if
(
isLine
&&
material
&&
!
(
material
instanceof
LineBasicMaterial
)
)
{
var
materialLine
=
new
LineBasicMaterial
();
Material
.
prototype
.
copy
.
call
(
materialLine
,
material
);
materialLine
.
color
.
copy
(
material
.
color
);
materialLine
.
lights
=
false
;
material
=
materialLine
;
}
else
if
(
isPoints
&&
material
&&
!
(
material
instanceof
PointsMaterial
)
)
{
var
materialPoints
=
new
PointsMaterial
(
{
size
:
10
,
sizeAttenuation
:
false
}
);
Material
.
prototype
.
copy
.
call
(
materialPoints
,
material
);
materialPoints
.
color
.
copy
(
material
.
color
);
materialPoints
.
map
=
material
.
map
;
materialPoints
.
lights
=
false
;
material
=
materialPoints
;
}
}
if
(
!
material
)
{
if
(
isLine
)
{
material
=
new
LineBasicMaterial
();
}
else
if
(
isPoints
)
{
material
=
new
PointsMaterial
(
{
size
:
1
,
sizeAttenuation
:
false
}
);
}
else
{
material
=
new
MeshPhongMaterial
();
}
material
.
name
=
sourceMaterial
.
name
;
}
material
.
flatShading
=
sourceMaterial
.
smooth
?
false
:
true
;
material
.
vertexColors
=
hasVertexColors
?
VertexColors
:
NoColors
;
createdMaterials
.
push
(
material
);
}
// Create mesh
var
mesh
;
if
(
createdMaterials
.
length
>
1
)
{
for
(
var
mi
=
0
,
miLen
=
materials
.
length
;
mi
<
miLen
;
mi
++
)
{
var
sourceMaterial
=
materials
[
mi
];
buffergeometry
.
addGroup
(
sourceMaterial
.
groupStart
,
sourceMaterial
.
groupCount
,
mi
);
}
if
(
isLine
)
{
mesh
=
new
LineSegments
(
buffergeometry
,
createdMaterials
);
}
else
if
(
isPoints
)
{
mesh
=
new
Points
(
buffergeometry
,
createdMaterials
);
}
else
{
mesh
=
new
Mesh
(
buffergeometry
,
createdMaterials
);
}
}
else
{
if
(
isLine
)
{
mesh
=
new
LineSegments
(
buffergeometry
,
createdMaterials
[
0
]
);
}
else
if
(
isPoints
)
{
mesh
=
new
Points
(
buffergeometry
,
createdMaterials
[
0
]
);
}
else
{
mesh
=
new
Mesh
(
buffergeometry
,
createdMaterials
[
0
]
);
}
}
mesh
.
name
=
object
.
name
;
container
.
add
(
mesh
);
}
console
.
timeEnd
(
'
OBJLoader
'
);
return
container
;
}
};
return
OBJLoader
;
}
)();
export
{
OBJLoader
}
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录