-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathcanvas_geometry_panorama_fisheye.html
278 lines (239 loc) · 10.6 KB
/
canvas_geometry_panorama_fisheye.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - panorama fisheye demo</title>
<meta charset="utf-8">
<!--
如果没有设置viewport的width的话,网页很可能会超出手机屏幕宽度,具体多宽,要看浏览器定义的默认宽度是多少
user-scalable=no,规定了用户不能缩放网页,但有些浏览器对该项支持不是很好,故需要设置minimum-scale和maximum-scale相同来限制用户缩放
-->
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: rgb(200,200,200);
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
color: #ffffff;
padding: 5px;
font-family:Monospace;
font-size:13px;
font-weight: bold;
text-align:center;
}
a {
color: #ffffff;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - panorama fisheye demo. cubemap by <a href="http://www.zfight.com/" target="_blank">Jochum Skoglund</a>. (mousewheel: change fov)</div>
<script src="../build/three.js"></script>
<!--
想要使用CanvasRenderer,必须添加如下两个js文件
Projector.js顾名思义上将3d图像投影到Canvas("2d")上,如果没有该文件会报如下错误
THREE.Projector has been moved to /examples/js/renderers/Projector.js. three.js:42883:3
TypeError: THREE.RenderableVertex is not a constructor
-->
<script src="js/renderers/Projector.js"></script>
<script src="js/renderers/CanvasRenderer.js"></script>
<script>
var camera, scene, renderer;
//这里根本不需要canvas
//var texture_placeholder,
//标记是否存在用户交互
isUserInteracting = false,
//鼠标按下时的x,y坐标
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
//longtitude 经度
lon = 90, onMouseDownLon = 0,
//latitude 维度
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0,
//相机注视方向
target = new THREE.Vector3();
init();
animate();
function init() {
var container, mesh;
container = document.getElementById( 'container' );
/*
透视相机
PerspectiveCamera(fov, aspect, near, far)
fov(视场):从相机位置能够看到的部分场景。推荐默认值45
aspect(长宽比):渲染结果输出区域的横向长度和纵向长度的比值。推荐默认值window.innerWidth/window.innerHeight
near(近面):定义从距离相机多近的地方开始渲染场景。推荐默认值0.1
far(远面):定义相机可以从它所处的位置看多远。默认值1000
*/
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
scene = new THREE.Scene();
/*
texture_placeholder = document.createElement( 'canvas' );
texture_placeholder.width = 128;
texture_placeholder.height = 128;
var context = texture_placeholder.getContext( '2d' );
context.fillStyle = 'rgb( 200, 200, 200 )';
context.fillRect( 0, 0, texture_placeholder.width, texture_placeholder.height );
*/
/*
也可以从地图集中一次性批量提取图片,顺序分别是右左上下后前
var textures = getTexturesFromAtlasFile( "textures/cube/sun_temple_stripe.jpg", 6 );
如果下面的MultiMaterial中某个material缺失的话,会显示黑色
*/
var materials = [
/*
loadTexture( 'textures/cube/skybox/px.jpg' ), // right
loadTexture( 'textures/cube/skybox/nx.jpg' ), // left
loadTexture( 'textures/cube/skybox/py.jpg' ), // top
loadTexture( 'textures/cube/skybox/ny.jpg' ), // bottom
loadTexture( 'textures/cube/skybox/pz.jpg' ), // back
loadTexture( 'textures/cube/skybox/nz.jpg' ) // front
*/
loadTexture( 'textures/cube/test/px.jpg' ), // right
loadTexture( 'textures/cube/test/nx.jpg' ), // left
loadTexture( 'textures/cube/test/py.jpg' ), // top
loadTexture( 'textures/cube/test/ny.jpg' ), // bottom
loadTexture( 'textures/cube/test/pz.jpg' ), // back
loadTexture( 'textures/cube/test/nz.jpg' ) // front
];
//这里将立方体的每条边分成了7份,换成1份也是可以的,没影响
mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MultiMaterial( materials ) );
//由于默认情况只渲染物体外部,将某一坐标置反,可以达到渲染内部的效果
//mesh.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, -1 ) );
mesh.scale.x = - 1;
//如果不设置的话,网格位置默认为Vector3{x:0,y:0,z:0}
scene.add( mesh );
for ( var i = 0, l = mesh.geometry.vertices.length; i < l; i ++ ) {
var vertex = mesh.geometry.vertices[ i ];
//归一化函数,将向量缩放为单位向量
vertex.normalize();
//向量乘以一个标量
vertex.multiplyScalar( 550 );
}
renderer = new THREE.CanvasRenderer();
//window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例
renderer.setPixelRatio( window.devicePixelRatio );
//设置渲染场景的大小
renderer.setSize( window.innerWidth, window.innerHeight );
//将渲染器的DOM元素(即Canvas)添加到HTML中
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'wheel', onDocumentMouseWheel, false );
//注意:触摸事件比鼠标事件少了一个touchend,因为暂不存在不放开手指的情况
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
//更新透视相机的宽高比。如果宽高比不对,那么正方形可能就不是正方形了
camera.aspect = window.innerWidth / window.innerHeight;
//更新相机的投影矩阵
camera.updateProjectionMatrix();
//重新设置渲染场景的大小
renderer.setSize( window.innerWidth, window.innerHeight );
}
function loadTexture( path ) {
//由于不是从canvas中获取图片,用canvas来初始化就显得很没道理
//var texture = new THREE.Texture( texture_placeholder );
var texture = new THREE.Texture();
/*
MeshBasicMaterial:与光照无关,仅根据材质的颜色或贴图来渲染物体
color:材质的颜色
map:材质的贴图
wireframe: 显示三角形线框还是显示面
side:可选的值有THREE.FrontSide(仅渲染正面)、THREE.BackSide(仅渲染背面)、THREE.DoubleSide(双面渲染)
overdraw:过渡描绘。如果用THREE.CanvasRenderer对象,有缝隙时需设置该值。例如当前如果使用0.5以下的值,三角形的分界线就很明显。但是使用WebGLRenderer则不会有分割线
*/
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var image = new Image();
image.onload = function () {
texture.image = this;
//由于图片是异步加载的,一旦检测到needsUpdate=true,three.js就会使用_gl.texImage2D将空的纹理数据传输到显存中,然后就将这个标志位设成false, 之后再使用该图片的时候就不需要重新加载显存数据了
texture.needsUpdate = true;
};
image.src = path;
return material;
}
function onDocumentMouseDown( event ) {
//通知 Web 浏览器不要执行与事件关联的默认动作
event.preventDefault();
isUserInteracting = true;
//clientX和clientY 表示事件触发时,相对于当前窗口的坐标
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting === true ) {
//鼠标拖动的方向与相机注视的方向相反,与TrackballControls插件效果相近
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp( event ) {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
//delta可以获取鼠标滚轮的方向和速度。如果delta的值是负的,那么滚轮就是向下滚动,正的就是向上。deltaX, deltaY分别是滚轮滚动的坐标值
camera.fov += event.deltaY * 0.05;
//这里要设置一个视场范围,过大或过小的视场都会导致显示异常
camera.fov = Math.max(10, camera.fov);
camera.fov = Math.min(120, camera.fov);
//更新相机的投影矩阵
camera.updateProjectionMatrix();
}
function onDocumentTouchStart( event ) {
/*
event.touches存放的是多指触碰时的位置数组
三个等号是恒等,比较数值的同时也比较类型。
这里限制只有单指触摸的时候才执行相应的方法
*/
if ( event.touches.length === 1 ) {
event.preventDefault();
onPointerDownPointerX = event.touches[ 0 ].pageX;
onPointerDownPointerY = event.touches[ 0 ].pageY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
lon = ( onPointerDownPointerX - event.touches[0].pageX ) * 0.1 + onPointerDownLon;
lat = ( event.touches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function animate() {
requestAnimationFrame( animate );
update();
}
function update() {
//没有交互的情况下对改变观察方向
if ( isUserInteracting === false ) {
lon += 0.1;
}
//设置仰俯角范围[-85,85]
lat = Math.max( - 85, Math.min( 85, lat ) );
//THREE.Math.degToRad将角度转换成弧度
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
//相机注视的点是一个半径为r的球上的一点,这是一个方向向量
var r = 500;
target.x = r * Math.sin( phi ) * Math.cos( theta );
target.y = r * Math.cos( phi );
target.z = r * Math.sin( phi ) * Math.sin( theta );
//修改相机的位置为注视点所在球体的对面
camera.position.copy( target ).negate();
camera.lookAt( target );
renderer.render( scene, camera );
}
</script>
</body>
</html>