Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
车家大少爷
three.js
提交
1372cc5e
T
three.js
项目概览
车家大少爷
/
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,发现更多精彩内容 >>
提交
1372cc5e
编写于
8月 02, 2018
作者:
Y
yomboprime
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fixes #14609
上级
3585caf4
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
1079 addition
and
0 deletion
+1079
-0
examples/files.js
examples/files.js
+1
-0
examples/js/ConvexBufferObjectBreaker.js
examples/js/ConvexBufferObjectBreaker.js
+518
-0
examples/webgl_physics_convex_buffer_break.html
examples/webgl_physics_convex_buffer_break.html
+560
-0
未找到文件。
examples/files.js
浏览文件 @
1372cc5e
...
@@ -213,6 +213,7 @@ var files = {
...
@@ -213,6 +213,7 @@ var files = {
"
webgl_performance_static
"
,
"
webgl_performance_static
"
,
"
webgl_physics_cloth
"
,
"
webgl_physics_cloth
"
,
"
webgl_physics_convex_break
"
,
"
webgl_physics_convex_break
"
,
"
webgl_physics_convex_buffer_break
"
,
"
webgl_physics_rope
"
,
"
webgl_physics_rope
"
,
"
webgl_physics_terrain
"
,
"
webgl_physics_terrain
"
,
"
webgl_physics_volume
"
,
"
webgl_physics_volume
"
,
...
...
examples/js/ConvexBufferObjectBreaker.js
0 → 100644
浏览文件 @
1372cc5e
/**
* @author yomboprime https://github.com/yomboprime
*
* @fileoverview This class can be used to subdivide a convex Geometry object into pieces.
*
* Usage:
*
* Use the function prepareBreakableObject to prepare a Mesh object to be broken.
*
* Then, call the various functions to subdivide the object (subdivideByImpact, cutByPlane)
*
* Sub-objects that are product of subdivision don't need prepareBreakableObject to be called on them.
*
* Requisites for the object:
*
* - Mesh object must have a BufferGeometry (not Geometry) and a Material
*
* - Vertex normals must be planar (not smoothed)
*
* - The geometry must be convex (this is not checked in the library). You can create convex
* geometries with THREE.ConvexBufferGeometry. The BoxBufferGeometry, SphereBufferGeometry and other convex primitives
* can also be used.
*
* Note: This lib adds member variables to object's userData member (see prepareBreakableObject function)
* Use with caution and read the code when using with other libs.
*
* @param {double} minSizeForBreak Min size a debris can have to break.
* @param {double} smallDelta Max distance to consider that a point belongs to a plane.
*
*/
THREE
.
ConvexBufferObjectBreaker
=
function
(
minSizeForBreak
,
smallDelta
)
{
this
.
minSizeForBreak
=
minSizeForBreak
||
1.4
;
this
.
smallDelta
=
smallDelta
||
0.0001
;
this
.
tempLine1
=
new
THREE
.
Line3
();
this
.
tempPlane1
=
new
THREE
.
Plane
();
this
.
tempPlane2
=
new
THREE
.
Plane
();
this
.
tempPlane_Cut
=
new
THREE
.
Plane
();
this
.
tempCM1
=
new
THREE
.
Vector3
();
this
.
tempCM2
=
new
THREE
.
Vector3
();
this
.
tempVector3
=
new
THREE
.
Vector3
();
this
.
tempVector3_2
=
new
THREE
.
Vector3
();
this
.
tempVector3_3
=
new
THREE
.
Vector3
();
this
.
tempVector3_P0
=
new
THREE
.
Vector3
();
this
.
tempVector3_P1
=
new
THREE
.
Vector3
();
this
.
tempVector3_P2
=
new
THREE
.
Vector3
();
this
.
tempVector3_N0
=
new
THREE
.
Vector3
();
this
.
tempVector3_N1
=
new
THREE
.
Vector3
();
this
.
tempVector3_AB
=
new
THREE
.
Vector3
();
this
.
tempVector3_CB
=
new
THREE
.
Vector3
();
this
.
tempResultObjects
=
{
object1
:
null
,
object2
:
null
};
this
.
segments
=
[];
var
n
=
30
*
30
;
for
(
var
i
=
0
;
i
<
n
;
i
++
)
this
.
segments
[
i
]
=
false
;
};
THREE
.
ConvexBufferObjectBreaker
.
prototype
=
{
constructor
:
THREE
.
ConvexBufferObjectBreaker
,
prepareBreakableObject
:
function
(
object
,
mass
,
velocity
,
angularVelocity
,
breakable
)
{
// object is a THREE.Object3d (normally a Mesh), must have a BufferGeometry, and it must be convex.
// Its material property is propagated to its children (sub-pieces)
// mass must be > 0
if
(
!
object
.
geometry
.
isBufferGeometry
)
{
console
.
error
(
"
THREE.ConvexBufferObjectBreaker.prepareBreakableObject(): Parameter object must have a BufferGeometry.
"
);
}
var
userData
=
object
.
userData
;
userData
.
mass
=
mass
;
userData
.
velocity
=
velocity
.
clone
();
userData
.
angularVelocity
=
angularVelocity
.
clone
();
userData
.
breakable
=
breakable
;
},
/*
* @param {int} maxRadialIterations Iterations for radial cuts.
* @param {int} maxRandomIterations Max random iterations for not-radial cuts
*
* Returns the array of pieces
*/
subdivideByImpact
:
function
(
object
,
pointOfImpact
,
normal
,
maxRadialIterations
,
maxRandomIterations
)
{
var
debris
=
[];
var
tempPlane1
=
this
.
tempPlane1
;
var
tempPlane2
=
this
.
tempPlane2
;
this
.
tempVector3
.
addVectors
(
pointOfImpact
,
normal
);
tempPlane1
.
setFromCoplanarPoints
(
pointOfImpact
,
object
.
position
,
this
.
tempVector3
);
var
maxTotalIterations
=
maxRandomIterations
+
maxRadialIterations
;
var
scope
=
this
;
function
subdivideRadial
(
subObject
,
startAngle
,
endAngle
,
numIterations
)
{
if
(
Math
.
random
()
<
numIterations
*
0.05
||
numIterations
>
maxTotalIterations
)
{
debris
.
push
(
subObject
);
return
;
}
var
angle
=
Math
.
PI
;
if
(
numIterations
===
0
)
{
tempPlane2
.
normal
.
copy
(
tempPlane1
.
normal
);
tempPlane2
.
constant
=
tempPlane1
.
constant
;
}
else
{
if
(
numIterations
<=
maxRadialIterations
)
{
angle
=
(
endAngle
-
startAngle
)
*
(
0.2
+
0.6
*
Math
.
random
()
)
+
startAngle
;
// Rotate tempPlane2 at impact point around normal axis and the angle
scope
.
tempVector3_2
.
copy
(
object
.
position
).
sub
(
pointOfImpact
).
applyAxisAngle
(
normal
,
angle
).
add
(
pointOfImpact
);
tempPlane2
.
setFromCoplanarPoints
(
pointOfImpact
,
scope
.
tempVector3
,
scope
.
tempVector3_2
);
}
else
{
angle
=
(
(
0.5
*
(
numIterations
&
1
)
)
+
0.2
*
(
2
-
Math
.
random
()
)
)
*
Math
.
PI
;
// Rotate tempPlane2 at object position around normal axis and the angle
scope
.
tempVector3_2
.
copy
(
pointOfImpact
).
sub
(
subObject
.
position
).
applyAxisAngle
(
normal
,
angle
).
add
(
subObject
.
position
);
scope
.
tempVector3_3
.
copy
(
normal
).
add
(
subObject
.
position
);
tempPlane2
.
setFromCoplanarPoints
(
subObject
.
position
,
scope
.
tempVector3_3
,
scope
.
tempVector3_2
);
}
}
// Perform the cut
scope
.
cutByPlane
(
subObject
,
tempPlane2
,
scope
.
tempResultObjects
);
var
obj1
=
scope
.
tempResultObjects
.
object1
;
var
obj2
=
scope
.
tempResultObjects
.
object2
;
if
(
obj1
)
{
subdivideRadial
(
obj1
,
startAngle
,
angle
,
numIterations
+
1
);
}
if
(
obj2
)
{
subdivideRadial
(
obj2
,
angle
,
endAngle
,
numIterations
+
1
);
}
}
subdivideRadial
(
object
,
0
,
2
*
Math
.
PI
,
0
);
return
debris
;
},
cutByPlane
:
function
(
object
,
plane
,
output
)
{
// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
// object2 can be null if the plane doesn't cut the object.
// object1 can be null only in case of internal error
// Returned value is number of pieces, 0 for error.
var
geometry
=
object
.
geometry
;
var
coords
=
geometry
.
attributes
.
position
.
array
;
var
normals
=
geometry
.
attributes
.
normal
.
array
;
var
numPoints
=
coords
.
length
/
3
;
var
numFaces
=
numPoints
/
3
;
var
indices
=
geometry
.
getIndex
();
if
(
indices
)
{
indices
=
indices
.
array
;
numFaces
=
indices
.
length
/
3
;
}
function
getVertexIndex
(
faceIdx
,
vert
)
{
// vert = 0, 1 or 2.
var
idx
=
faceIdx
*
3
+
vert
;
return
indices
?
indices
[
idx
]
:
idx
;
}
var
points1
=
[];
var
points2
=
[];
var
delta
=
this
.
smallDelta
;
// Reset segments mark
var
numPointPairs
=
numPoints
*
numPoints
;
for
(
var
i
=
0
;
i
<
numPointPairs
;
i
++
)
this
.
segments
[
i
]
=
false
;
var
p0
=
this
.
tempVector3_P0
;
var
p1
=
this
.
tempVector3_P1
;
var
p2
=
this
.
tempVector3_P2
;
var
n0
=
this
.
tempVector3_N0
;
var
n1
=
this
.
tempVector3_N1
;
// Iterate through the faces to mark edges shared by coplanar faces
for
(
var
i
=
0
;
i
<
numFaces
-
1
;
i
++
)
{
var
a1
=
getVertexIndex
(
i
,
0
);
var
b1
=
getVertexIndex
(
i
,
1
);
var
c1
=
getVertexIndex
(
i
,
2
);
// Assuming all 3 vertices have the same normal
n0
.
set
(
normals
[
a1
],
normals
[
a1
]
+
1
,
normals
[
a1
]
+
2
);
for
(
var
j
=
i
+
1
;
j
<
numFaces
;
j
++
)
{
var
a2
=
getVertexIndex
(
j
,
0
);
var
b2
=
getVertexIndex
(
j
,
1
);
var
c2
=
getVertexIndex
(
j
,
2
);
// Assuming all 3 vertices have the same normal
n1
.
set
(
normals
[
a2
],
normals
[
a2
]
+
1
,
normals
[
a2
]
+
2
);
var
coplanar
=
1
-
n0
.
dot
(
n1
)
<
delta
;
if
(
coplanar
)
{
if
(
a1
===
a2
||
a1
===
b2
||
a1
===
c2
)
{
if
(
b1
===
a2
||
b1
===
b2
||
b1
===
c2
)
{
this
.
segments
[
a1
*
numPoints
+
b1
]
=
true
;
this
.
segments
[
b1
*
numPoints
+
a1
]
=
true
;
}
else
{
this
.
segments
[
c1
*
numPoints
+
a1
]
=
true
;
this
.
segments
[
a1
*
numPoints
+
c1
]
=
true
;
}
}
else
if
(
b1
===
a2
||
b1
===
b2
||
b1
===
c2
)
{
this
.
segments
[
c1
*
numPoints
+
b1
]
=
true
;
this
.
segments
[
b1
*
numPoints
+
c1
]
=
true
;
}
}
}
}
// Transform the plane to object local space
var
localPlane
=
this
.
tempPlane_Cut
;
object
.
updateMatrix
();
THREE
.
ConvexBufferObjectBreaker
.
transformPlaneToLocalSpace
(
plane
,
object
.
matrix
,
localPlane
);
// Iterate through the faces adding points to both pieces
for
(
var
i
=
0
;
i
<
numFaces
;
i
++
)
{
var
va
=
getVertexIndex
(
i
,
0
);
var
vb
=
getVertexIndex
(
i
,
1
);
var
vc
=
getVertexIndex
(
i
,
2
);
for
(
var
segment
=
0
;
segment
<
3
;
segment
++
)
{
var
i0
=
segment
===
0
?
va
:
(
segment
===
1
?
vb
:
vc
);
var
i1
=
segment
===
0
?
vb
:
(
segment
===
1
?
vc
:
va
);
var
segmentState
=
this
.
segments
[
i0
*
numPoints
+
i1
];
if
(
segmentState
)
continue
;
// The segment already has been processed in another face
// Mark segment as processed (also inverted segment)
this
.
segments
[
i0
*
numPoints
+
i1
]
=
true
;
this
.
segments
[
i1
*
numPoints
+
i0
]
=
true
;
p0
.
set
(
coords
[
3
*
i0
],
coords
[
3
*
i0
+
1
],
coords
[
3
*
i0
+
2
]
);
p1
.
set
(
coords
[
3
*
i1
],
coords
[
3
*
i1
+
1
],
coords
[
3
*
i1
+
2
]
);
// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
var
mark0
=
0
;
var
d
=
localPlane
.
distanceToPoint
(
p0
);
if
(
d
>
delta
)
{
mark0
=
2
;
points2
.
push
(
p0
.
clone
()
);
}
else
if
(
d
<
-
delta
)
{
mark0
=
1
;
points1
.
push
(
p0
.
clone
()
);
}
else
{
mark0
=
3
;
points1
.
push
(
p0
.
clone
()
);
points2
.
push
(
p0
.
clone
()
);
}
// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
var
mark1
=
0
;
var
d
=
localPlane
.
distanceToPoint
(
p1
);
if
(
d
>
delta
)
{
mark1
=
2
;
points2
.
push
(
p1
.
clone
()
);
}
else
if
(
d
<
-
delta
)
{
mark1
=
1
;
points1
.
push
(
p1
.
clone
()
);
}
else
{
mark1
=
3
;
points1
.
push
(
p1
.
clone
()
);
points2
.
push
(
p1
.
clone
()
);
}
if
(
(
mark0
===
1
&&
mark1
===
2
)
||
(
mark0
===
2
&&
mark1
===
1
)
)
{
// Intersection of segment with the plane
this
.
tempLine1
.
start
.
copy
(
p0
);
this
.
tempLine1
.
end
.
copy
(
p1
);
var
intersection
=
new
THREE
.
Vector3
();
intersection
=
localPlane
.
intersectLine
(
this
.
tempLine1
,
intersection
);
if
(
intersection
===
undefined
)
{
// Shouldn't happen
console
.
error
(
"
Internal error: segment does not intersect plane.
"
);
output
.
segmentedObject1
=
null
;
output
.
segmentedObject2
=
null
;
return
0
;
}
points1
.
push
(
intersection
);
points2
.
push
(
intersection
.
clone
()
);
}
}
}
// Calculate debris mass (very fast and imprecise):
var
newMass
=
object
.
userData
.
mass
*
0.5
;
// Calculate debris Center of Mass (again fast and imprecise)
this
.
tempCM1
.
set
(
0
,
0
,
0
);
var
radius1
=
0
;
var
numPoints1
=
points1
.
length
;
if
(
numPoints1
>
0
)
{
for
(
var
i
=
0
;
i
<
numPoints1
;
i
++
)
this
.
tempCM1
.
add
(
points1
[
i
]
);
this
.
tempCM1
.
divideScalar
(
numPoints1
);
for
(
var
i
=
0
;
i
<
numPoints1
;
i
++
)
{
var
p
=
points1
[
i
];
p
.
sub
(
this
.
tempCM1
);
radius1
=
Math
.
max
(
radius1
,
p
.
x
,
p
.
y
,
p
.
z
);
}
this
.
tempCM1
.
add
(
object
.
position
);
}
this
.
tempCM2
.
set
(
0
,
0
,
0
);
var
radius2
=
0
;
var
numPoints2
=
points2
.
length
;
if
(
numPoints2
>
0
)
{
for
(
var
i
=
0
;
i
<
numPoints2
;
i
++
)
this
.
tempCM2
.
add
(
points2
[
i
]
);
this
.
tempCM2
.
divideScalar
(
numPoints2
);
for
(
var
i
=
0
;
i
<
numPoints2
;
i
++
)
{
var
p
=
points2
[
i
];
p
.
sub
(
this
.
tempCM2
);
radius2
=
Math
.
max
(
radius2
,
p
.
x
,
p
.
y
,
p
.
z
);
}
this
.
tempCM2
.
add
(
object
.
position
);
}
var
object1
=
null
;
var
object2
=
null
;
var
numObjects
=
0
;
if
(
numPoints1
>
4
)
{
object1
=
new
THREE
.
Mesh
(
new
THREE
.
ConvexBufferGeometry
(
points1
),
object
.
material
);
object1
.
position
.
copy
(
this
.
tempCM1
);
object1
.
quaternion
.
copy
(
object
.
quaternion
);
this
.
prepareBreakableObject
(
object1
,
newMass
,
object
.
userData
.
velocity
,
object
.
userData
.
angularVelocity
,
2
*
radius1
>
this
.
minSizeForBreak
);
numObjects
++
;
}
if
(
numPoints2
>
4
)
{
object2
=
new
THREE
.
Mesh
(
new
THREE
.
ConvexBufferGeometry
(
points2
),
object
.
material
);
object2
.
position
.
copy
(
this
.
tempCM2
);
object2
.
quaternion
.
copy
(
object
.
quaternion
);
this
.
prepareBreakableObject
(
object2
,
newMass
,
object
.
userData
.
velocity
,
object
.
userData
.
angularVelocity
,
2
*
radius2
>
this
.
minSizeForBreak
);
numObjects
++
;
}
output
.
object1
=
object1
;
output
.
object2
=
object2
;
return
numObjects
;
}
};
THREE
.
ConvexBufferObjectBreaker
.
transformFreeVector
=
function
(
v
,
m
)
{
// input:
// vector interpreted as a free vector
// THREE.Matrix4 orthogonal matrix (matrix without scale)
var
x
=
v
.
x
,
y
=
v
.
y
,
z
=
v
.
z
;
var
e
=
m
.
elements
;
v
.
x
=
e
[
0
]
*
x
+
e
[
4
]
*
y
+
e
[
8
]
*
z
;
v
.
y
=
e
[
1
]
*
x
+
e
[
5
]
*
y
+
e
[
9
]
*
z
;
v
.
z
=
e
[
2
]
*
x
+
e
[
6
]
*
y
+
e
[
10
]
*
z
;
return
v
;
};
THREE
.
ConvexBufferObjectBreaker
.
transformFreeVectorInverse
=
function
(
v
,
m
)
{
// input:
// vector interpreted as a free vector
// THREE.Matrix4 orthogonal matrix (matrix without scale)
var
x
=
v
.
x
,
y
=
v
.
y
,
z
=
v
.
z
;
var
e
=
m
.
elements
;
v
.
x
=
e
[
0
]
*
x
+
e
[
1
]
*
y
+
e
[
2
]
*
z
;
v
.
y
=
e
[
4
]
*
x
+
e
[
5
]
*
y
+
e
[
6
]
*
z
;
v
.
z
=
e
[
8
]
*
x
+
e
[
9
]
*
y
+
e
[
10
]
*
z
;
return
v
;
};
THREE
.
ConvexBufferObjectBreaker
.
transformTiedVectorInverse
=
function
(
v
,
m
)
{
// input:
// vector interpreted as a tied (ordinary) vector
// THREE.Matrix4 orthogonal matrix (matrix without scale)
var
x
=
v
.
x
,
y
=
v
.
y
,
z
=
v
.
z
;
var
e
=
m
.
elements
;
v
.
x
=
e
[
0
]
*
x
+
e
[
1
]
*
y
+
e
[
2
]
*
z
-
e
[
12
];
v
.
y
=
e
[
4
]
*
x
+
e
[
5
]
*
y
+
e
[
6
]
*
z
-
e
[
13
];
v
.
z
=
e
[
8
]
*
x
+
e
[
9
]
*
y
+
e
[
10
]
*
z
-
e
[
14
];
return
v
;
};
THREE
.
ConvexBufferObjectBreaker
.
transformPlaneToLocalSpace
=
function
()
{
var
v1
=
new
THREE
.
Vector3
();
return
function
transformPlaneToLocalSpace
(
plane
,
m
,
resultPlane
)
{
resultPlane
.
normal
.
copy
(
plane
.
normal
);
resultPlane
.
constant
=
plane
.
constant
;
var
referencePoint
=
THREE
.
ConvexBufferObjectBreaker
.
transformTiedVectorInverse
(
plane
.
coplanarPoint
(
v1
),
m
);
THREE
.
ConvexBufferObjectBreaker
.
transformFreeVectorInverse
(
resultPlane
.
normal
,
m
);
// recalculate constant (like in setFromNormalAndCoplanarPoint)
resultPlane
.
constant
=
-
referencePoint
.
dot
(
resultPlane
.
normal
);
};
}();
examples/webgl_physics_convex_buffer_break.html
0 → 100644
浏览文件 @
1372cc5e
<html
lang=
"en"
>
<head>
<title>
Convex buffer object breaking example
</title>
<meta
charset=
"utf-8"
>
<meta
name=
"viewport"
content=
"width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
>
<style>
body
{
color
:
#61443e
;
font-family
:
Monospace
;
font-size
:
13px
;
text-align
:
center
;
background-color
:
#bfd1e5
;
margin
:
0px
;
overflow
:
hidden
;
}
#info
{
position
:
absolute
;
top
:
0px
;
width
:
100%
;
padding
:
5px
;
}
a
{
color
:
#a06851
;
}
</style>
</head>
<body>
<div
id=
"info"
>
Physics threejs demo with convex objects breaking in real time
<br
/>
Press mouse to throw balls and move the camera.
</div>
<div
id=
"container"
><br
/><br
/><br
/><br
/><br
/>
Loading...
</div>
<script
src=
"../build/three.js"
></script>
<script
src=
"js/libs/ammo.js"
></script>
<script
src=
"js/controls/OrbitControls.js"
></script>
<script
src=
"js/Detector.js"
></script>
<script
src=
"js/libs/stats.min.js"
></script>
<script
src=
"js/ConvexBufferObjectBreaker.js"
></script>
<script
src=
"js/QuickHull.js"
></script>
<script
src=
"js/geometries/ConvexGeometry.js"
></script>
<script>
// Detects webgl
if
(
!
Detector
.
webgl
)
{
Detector
.
addGetWebGLMessage
();
document
.
getElementById
(
'
container
'
).
innerHTML
=
""
;
}
// - Global variables -
// Graphics variables
var
container
,
stats
;
var
camera
,
controls
,
scene
,
renderer
;
var
textureLoader
;
var
clock
=
new
THREE
.
Clock
();
var
mouseCoords
=
new
THREE
.
Vector2
();
var
raycaster
=
new
THREE
.
Raycaster
();
var
ballMaterial
=
new
THREE
.
MeshPhongMaterial
(
{
color
:
0x202020
}
);
// Physics variables
var
gravityConstant
=
7.8
;
var
collisionConfiguration
;
var
dispatcher
;
var
broadphase
;
var
solver
;
var
physicsWorld
;
var
margin
=
0.05
;
var
convexBreaker
=
new
THREE
.
ConvexBufferObjectBreaker
();
// Rigid bodies include all movable objects
var
rigidBodies
=
[];
var
pos
=
new
THREE
.
Vector3
();
var
quat
=
new
THREE
.
Quaternion
();
var
transformAux1
=
new
Ammo
.
btTransform
();
var
tempBtVec3_1
=
new
Ammo
.
btVector3
(
0
,
0
,
0
);
var
time
=
0
;
var
objectsToRemove
=
[];
for
(
var
i
=
0
;
i
<
500
;
i
++
)
{
objectsToRemove
[
i
]
=
null
;
}
var
numObjectsToRemove
=
0
;
var
impactPoint
=
new
THREE
.
Vector3
();
var
impactNormal
=
new
THREE
.
Vector3
();
// - Main code -
init
();
animate
();
// - Functions -
function
init
()
{
initGraphics
();
initPhysics
();
createObjects
();
initInput
();
}
function
initGraphics
()
{
container
=
document
.
getElementById
(
'
container
'
);
camera
=
new
THREE
.
PerspectiveCamera
(
60
,
window
.
innerWidth
/
window
.
innerHeight
,
0.2
,
2000
);
scene
=
new
THREE
.
Scene
();
scene
.
background
=
new
THREE
.
Color
(
0xbfd1e5
);
camera
.
position
.
set
(
-
14
,
8
,
16
);
controls
=
new
THREE
.
OrbitControls
(
camera
);
controls
.
target
.
set
(
0
,
2
,
0
);
controls
.
update
();
renderer
=
new
THREE
.
WebGLRenderer
();
renderer
.
setPixelRatio
(
window
.
devicePixelRatio
);
renderer
.
setSize
(
window
.
innerWidth
,
window
.
innerHeight
);
renderer
.
shadowMap
.
enabled
=
true
;
textureLoader
=
new
THREE
.
TextureLoader
();
var
ambientLight
=
new
THREE
.
AmbientLight
(
0x707070
);
scene
.
add
(
ambientLight
);
var
light
=
new
THREE
.
DirectionalLight
(
0xffffff
,
1
);
light
.
position
.
set
(
-
10
,
18
,
5
);
light
.
castShadow
=
true
;
var
d
=
14
;
light
.
shadow
.
camera
.
left
=
-
d
;
light
.
shadow
.
camera
.
right
=
d
;
light
.
shadow
.
camera
.
top
=
d
;
light
.
shadow
.
camera
.
bottom
=
-
d
;
light
.
shadow
.
camera
.
near
=
2
;
light
.
shadow
.
camera
.
far
=
50
;
light
.
shadow
.
mapSize
.
x
=
1024
;
light
.
shadow
.
mapSize
.
y
=
1024
;
scene
.
add
(
light
);
container
.
innerHTML
=
""
;
container
.
appendChild
(
renderer
.
domElement
);
stats
=
new
Stats
();
stats
.
domElement
.
style
.
position
=
'
absolute
'
;
stats
.
domElement
.
style
.
top
=
'
0px
'
;
container
.
appendChild
(
stats
.
domElement
);
//
window
.
addEventListener
(
'
resize
'
,
onWindowResize
,
false
);
}
function
initPhysics
()
{
// Physics configuration
collisionConfiguration
=
new
Ammo
.
btDefaultCollisionConfiguration
();
dispatcher
=
new
Ammo
.
btCollisionDispatcher
(
collisionConfiguration
);
broadphase
=
new
Ammo
.
btDbvtBroadphase
();
solver
=
new
Ammo
.
btSequentialImpulseConstraintSolver
();
physicsWorld
=
new
Ammo
.
btDiscreteDynamicsWorld
(
dispatcher
,
broadphase
,
solver
,
collisionConfiguration
);
physicsWorld
.
setGravity
(
new
Ammo
.
btVector3
(
0
,
-
gravityConstant
,
0
)
);
}
function
createObject
(
mass
,
halfExtents
,
pos
,
quat
,
material
)
{
var
object
=
new
THREE
.
Mesh
(
new
THREE
.
BoxBufferGeometry
(
halfExtents
.
x
*
2
,
halfExtents
.
y
*
2
,
halfExtents
.
z
*
2
),
material
);
object
.
position
.
copy
(
pos
);
object
.
quaternion
.
copy
(
quat
);
convexBreaker
.
prepareBreakableObject
(
object
,
mass
,
new
THREE
.
Vector3
(),
new
THREE
.
Vector3
(),
true
);
createDebrisFromBreakableObject
(
object
);
}
function
createObjects
()
{
// Ground
pos
.
set
(
0
,
-
0.5
,
0
);
quat
.
set
(
0
,
0
,
0
,
1
);
var
ground
=
createParalellepipedWithPhysics
(
40
,
1
,
40
,
0
,
pos
,
quat
,
new
THREE
.
MeshPhongMaterial
(
{
color
:
0xFFFFFF
}
)
);
ground
.
receiveShadow
=
true
;
textureLoader
.
load
(
"
textures/grid.png
"
,
function
(
texture
)
{
texture
.
wrapS
=
THREE
.
RepeatWrapping
;
texture
.
wrapT
=
THREE
.
RepeatWrapping
;
texture
.
repeat
.
set
(
40
,
40
);
ground
.
material
.
map
=
texture
;
ground
.
material
.
needsUpdate
=
true
;
}
);
// Tower 1
var
towerMass
=
1000
;
var
towerHalfExtents
=
new
THREE
.
Vector3
(
2
,
5
,
2
);
pos
.
set
(
-
8
,
5
,
0
);
quat
.
set
(
0
,
0
,
0
,
1
);
createObject
(
towerMass
,
towerHalfExtents
,
pos
,
quat
,
createMaterial
(
0xB03014
)
);
// Tower 2
pos
.
set
(
8
,
5
,
0
);
quat
.
set
(
0
,
0
,
0
,
1
);
createObject
(
towerMass
,
towerHalfExtents
,
pos
,
quat
,
createMaterial
(
0xB03214
)
);
//Bridge
var
bridgeMass
=
100
;
var
bridgeHalfExtents
=
new
THREE
.
Vector3
(
7
,
0.2
,
1.5
);
pos
.
set
(
0
,
10.2
,
0
);
quat
.
set
(
0
,
0
,
0
,
1
);
createObject
(
bridgeMass
,
bridgeHalfExtents
,
pos
,
quat
,
createMaterial
(
0xB3B865
)
);
// Stones
var
stoneMass
=
120
;
var
stoneHalfExtents
=
new
THREE
.
Vector3
(
1
,
2
,
0.15
);
var
numStones
=
8
;
quat
.
set
(
0
,
0
,
0
,
1
);
for
(
var
i
=
0
;
i
<
numStones
;
i
++
)
{
pos
.
set
(
0
,
2
,
15
*
(
0.5
-
i
/
(
numStones
+
1
)
)
);
createObject
(
stoneMass
,
stoneHalfExtents
,
pos
,
quat
,
createMaterial
(
0xB0B0B0
)
);
}
// Mountain
var
mountainMass
=
860
;
var
mountainHalfExtents
=
new
THREE
.
Vector3
(
4
,
5
,
4
);
pos
.
set
(
5
,
mountainHalfExtents
.
y
*
0.5
,
-
7
);
quat
.
set
(
0
,
0
,
0
,
1
);
var
mountainPoints
=
[];
mountainPoints
.
push
(
new
THREE
.
Vector3
(
mountainHalfExtents
.
x
,
-
mountainHalfExtents
.
y
,
mountainHalfExtents
.
z
)
);
mountainPoints
.
push
(
new
THREE
.
Vector3
(
-
mountainHalfExtents
.
x
,
-
mountainHalfExtents
.
y
,
mountainHalfExtents
.
z
)
);
mountainPoints
.
push
(
new
THREE
.
Vector3
(
mountainHalfExtents
.
x
,
-
mountainHalfExtents
.
y
,
-
mountainHalfExtents
.
z
)
);
mountainPoints
.
push
(
new
THREE
.
Vector3
(
-
mountainHalfExtents
.
x
,
-
mountainHalfExtents
.
y
,
-
mountainHalfExtents
.
z
)
);
mountainPoints
.
push
(
new
THREE
.
Vector3
(
0
,
mountainHalfExtents
.
y
,
0
)
);
var
mountain
=
new
THREE
.
Mesh
(
new
THREE
.
ConvexBufferGeometry
(
mountainPoints
),
createMaterial
(
0xB03814
)
);
mountain
.
position
.
copy
(
pos
);
mountain
.
quaternion
.
copy
(
quat
);
convexBreaker
.
prepareBreakableObject
(
mountain
,
mountainMass
,
new
THREE
.
Vector3
(),
new
THREE
.
Vector3
(),
true
);
createDebrisFromBreakableObject
(
mountain
);
}
function
createParalellepipedWithPhysics
(
sx
,
sy
,
sz
,
mass
,
pos
,
quat
,
material
)
{
var
object
=
new
THREE
.
Mesh
(
new
THREE
.
BoxBufferGeometry
(
sx
,
sy
,
sz
,
1
,
1
,
1
),
material
);
var
shape
=
new
Ammo
.
btBoxShape
(
new
Ammo
.
btVector3
(
sx
*
0.5
,
sy
*
0.5
,
sz
*
0.5
)
);
shape
.
setMargin
(
margin
);
createRigidBody
(
object
,
shape
,
mass
,
pos
,
quat
);
return
object
;
}
function
createDebrisFromBreakableObject
(
object
)
{
object
.
castShadow
=
true
;
object
.
receiveShadow
=
true
;
var
shape
=
createConvexHullPhysicsShape
(
object
.
geometry
.
attributes
.
position
.
array
);
shape
.
setMargin
(
margin
);
var
body
=
createRigidBody
(
object
,
shape
,
object
.
userData
.
mass
,
null
,
null
,
object
.
userData
.
velocity
,
object
.
userData
.
angularVelocity
);
// Set pointer back to the three object only in the debris objects
var
btVecUserData
=
new
Ammo
.
btVector3
(
0
,
0
,
0
);
btVecUserData
.
threeObject
=
object
;
body
.
setUserPointer
(
btVecUserData
);
}
function
removeDebris
(
object
)
{
scene
.
remove
(
object
);
physicsWorld
.
removeRigidBody
(
object
.
userData
.
physicsBody
);
}
function
createConvexHullPhysicsShape
(
coords
)
{
var
shape
=
new
Ammo
.
btConvexHullShape
();
for
(
var
i
=
0
,
il
=
coords
.
length
;
i
<
il
;
i
+=
3
)
{
var
p
=
coords
[
i
];
this
.
tempBtVec3_1
.
setValue
(
coords
[
i
],
coords
[
i
+
1
],
coords
[
i
+
2
]
);
var
lastOne
=
(
i
>=
(
il
-
3
)
);
shape
.
addPoint
(
this
.
tempBtVec3_1
,
lastOne
);
}
return
shape
;
}
function
createRigidBody
(
object
,
physicsShape
,
mass
,
pos
,
quat
,
vel
,
angVel
)
{
if
(
pos
)
{
object
.
position
.
copy
(
pos
);
}
else
{
pos
=
object
.
position
;
}
if
(
quat
)
{
object
.
quaternion
.
copy
(
quat
);
}
else
{
quat
=
object
.
quaternion
;
}
var
transform
=
new
Ammo
.
btTransform
();
transform
.
setIdentity
();
transform
.
setOrigin
(
new
Ammo
.
btVector3
(
pos
.
x
,
pos
.
y
,
pos
.
z
)
);
transform
.
setRotation
(
new
Ammo
.
btQuaternion
(
quat
.
x
,
quat
.
y
,
quat
.
z
,
quat
.
w
)
);
var
motionState
=
new
Ammo
.
btDefaultMotionState
(
transform
);
var
localInertia
=
new
Ammo
.
btVector3
(
0
,
0
,
0
);
physicsShape
.
calculateLocalInertia
(
mass
,
localInertia
);
var
rbInfo
=
new
Ammo
.
btRigidBodyConstructionInfo
(
mass
,
motionState
,
physicsShape
,
localInertia
);
var
body
=
new
Ammo
.
btRigidBody
(
rbInfo
);
body
.
setFriction
(
0.5
);
if
(
vel
)
{
body
.
setLinearVelocity
(
new
Ammo
.
btVector3
(
vel
.
x
,
vel
.
y
,
vel
.
z
)
);
}
if
(
angVel
)
{
body
.
setAngularVelocity
(
new
Ammo
.
btVector3
(
angVel
.
x
,
angVel
.
y
,
angVel
.
z
)
);
}
object
.
userData
.
physicsBody
=
body
;
object
.
userData
.
collided
=
false
;
scene
.
add
(
object
);
if
(
mass
>
0
)
{
rigidBodies
.
push
(
object
);
// Disable deactivation
body
.
setActivationState
(
4
);
}
physicsWorld
.
addRigidBody
(
body
);
return
body
;
}
function
createRandomColor
()
{
return
Math
.
floor
(
Math
.
random
()
*
(
1
<<
24
)
);
}
function
createMaterial
(
color
)
{
color
=
color
||
createRandomColor
();
return
new
THREE
.
MeshPhongMaterial
(
{
color
:
color
}
);
}
function
initInput
()
{
window
.
addEventListener
(
'
mousedown
'
,
function
(
event
)
{
mouseCoords
.
set
(
(
event
.
clientX
/
window
.
innerWidth
)
*
2
-
1
,
-
(
event
.
clientY
/
window
.
innerHeight
)
*
2
+
1
);
raycaster
.
setFromCamera
(
mouseCoords
,
camera
);
// Creates a ball and throws it
var
ballMass
=
35
;
var
ballRadius
=
0.4
;
var
ball
=
new
THREE
.
Mesh
(
new
THREE
.
SphereBufferGeometry
(
ballRadius
,
14
,
10
),
ballMaterial
);
ball
.
castShadow
=
true
;
ball
.
receiveShadow
=
true
;
var
ballShape
=
new
Ammo
.
btSphereShape
(
ballRadius
);
ballShape
.
setMargin
(
margin
);
pos
.
copy
(
raycaster
.
ray
.
direction
);
pos
.
add
(
raycaster
.
ray
.
origin
);
quat
.
set
(
0
,
0
,
0
,
1
);
var
ballBody
=
createRigidBody
(
ball
,
ballShape
,
ballMass
,
pos
,
quat
);
pos
.
copy
(
raycaster
.
ray
.
direction
);
pos
.
multiplyScalar
(
24
);
ballBody
.
setLinearVelocity
(
new
Ammo
.
btVector3
(
pos
.
x
,
pos
.
y
,
pos
.
z
)
);
},
false
);
}
function
onWindowResize
()
{
camera
.
aspect
=
window
.
innerWidth
/
window
.
innerHeight
;
camera
.
updateProjectionMatrix
();
renderer
.
setSize
(
window
.
innerWidth
,
window
.
innerHeight
);
}
function
animate
()
{
requestAnimationFrame
(
animate
);
render
();
stats
.
update
();
}
function
render
()
{
var
deltaTime
=
clock
.
getDelta
();
updatePhysics
(
deltaTime
);
renderer
.
render
(
scene
,
camera
);
time
+=
deltaTime
;
}
function
updatePhysics
(
deltaTime
)
{
// Step world
physicsWorld
.
stepSimulation
(
deltaTime
,
10
);
// Update rigid bodies
for
(
var
i
=
0
,
il
=
rigidBodies
.
length
;
i
<
il
;
i
++
)
{
var
objThree
=
rigidBodies
[
i
];
var
objPhys
=
objThree
.
userData
.
physicsBody
;
var
ms
=
objPhys
.
getMotionState
();
if
(
ms
)
{
ms
.
getWorldTransform
(
transformAux1
);
var
p
=
transformAux1
.
getOrigin
();
var
q
=
transformAux1
.
getRotation
();
objThree
.
position
.
set
(
p
.
x
(),
p
.
y
(),
p
.
z
()
);
objThree
.
quaternion
.
set
(
q
.
x
(),
q
.
y
(),
q
.
z
(),
q
.
w
()
);
objThree
.
userData
.
collided
=
false
;
}
}
for
(
var
i
=
0
,
il
=
dispatcher
.
getNumManifolds
();
i
<
il
;
i
++
)
{
var
contactManifold
=
dispatcher
.
getManifoldByIndexInternal
(
i
);
var
rb0
=
contactManifold
.
getBody0
();
var
rb1
=
contactManifold
.
getBody1
();
var
threeObject0
=
Ammo
.
castObject
(
rb0
.
getUserPointer
(),
Ammo
.
btVector3
).
threeObject
;
var
threeObject1
=
Ammo
.
castObject
(
rb1
.
getUserPointer
(),
Ammo
.
btVector3
).
threeObject
;
if
(
!
threeObject0
&&
!
threeObject1
)
{
continue
;
}
var
userData0
=
threeObject0
?
threeObject0
.
userData
:
null
;
var
userData1
=
threeObject1
?
threeObject1
.
userData
:
null
;
var
breakable0
=
userData0
?
userData0
.
breakable
:
false
;
var
breakable1
=
userData1
?
userData1
.
breakable
:
false
;
var
collided0
=
userData0
?
userData0
.
collided
:
false
;
var
collided1
=
userData1
?
userData1
.
collided
:
false
;
if
(
(
!
breakable0
&&
!
breakable1
)
||
(
collided0
&&
collided1
)
)
{
continue
;
}
var
contact
=
false
;
var
maxImpulse
=
0
;
for
(
var
j
=
0
,
jl
=
contactManifold
.
getNumContacts
();
j
<
jl
;
j
++
)
{
var
contactPoint
=
contactManifold
.
getContactPoint
(
j
);
if
(
contactPoint
.
getDistance
()
<
0
)
{
contact
=
true
;
var
impulse
=
contactPoint
.
getAppliedImpulse
();
if
(
impulse
>
maxImpulse
)
{
maxImpulse
=
impulse
;
var
pos
=
contactPoint
.
get_m_positionWorldOnB
();
var
normal
=
contactPoint
.
get_m_normalWorldOnB
();
impactPoint
.
set
(
pos
.
x
(),
pos
.
y
(),
pos
.
z
()
);
impactNormal
.
set
(
normal
.
x
(),
normal
.
y
(),
normal
.
z
()
);
}
break
;
}
}
// If no point has contact, abort
if
(
!
contact
)
{
continue
;
}
// Subdivision
var
fractureImpulse
=
250
;
if
(
breakable0
&&
!
collided0
&&
maxImpulse
>
fractureImpulse
)
{
var
debris
=
convexBreaker
.
subdivideByImpact
(
threeObject0
,
impactPoint
,
impactNormal
,
1
,
2
,
1.5
);
var
numObjects
=
debris
.
length
;
for
(
var
j
=
0
;
j
<
numObjects
;
j
++
)
{
createDebrisFromBreakableObject
(
debris
[
j
]
);
}
objectsToRemove
[
numObjectsToRemove
++
]
=
threeObject0
;
userData0
.
collided
=
true
;
}
if
(
breakable1
&&
!
collided1
&&
maxImpulse
>
fractureImpulse
)
{
var
debris
=
convexBreaker
.
subdivideByImpact
(
threeObject1
,
impactPoint
,
impactNormal
,
1
,
2
,
1.5
);
var
numObjects
=
debris
.
length
;
for
(
var
j
=
0
;
j
<
numObjects
;
j
++
)
{
createDebrisFromBreakableObject
(
debris
[
j
]
);
}
objectsToRemove
[
numObjectsToRemove
++
]
=
threeObject1
;
userData1
.
collided
=
true
;
}
}
for
(
var
i
=
0
;
i
<
numObjectsToRemove
;
i
++
)
{
removeDebris
(
objectsToRemove
[
i
]
);
}
numObjectsToRemove
=
0
;
}
</script>
</body>
</html>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录