Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
车家大少爷
three.js
提交
7c67cfb3
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,发现更多精彩内容 >>
提交
7c67cfb3
编写于
9月 15, 2013
作者:
M
Mr.doob
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added Mirror. See #3856.
上级
d1eace25
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
502 addition
and
0 deletion
+502
-0
examples/index.html
examples/index.html
+1
-0
examples/js/Mirror.js
examples/js/Mirror.js
+286
-0
examples/webgl_mirror.html
examples/webgl_mirror.html
+215
-0
未找到文件。
examples/index.html
浏览文件 @
7c67cfb3
...
...
@@ -219,6 +219,7 @@
"
webgl_materials_texture_manualmipmap
"
,
"
webgl_materials_video
"
,
"
webgl_materials_wireframe
"
,
"
webgl_mirror
"
,
"
webgl_morphnormals
"
,
"
webgl_morphtargets
"
,
"
webgl_morphtargets_horse
"
,
...
...
examples/js/Mirror.js
0 → 100644
浏览文件 @
7c67cfb3
/**
* @author Slayvin / http://slayvin.net
*/
THREE
.
ShaderLib
[
'
mirror
'
]
=
{
uniforms
:
{
"
mirrorColor
"
:
{
type
:
"
c
"
,
value
:
new
THREE
.
Color
(
0x7F7F7F
)
},
"
mirrorSampler
"
:
{
type
:
"
t
"
,
value
:
null
},
"
textureMatrix
"
:
{
type
:
"
m4
"
,
value
:
new
THREE
.
Matrix4
()
}
},
vertexShader
:
[
"
uniform mat4 textureMatrix;
"
,
"
varying vec4 mirrorCoord;
"
,
"
void main() {
"
,
"
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
"
,
"
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
"
,
"
mirrorCoord = textureMatrix * worldPosition;
"
,
"
gl_Position = projectionMatrix * mvPosition;
"
,
"
}
"
].
join
(
"
\n
"
),
fragmentShader
:
[
"
uniform vec3 mirrorColor;
"
,
"
uniform sampler2D mirrorSampler;
"
,
"
varying vec4 mirrorCoord;
"
,
"
float blendOverlay(float base, float blend) {
"
,
"
return( base < 0.5 ? ( 2.0 * base * blend ) : (1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );
"
,
"
}
"
,
"
void main() {
"
,
"
vec4 color = texture2DProj(mirrorSampler, mirrorCoord);
"
,
"
color = vec4(blendOverlay(mirrorColor.r, color.r), blendOverlay(mirrorColor.g, color.g), blendOverlay(mirrorColor.b, color.b), 1.0);
"
,
"
gl_FragColor = color;
"
,
"
}
"
].
join
(
"
\n
"
)
};
THREE
.
Mirror
=
function
(
renderer
,
camera
,
options
)
{
THREE
.
Object3D
.
call
(
this
);
this
.
name
=
'
mirror_
'
+
this
.
id
;
function
isPowerOfTwo
(
value
)
{
return
(
value
&
(
value
-
1
)
)
===
0
;
};
options
=
options
||
{};
this
.
matrixNeedsUpdate
=
true
;
var
width
=
options
.
textureWidth
!==
undefined
?
options
.
textureWidth
:
512
;
var
height
=
options
.
textureHeight
!==
undefined
?
options
.
textureHeight
:
512
;
this
.
clipBias
=
options
.
clipBias
!==
undefined
?
options
.
clipBias
:
0.0
;
var
mirrorColor
=
options
.
color
!==
undefined
?
new
THREE
.
Color
(
options
.
color
)
:
new
THREE
.
Color
(
0x7F7F7F
);
this
.
renderer
=
renderer
;
this
.
mirrorPlane
=
new
THREE
.
Plane
();
this
.
normal
=
new
THREE
.
Vector3
(
0
,
0
,
1
);
this
.
mirrorWorldPosition
=
new
THREE
.
Vector3
();
this
.
cameraWorldPosition
=
new
THREE
.
Vector3
();
this
.
rotationMatrix
=
new
THREE
.
Matrix4
();
this
.
lookAtPosition
=
new
THREE
.
Vector3
(
0
,
0
,
-
1
);
this
.
clipPlane
=
new
THREE
.
Vector4
();
// For debug only, show the normal and plane of the mirror
var
debugMode
=
options
.
debugMode
!==
undefined
?
options
.
debugMode
:
false
;
if
(
debugMode
){
var
arrow
=
new
THREE
.
ArrowHelper
(
new
THREE
.
Vector3
(
0
,
0
,
1
),
new
THREE
.
Vector3
(
0
,
0
,
0
),
10
,
0xffff80
);
var
planeGeometry
=
new
THREE
.
Geometry
();
planeGeometry
.
vertices
.
push
(
new
THREE
.
Vector3
(
-
10
,
-
10
,
0
)
);
planeGeometry
.
vertices
.
push
(
new
THREE
.
Vector3
(
10
,
-
10
,
0
)
);
planeGeometry
.
vertices
.
push
(
new
THREE
.
Vector3
(
10
,
10
,
0
)
);
planeGeometry
.
vertices
.
push
(
new
THREE
.
Vector3
(
-
10
,
10
,
0
)
);
planeGeometry
.
vertices
.
push
(
planeGeometry
.
vertices
[
0
]
);
var
plane
=
new
THREE
.
Line
(
planeGeometry
,
new
THREE
.
LineBasicMaterial
(
{
color
:
0xffff80
}
)
);
this
.
add
(
arrow
);
this
.
add
(
plane
);
}
if
(
camera
instanceof
THREE
.
PerspectiveCamera
)
this
.
camera
=
camera
;
else
{
this
.
camera
=
new
THREE
.
PerspectiveCamera
();
console
.
log
(
this
.
name
+
'
: camera is not a Perspective Camera!
'
)
}
this
.
textureMatrix
=
new
THREE
.
Matrix4
();
this
.
mirrorCamera
=
this
.
camera
.
clone
();
this
.
texture
=
new
THREE
.
WebGLRenderTarget
(
width
,
height
);
this
.
tempTexture
=
new
THREE
.
WebGLRenderTarget
(
width
,
height
);
var
mirrorShader
=
THREE
.
ShaderLib
[
"
mirror
"
];
var
mirrorUniforms
=
THREE
.
UniformsUtils
.
clone
(
mirrorShader
.
uniforms
);
this
.
material
=
new
THREE
.
ShaderMaterial
(
{
fragmentShader
:
mirrorShader
.
fragmentShader
,
vertexShader
:
mirrorShader
.
vertexShader
,
uniforms
:
mirrorUniforms
}
);
this
.
material
.
uniforms
.
mirrorSampler
.
value
=
this
.
texture
;
this
.
material
.
uniforms
.
mirrorColor
.
value
=
mirrorColor
;
this
.
material
.
uniforms
.
textureMatrix
.
value
=
this
.
textureMatrix
;
if
(
!
isPowerOfTwo
(
width
)
||
!
isPowerOfTwo
(
height
)
)
{
this
.
texture
.
generateMipmaps
=
false
;
this
.
tempTexture
.
generateMipmaps
=
false
;
}
this
.
updateTextureMatrix
();
this
.
render
();
};
THREE
.
Mirror
.
prototype
=
Object
.
create
(
THREE
.
Object3D
.
prototype
);
THREE
.
Mirror
.
prototype
.
renderWithMirror
=
function
(
otherMirror
)
{
// update the mirror matrix to mirror the current view
this
.
updateTextureMatrix
();
this
.
matrixNeedsUpdate
=
false
;
// set the camera of the other mirror so the mirrored view is the reference view
var
tempCamera
=
otherMirror
.
camera
;
otherMirror
.
camera
=
this
.
mirrorCamera
;
// render the other mirror in temp texture
otherMirror
.
renderTemp
();
otherMirror
.
material
.
uniforms
.
mirrorSampler
.
value
=
otherMirror
.
tempTexture
;
// render the current mirror
this
.
render
();
this
.
matrixNeedsUpdate
=
true
;
// restore material and camera of other mirror
otherMirror
.
material
.
uniforms
.
mirrorSampler
.
value
=
otherMirror
.
texture
;
otherMirror
.
camera
=
tempCamera
;
// restore texture matrix of other mirror
otherMirror
.
updateTextureMatrix
();
};
THREE
.
Mirror
.
prototype
.
updateTextureMatrix
=
function
()
{
function
sign
(
x
)
{
return
x
?
x
<
0
?
-
1
:
1
:
0
;
}
this
.
updateMatrixWorld
();
this
.
camera
.
updateMatrixWorld
();
this
.
mirrorWorldPosition
.
getPositionFromMatrix
(
this
.
matrixWorld
);
this
.
cameraWorldPosition
.
getPositionFromMatrix
(
this
.
camera
.
matrixWorld
);
this
.
rotationMatrix
.
extractRotation
(
this
.
matrixWorld
);
this
.
normal
.
set
(
0
,
0
,
1
);
this
.
normal
.
applyMatrix4
(
this
.
rotationMatrix
);
var
view
=
this
.
mirrorWorldPosition
.
clone
().
sub
(
this
.
cameraWorldPosition
);
var
reflectView
=
view
.
reflect
(
this
.
normal
);
reflectView
.
add
(
this
.
mirrorWorldPosition
);
this
.
rotationMatrix
.
extractRotation
(
this
.
camera
.
matrixWorld
);
this
.
lookAtPosition
.
set
(
0
,
0
,
-
1
);
this
.
lookAtPosition
.
applyMatrix4
(
this
.
rotationMatrix
);
this
.
lookAtPosition
.
add
(
this
.
cameraWorldPosition
);
var
target
=
this
.
mirrorWorldPosition
.
clone
().
sub
(
this
.
lookAtPosition
);
var
reflectTarget
=
target
.
reflect
(
this
.
normal
);
reflectTarget
.
add
(
this
.
mirrorWorldPosition
);
this
.
up
.
set
(
0
,
-
1
,
0
);
this
.
up
.
applyMatrix4
(
this
.
rotationMatrix
);
var
reflectUp
=
this
.
up
.
reflect
(
this
.
normal
);
this
.
mirrorCamera
.
position
.
copy
(
reflectView
);
this
.
mirrorCamera
.
up
=
reflectUp
;
this
.
mirrorCamera
.
lookAt
(
reflectTarget
);
this
.
mirrorCamera
.
updateProjectionMatrix
();
this
.
mirrorCamera
.
updateMatrixWorld
();
this
.
mirrorCamera
.
matrixWorldInverse
.
getInverse
(
this
.
mirrorCamera
.
matrixWorld
);
// Update the texture matrix
this
.
textureMatrix
.
set
(
0.5
,
0.0
,
0.0
,
0.5
,
0.0
,
0.5
,
0.0
,
0.5
,
0.0
,
0.0
,
0.5
,
0.5
,
0.0
,
0.0
,
0.0
,
1.0
);
this
.
textureMatrix
.
multiply
(
this
.
mirrorCamera
.
projectionMatrix
);
this
.
textureMatrix
.
multiply
(
this
.
mirrorCamera
.
matrixWorldInverse
);
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
this
.
mirrorPlane
.
setFromNormalAndCoplanarPoint
(
this
.
normal
,
this
.
mirrorWorldPosition
);
this
.
mirrorPlane
.
applyMatrix4
(
this
.
mirrorCamera
.
matrixWorldInverse
);
this
.
clipPlane
.
set
(
this
.
mirrorPlane
.
normal
.
x
,
this
.
mirrorPlane
.
normal
.
y
,
this
.
mirrorPlane
.
normal
.
z
,
this
.
mirrorPlane
.
constant
);
var
q
=
new
THREE
.
Vector4
();
var
projectionMatrix
=
this
.
mirrorCamera
.
projectionMatrix
;
q
.
x
=
(
sign
(
this
.
clipPlane
.
x
)
+
projectionMatrix
.
elements
[
8
])
/
projectionMatrix
.
elements
[
0
];
q
.
y
=
(
sign
(
this
.
clipPlane
.
y
)
+
projectionMatrix
.
elements
[
9
])
/
projectionMatrix
.
elements
[
5
];
q
.
z
=
-
1.0
;
q
.
w
=
(
1.0
+
projectionMatrix
.
elements
[
10
])
/
projectionMatrix
.
elements
[
14
];
// Calculate the scaled plane vector
var
c
=
new
THREE
.
Vector4
();
c
=
this
.
clipPlane
.
multiplyScalar
(
2.0
/
this
.
clipPlane
.
dot
(
q
)
);
// Replacing the third row of the projection matrix
projectionMatrix
.
elements
[
2
]
=
c
.
x
;
projectionMatrix
.
elements
[
6
]
=
c
.
y
;
projectionMatrix
.
elements
[
10
]
=
c
.
z
+
1.0
-
this
.
clipBias
;
projectionMatrix
.
elements
[
14
]
=
c
.
w
;
};
THREE
.
Mirror
.
prototype
.
render
=
function
()
{
if
(
this
.
matrixNeedsUpdate
)
this
.
updateTextureMatrix
();
this
.
matrixNeedsUpdate
=
true
;
// Render the mirrored view of the current scene into the target texture
var
scene
=
this
;
while
(
scene
.
parent
!==
undefined
)
{
scene
=
scene
.
parent
;
}
if
(
scene
!==
undefined
&&
scene
instanceof
THREE
.
Scene
)
{
this
.
renderer
.
render
(
scene
,
this
.
mirrorCamera
,
this
.
texture
,
true
);
}
};
THREE
.
Mirror
.
prototype
.
renderTemp
=
function
()
{
if
(
this
.
matrixNeedsUpdate
)
this
.
updateTextureMatrix
();
this
.
matrixNeedsUpdate
=
true
;
// Render the mirrored view of the current scene into the target texture
var
scene
=
this
;
while
(
scene
.
parent
!==
undefined
)
{
scene
=
scene
.
parent
;
}
if
(
scene
!==
undefined
&&
scene
instanceof
THREE
.
Scene
)
{
this
.
renderer
.
render
(
scene
,
this
.
mirrorCamera
,
this
.
tempTexture
,
true
);
}
};
examples/webgl_mirror.html
0 → 100644
浏览文件 @
7c67cfb3
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<title>
three.js webgl - mirror
</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
:
#888888
;
font-family
:
Monospace
;
font-size
:
13px
;
background-color
:
#000
;
margin
:
0px
;
overflow
:
hidden
;
}
#info
{
position
:
absolute
;
top
:
0px
;
width
:
200px
;
left
:
calc
(
50%
-
100px
);
text-align
:
center
;
}
a
{
color
:
#00f
;
}
</style>
</head>
<body>
<div
id=
"container"
></div>
<div
id=
"info"
><a
href=
"http://threejs.org"
target=
"_blank"
>
three.js
</a>
- mirror
</div>
<script
src=
"../build/three.min.js"
></script>
<script
src=
"js/Mirror.js"
></script>
<script
src=
"js/controls/OrbitControls.js"
></script>
<script>
// scene size
var
WIDTH
=
window
.
innerWidth
;
var
HEIGHT
=
window
.
innerHeight
;
// camera
var
VIEW_ANGLE
=
45
;
var
ASPECT
=
WIDTH
/
HEIGHT
;
var
NEAR
=
1
;
var
FAR
=
500
;
var
camera
,
scane
,
renderer
;
var
cameraControls
;
var
verticalMirror
,
groundMirror
;
var
sphereGroup
,
smallSphere
;
function
init
()
{
// renderer
renderer
=
new
THREE
.
WebGLRenderer
();
renderer
.
setSize
(
WIDTH
,
HEIGHT
);
renderer
.
autoClear
=
true
;
renderer
.
setClearColor
(
0x000000
,
1
);
// scene
scene
=
new
THREE
.
Scene
();
// camera
camera
=
new
THREE
.
PerspectiveCamera
(
VIEW_ANGLE
,
ASPECT
,
NEAR
,
FAR
);
camera
.
position
.
set
(
0
,
75
,
160
);
cameraControls
=
new
THREE
.
OrbitControls
(
camera
,
renderer
.
domElement
);
cameraControls
.
target
.
set
(
0
,
40
,
0
);
cameraControls
.
maxDistance
=
400
;
cameraControls
.
minDistance
=
10
;
cameraControls
.
update
();
var
container
=
document
.
getElementById
(
'
container
'
);
container
.
appendChild
(
renderer
.
domElement
);
}
function
fillScene
()
{
var
planeGeo
=
new
THREE
.
PlaneGeometry
(
100.1
,
100.1
);
//MIRORR planes
groundMirror
=
new
THREE
.
Mirror
(
renderer
,
camera
,
{
clipBias
:
0.003
,
textureWidth
:
WIDTH
,
textureHeight
:
HEIGHT
,
color
:
0x777777
}
);
var
mirrorMesh
=
new
THREE
.
Mesh
(
planeGeo
,
groundMirror
.
material
);
mirrorMesh
.
add
(
groundMirror
);
mirrorMesh
.
rotateX
(
-
Math
.
PI
/
2
);
scene
.
add
(
mirrorMesh
);
verticalMirror
=
new
THREE
.
Mirror
(
renderer
,
camera
,
{
clipBias
:
0.003
,
textureWidth
:
WIDTH
,
textureHeight
:
HEIGHT
,
color
:
0x889999
}
);
var
verticalMirrorMesh
=
new
THREE
.
Mesh
(
new
THREE
.
PlaneGeometry
(
60
,
60
),
verticalMirror
.
material
);
verticalMirrorMesh
.
add
(
verticalMirror
);
verticalMirrorMesh
.
position
.
y
=
35
;
verticalMirrorMesh
.
position
.
z
=
-
45
;
scene
.
add
(
verticalMirrorMesh
);
sphereGroup
=
new
THREE
.
Object3D
();
scene
.
add
(
sphereGroup
);
var
geometry
=
new
THREE
.
CylinderGeometry
(
0.1
,
15
*
Math
.
cos
(
Math
.
PI
/
180
*
30
),
0.1
,
24
,
1
);
var
material
=
new
THREE
.
MeshPhongMaterial
(
{
color
:
0xffffff
,
emissive
:
0x444444
}
);
var
sphereCap
=
new
THREE
.
Mesh
(
geometry
,
material
);
sphereCap
.
position
.
y
=
-
15
*
Math
.
sin
(
Math
.
PI
/
180
*
30
)
-
0.05
;
sphereCap
.
rotateX
(
-
Math
.
PI
);
var
geometry
=
new
THREE
.
SphereGeometry
(
15
,
24
,
24
,
Math
.
PI
/
2
,
Math
.
PI
*
2
,
0
,
Math
.
PI
/
180
*
120
);
var
halfSphere
=
new
THREE
.
Mesh
(
geometry
,
material
);
halfSphere
.
add
(
sphereCap
);
halfSphere
.
rotateX
(
-
Math
.
PI
/
180
*
135
);
halfSphere
.
rotateZ
(
-
Math
.
PI
/
180
*
20
);
halfSphere
.
position
.
y
=
7.5
+
15
*
Math
.
sin
(
Math
.
PI
/
180
*
30
);
sphereGroup
.
add
(
halfSphere
);
var
geometry
=
new
THREE
.
IcosahedronGeometry
(
5
,
0
);
var
material
=
new
THREE
.
MeshLambertMaterial
(
{
color
:
0xffffff
,
emissive
:
0x333333
,
shading
:
THREE
.
FlatShading
}
);
smallSphere
=
new
THREE
.
Mesh
(
geometry
,
material
);
scene
.
add
(
smallSphere
);
// walls
var
planeTop
=
new
THREE
.
Mesh
(
planeGeo
,
new
THREE
.
MeshPhongMaterial
(
{
color
:
0xffffff
}
)
);
planeTop
.
position
.
y
=
100
;
planeTop
.
rotateX
(
Math
.
PI
/
2
);
scene
.
add
(
planeTop
);
var
planeBack
=
new
THREE
.
Mesh
(
planeGeo
,
new
THREE
.
MeshPhongMaterial
(
{
color
:
0xffffff
}
)
);
planeBack
.
position
.
z
=
-
50
;
planeBack
.
position
.
y
=
50
;
scene
.
add
(
planeBack
);
var
planeFront
=
new
THREE
.
Mesh
(
planeGeo
,
new
THREE
.
MeshPhongMaterial
(
{
color
:
0x7f7fff
}
)
);
planeFront
.
position
.
z
=
50
;
planeFront
.
position
.
y
=
50
;
planeFront
.
rotateY
(
Math
.
PI
);
scene
.
add
(
planeFront
);
var
planeRight
=
new
THREE
.
Mesh
(
planeGeo
,
new
THREE
.
MeshPhongMaterial
(
{
color
:
0x00ff00
}
)
);
planeRight
.
position
.
x
=
50
;
planeRight
.
position
.
y
=
50
;
planeRight
.
rotateY
(
-
Math
.
PI
/
2
);
scene
.
add
(
planeRight
);
var
planeLeft
=
new
THREE
.
Mesh
(
planeGeo
,
new
THREE
.
MeshPhongMaterial
(
{
color
:
0xff0000
}
)
);
planeLeft
.
position
.
x
=
-
50
;
planeLeft
.
position
.
y
=
50
;
planeLeft
.
rotateY
(
Math
.
PI
/
2
);
scene
.
add
(
planeLeft
);
// lights
var
mainLight
=
new
THREE
.
PointLight
(
0xcccccc
,
1.5
,
250
);
mainLight
.
position
.
y
=
60
;
scene
.
add
(
mainLight
);
var
greenLight
=
new
THREE
.
PointLight
(
0x00ff00
,
0.25
,
1000
);
greenLight
.
position
.
set
(
550
,
50
,
0
);
scene
.
add
(
greenLight
);
var
redLight
=
new
THREE
.
PointLight
(
0xff0000
,
0.25
,
1000
);
redLight
.
position
.
set
(
-
550
,
50
,
0
);
scene
.
add
(
redLight
);
var
blueLight
=
new
THREE
.
PointLight
(
0x7f7fff
,
0.25
,
1000
);
blueLight
.
position
.
set
(
0
,
50
,
550
);
scene
.
add
(
blueLight
);
}
function
render
()
{
// render (update) the mirrors
groundMirror
.
renderWithMirror
(
verticalMirror
);
verticalMirror
.
renderWithMirror
(
groundMirror
);
renderer
.
render
(
scene
,
camera
);
}
function
update
()
{
requestAnimationFrame
(
update
);
var
timer
=
Date
.
now
()
*
0.01
;
sphereGroup
.
rotation
.
y
-=
0.002
;
smallSphere
.
position
.
set
(
Math
.
cos
(
timer
*
0.1
)
*
30
,
Math
.
abs
(
Math
.
cos
(
timer
*
0.2
)
)
*
20
+
5
,
Math
.
sin
(
timer
*
0.1
)
*
30
);
smallSphere
.
rotation
.
y
=
(
Math
.
PI
/
2
)
-
timer
*
0.1
;
smallSphere
.
rotation
.
z
=
timer
*
0.8
;
cameraControls
.
update
();
render
();
}
init
();
fillScene
();
update
();
</script>
</body>
</html>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录