本文搬自我的Github,https://github.com/555chy/three.js-example-comment,有兴趣的可以一起来完善,这个为Three.js的Example进行注解,方便初学者阅读
three.js 官网 Example 地址:https://threejs.org/examples/
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - panorama(全景画)</title>
<meta charset="utf-8">
<!--
如果没有设置viewport的width的话,网页很可能会超出手机屏幕宽度,具体多宽,要看浏览器定义的默认宽度是多少
user-scalable=no,规定了用户不能缩放网页,但有些浏览器对该项支持不是很好,故需要设置minimum-scale和maximum-scale相同来限制用户缩放
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
html, body {
background-color: #000;
margin: 0px;
padding: 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:link {color:blue;}
已访问 a:visited {color:blue;}
鼠标悬停 a:hover {color:red;}
鼠标按下 a:active {color:yellow;}
*/
a {
color: #ffffff;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="http://threejs.org" target="_blank">three.js webgl</a> - cube panorama demo.
</div>
<script src="../build/three.js"></script>
<!--
轨道控制,鼠标左键旋转(与鼠标方向相同,用于非触摸屏上),右键平移,中键缩放;也可以使用键盘控制
-->
<script src="js/controls/OrbitControls.js"></script>
<script>
var camera, controls;
var renderer;
var scene;
init();
animate();
function init() {
var container = document.getElementById( 'container' );
renderer = new THREE.WebGLRenderer();
//devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例,与Android上的DIP相仿,作用是在所有设备上的显示效果都相近
renderer.setPixelRatio( window.devicePixelRatio );
//设置渲染场景的大小
renderer.setSize( window.innerWidth, window.innerHeight );
//将渲染器的DOM元素(即Canvas)添加到HTML中
container.appendChild( renderer.domElement );
scene = new THREE.Scene();
// 坐标轴
var axes = new THREE.AxisHelper(1);
scene.add(axes);
/*
透视相机
PerspectiveCamera(fov, aspect, near, far)
fov(视场):从相机位置能够看到的部分场景。推荐默认值45
aspect(长宽比):渲染结果输出区域的横向长度和纵向长度的比值。推荐默认值window.innerWidth/window.innerHeight
near(近面):定义从距离相机多近的地方开始渲染场景。推荐默认值0.1
far(远面):定义相机可以从它所处的位置看多远。默认值1000
*/
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.01, 100 );
//只要将相机的位置修改到10,就能看到辅助坐标轴了
camera.position.z = 0.01;
//定义相机的位置,有如下两种方式。如果不设置的话,相机位置为默认的Vector3{x:0,y:0,z:0}
//camera.position.set(0,0,0.01);
//这句可以不加,因为初始化相机后,默认就会对着场景中心
//camera.lookAt(scene);
//轨道控制器控制相机
controls = new THREE.OrbitControls( camera );
//缩放设置
controls.enableZoom = true;
//平移设置
controls.enablePan = false;
//旋转设置
controls.enableRotate = true;
//实际贴图
var textures = getTexturesFromAtlasFile( "textures/cube/sun_temple_stripe.jpg", 6 );
//我做的辅助图
//var textures = getTexturesFromAtlasFile( "textures/cube/panorama_cube.jpg", 6 );
var materials = [];
for ( var i = 0; i < 6; i ++ ) {
//仅渲染外部
materials.push( new THREE.MeshBasicMaterial( { map: textures[ i ], side: THREE.FrontSide } ) );
//仅渲染内部
//materials.push( new THREE.MeshBasicMaterial( { map: textures[ i ], side: THREE.BackSide } ) );
//内部外部都渲染
//materials.push( new THREE.MeshBasicMaterial( { map: textures[ i ], side: THREE.DoubleSide } ) );
}
/*
MultiMaterial(多材质): A Material to define multiple materials for the same geometry.
The geometry decides which material is used for which faces by the faces materialindex.
用一个材质对象来为同一个几何体定义多个材质。该几何体会通过面的材质索引来决定哪一个面使用哪一种材质。
相机从立方体正面看,材质的顺序为:left(x),right(-x),top(y),bottom(-y),front(z),back(-z)
*/
var multiMaterial = new THREE.MultiMaterial( materials );
var skyBox = new THREE.Mesh( new THREE.CubeGeometry( 1, 1, 1 ), multiMaterial );
/*
THREE.Matrix4().makeScale(x,y,z) =》
{ x, 0, 0, 0 }
{ 0, y, 0, 0 }
{ 0, 0, z, 0 }
{ 0, 0, 0, 1 }
如果调用者本身的matrixWorldNeedsUpdate值为真,那么在函数applyMatrix(matrix)中,改变了matrix值后立刻就更新了position,rotation等属性
但在函数translate(distance,axis)中改变了position等变量(或者直接改变position等属性)后并没有立刻更新matrix值,这时应该手动调用updateMatrix()。
几何对象的原始Matrix(跟side无关) =》
{ 1, 0, 0, 0 }
{ 0, 1, 0, 0 }
{ 0, 0, 1, 0 }
{ 0, 0, 0, 1 }
mesh.applyMatrix之后,mesh.matrix的值为 =》
{ x, 0*xy, 0*yz, 0*xyz }
{ 0, y, 0, 0 }
{ 0, 0*x, z, 0 }
{ 0, 0, 0, 1 }
xyz表示相乘之后的符号位,负号会改变原先的material中的side参数
原始法向量normalMatrix为 =》
{ 1, 0, -0 }
{ -0, 1, 6.123 }
{ 0, -6.123, 1 }
mesh.applyMatrix之后,mesh.normalMatrix的值为 =》
{ x, 0*x*z, -0*x }
{ -0*xy, y, 6.123*y }
{ 0*x*y*z, -6.123*z, 1*z }
Error: WebGL: texImage2D: Incurred CPU-side conversion, which is very slow.
Error: WebGL: texImage2D: Chosen format/type incurred an expensive reformat 0x1908/0x1401
Multiplies the current matrix by the one specified through the parameters.
This is very slow because it will try to calculate the inverse of the transform, so avoid it whenever possible.
The equivalent function in OpenGL is glMultMatrix().
通过一个指定的参数乘以当前矩阵,这是非常慢的,因为它会尝试计算逆变换,所以如果可能的话尽量避免使用它
由于默认情况只渲染物体外部,将某一坐标置反,可以达到渲染内部的效果
skyBox.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, -1 ) );
等价于
skyBox.scale.z = -1;
*/
skyBox.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, -1 ) );
console.log(skyBox.matrix);
console.log(skyBox.normalMatrix);
scene.add( skyBox );
window.addEventListener( 'resize', onWindowResize, false );
}
//从地图集文件中获取纹理
function getTexturesFromAtlasFile( atlasImgUrl, tilesNum ) {
var textures = [];
for ( var i = 0; i < tilesNum; i ++ ) {
textures[ i ] = new THREE.Texture();
}
var imageObj = new Image();
//img标签的onload事件在图片加载完成后立即执行,这时才能取到图片的信息
imageObj.onload = function() {
var canvas, context;
var tileWidth = imageObj.height;
for ( var i = 0; i < textures.length; i ++ ) {
canvas = document.createElement( 'canvas' );
context = canvas.getContext( '2d' );
canvas.height = tileWidth;
canvas.width = tileWidth;
/*
在画布上绘制图像
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
img: 规定要使用的图像、画布或视频。
sx: 开始剪切的X坐标位置。
sy: 开始剪切的Y坐标位置。
swidth: 被剪切图像的宽度。
sheight: 被剪切图像的高度。
x: 在画布上放置图像的X坐标位置。
y: 在画布上放置图像的Y坐标位置。
width: 要使用的图像的宽度(伸展或缩小图像)
height: 要使用的图像的高度(伸展或缩小图像)
*/
context.drawImage( imageObj, tileWidth * i, 0, tileWidth, tileWidth, 0, 0, tileWidth, tileWidth );
textures[ i ].image = canvas
/*
第一次就把需要绘制的物体(Geometry)的顶点数据传输到显存中,并且缓存这个buffer到geometry.__webglVertexBuffer,
之后每次绘制的时候都会判断Geometry的verticesNeedUpdate属性,如果不需要更新就直接使用现在的缓存
*/
textures[ i ].needsUpdate = true;
}
};
imageObj.src = atlasImgUrl;
return textures;
}
function onWindowResize() {
//更新透视相机的宽高比。如果宽高比不对,那么正方形可能就不是正方形了
camera.aspect = window.innerWidth / window.innerHeight;
//更新相机的投影矩阵
camera.updateProjectionMatrix();
//重新设置渲染场景的大小
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
//更新轨道控制器,这里轨道控制器与相机关联,所以也会更新相机的位置和角度。注意这里就不用设置相机的lookAt了
controls.update();
renderer.render( scene, camera );
requestAnimationFrame( animate );
}
</script>
</body>
</html>