WebGL進修—-Three.js進修筆記(5)
簡樸網格材質 MeshNormalMaterial
MeshNormalMaterial是一種不受襯着時運用的色彩影響的材質,它隻與本身每一個面從内到外的法向量有關。法向量在webgl中用途非常普遍,光的反射,以及三維圖形的紋理映照都與這個有關。
從圖中可以看到,網格的每一面襯着的色彩都是不一樣的,假如我們想要在物體外表增加法向量,我們可以運用的THREE.ArrowHelper去示意每一個法向量,它的參數為
THREE.ArrowHelper(dir, origin, length, color, headLength, headWidth)
**個中參數的意義為:
dir:方向,默許是法向量
origin:最先的坐标位置
length:輔助線的長度
color:輔助線的色彩
headLength:頭部的長度
headWidth:頭部的寬度**
關于一個球體,要形貌它每一個面的法向量,起首須要對它的每一個面舉行周遊,掏出這個面上的三個極點(由于webgl的面都是三角形,是以是三個極點),經由過程divideScalar(3)這個函數盤算它的中間位置,我們就可以在這個中間位置點上,從内向外引出一個ArrowHelper,來模仿法向量。
for(let i=0;i
let face = sphereGeometry.faces[i];//獲得每一個面的對象
let centroid = new THREE.Vector3();
//先建立一個vector3對象,要運用這個對象找到每一個面的中間
centroid.add(sphereGeometry.vertices[face.a]);
// 将這該面的三個極點的索引傳給sphereGeometry.vertices找到其極點的坐标
//再增加進centroid
centroid.add(sphereGeometry.vertices[face.b]);
centroid.add(sphereGeometry.vertices[face.c]);
centroid.divideScalar(3);//三角形的中間點坐标
let arrow = new THREE.ArrowHelper(
face.normal,//face這個面的法向量
centroid,
2,
0xffcc55,
0.5,
0.5);//箭頭輔助線,相當于把法向量用箭頭示意出來
sphere.add(arrow);
}
個中,centroid.add(sphereGeometry.vertices[face.a])這段代碼中的sphereGeometry.vertices存有幾何體的一切極點資訊,經由過程[ ]索引可以獲得個中的某一個極點。face.a另有下面的face.b和c都是該面的極點索引号,示意這個面是由極點編号為face.a,face.b,face.c的三個極點所組成的一個三角形(webgl的面都是三角形),然後我們再盤算這三個極點的中間點。
菜單面闆的設定
在菜單面闆中設定一些MeshNormalmaterial的一些屬性,便于去測試這類材質的一些特質
個中:
**this.visible = meshMaterial.visible;//是不是可見
this.wireframe = meshMaterial.wireframe;//是不是以線框的體式格局襯着物體
this.wireframeWidth = meshMaterial.wireframeLinewidth;//線框的寬度
this.transparent = meshMaterial.transparent;//是不是通明
this.opacity = meshMaterial.opacity;//通明度,須要transparent為true才有結果
this.side = "front";//邊的襯着體式格局,有三種,前面,背面,另有雙面
this.selectMesh = "sphere";//目前挑選的幾何體
this.shading = "smooth";//着色體式格局,有平面着色戰争滑着色,對一個面很平的幾何體險些看不出區分,如正方體**
function initDatGUI() {
//設定菜單中須要的參數
controls = new function () {
this.rotationSpeed = 0.02;
this.visible = meshMaterial.visible;//是不是可見
this.wireframe = meshMaterial.wireframe;//是不是以線框的體式格局襯着物體
this.wireframeWidth = meshMaterial.wireframeLinewidth;//線框的寬度
this.transparent = meshMaterial.transparent;//是不是通明
this.opacity = meshMaterial.opacity;//通明度,須要transparent為true才有結果
this.side = "front";//邊的襯着體式格局,有三種,前面,背面,另有雙面
this.selectMesh = "sphere";//目前挑選的幾何體
this.shading = "smooth";//着色體式格局,有平面着色戰争滑着色,對一個面很平的幾何體險些看不出區分,如正方體
};
let gui = new dat.GUI();
//将方才設定的參數增加到菜單中
let F1 = gui.addFolder("Mesh");
F1.add(controls, "rotationSpeed", 0, 0.1);
F1.add(controls, "visible").onChange(function (e) {
meshMaterial.visible = e;
});
F1.add(controls, "wireframe").onChange(function (e) {
meshMaterial.wireframe = e;
});
F1.add(controls, "wireframeWidth",0,10).onChange(function (e) {
meshMaterial.wireframeWidth = e;
});
F1.add(controls, "transparent").onChange(function (e) {
meshMaterial.transparent = e;
});
F1.add(controls, "opacity",0,1).onChange(function (e) {
meshMaterial.opacity = e;
});
F1.add(controls, "side",["front","back","double"]).onChange(function (e) {
switch (e) {
case "front":
meshMaterial.side = THREE.FrontSide;
break;
case "back":
meshMaterial.side = THREE.BackSide;
break;
case "double":
meshMaterial.side = THREE.DoubleSide;
break;
}
meshMaterial.needsUpdate = true;//要在遞次中讓材質更新須要增加這一句話
});
F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) {
//先把場景的物體消滅,再來增加
scene.remove(cube);
scene.remove(sphere);
scene.remove(plane);
switch (e) {
case "sphere":
scene.add(sphere);
break;
case "cube":
scene.add(cube);
break;
case "plane":
scene.add(plane);
break;
}
});
F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) {
switch (e) {
case "flat":
meshMaterial.shading = THREE.FlatShading;
break;
case "smooth":
meshMaterial.shading = THREE.SmoothShading;
break;
}
meshMaterial.needsUpdate = true;//要在遞次中讓材質更新須要增加這一句話
});
}
**注意在遞次運轉過程當中想要轉變材質的屬性,須要在改完今後,增加一句
meshMaterial.needsUpdate = true,如許才更新勝利。**
360度全景背景
360度全景背景可以讓人有設身處地的覺得,一切這裡的背景運用了全景背景
假如想要運用全景的背景,就須要6張6個方向的圖檔來合成一個完全的背景(也可以運用1張6方向的圖檔),然後把這些貼圖指派給 scene.background
let urls =[
'image/posx.jpg',
'image/negx.jpg',
'image/posy.jpg',
'image/negy.jpg',
'image/posz.jpg',
'image/negz.jpg'
];//引入6個方向的貼圖
let cubeMap = THREE.ImageUtils.loadTextureCube( urls );
scene = new THREE.Scene();
scene.background = cubeMap;
這些圖檔的須要根據遞次擺放,右左高低後前,不然背景會紊亂。
這裡給一個全景圖檔的網站,内裡有許多的360度風景圖,都是6張範例的,下載下傳下來解壓後就可以直接引入
http://www.humus.name/index.p…
本例子的完全代碼以下:
Depth Material Test
div#WebGL-output {
border: none;
cursor: pointer;
width: 100%;
height: 850px;
background-color: #333333;
}
let camera, renderer, scene, light;
let controller;
let controls;
let cube, sphere, plane, meshMaterial;
function initThree() {
//襯着器初始化
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x333333);
document.getElementById("WebGL-output").appendChild(renderer.domElement);//将襯着增加到div中
//初始化錄影機,這裡運用透視投影錄影機
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 10, 100);
camera.position.set(0, 40, 60);
camera.up.x = 0;//設定錄影機的上方向為哪一個方向,這裡定義攝像的上方為Y軸正方向
camera.up.y = 1;
camera.up.z = 0;
camera.lookAt(0, 0, 0);
//初始化場景
let urls =[
'image/posx.jpg',
'image/negx.jpg',
'image/posy.jpg',
'image/negy.jpg',
'image/posz.jpg',
'image/negz.jpg'
];//引入6個方向的貼圖
let cubeMap = THREE.ImageUtils.loadTextureCube( urls );
scene = new THREE.Scene();
scene.background = cubeMap;
//相機的挪動
controller = new THREE.OrbitControls(camera, renderer.domElement);
controller.target = new THREE.Vector3(0, 0, 0);
light = new THREE.AmbientLight(0x0c0c0c);
scene.add(light);
// add spotlight for the shadows
light = new THREE.SpotLight(0xffffff);
light.position.set(0, 30, 30);
scene.add(light);
}
//初始化菜單面闆
function initDatGUI() {
//設定菜單中須要的參數
controls = new function () {
this.rotationSpeed = 0.02;
this.visible = meshMaterial.visible;//是不是可見
this.wireframe = meshMaterial.wireframe;//是不是以線框的體式格局襯着物體
this.wireframeWidth = meshMaterial.wireframeLinewidth;//線框的寬度
this.transparent = meshMaterial.transparent;//是不是通明
this.opacity = meshMaterial.opacity;//通明度,須要transparent為true才有結果
this.side = "front";//邊的襯着體式格局,有三種,前面,背面,另有雙面
this.selectMesh = "sphere";//目前挑選的幾何體
this.shading = "smooth";//着色體式格局,有平面着色戰争滑着色,對一個面很平的幾何體險些看不出區分,如正方體
};
let gui = new dat.GUI();
//将方才設定的參數增加到菜單中
let F1 = gui.addFolder("Mesh");
F1.add(controls, "rotationSpeed", 0, 0.1);
F1.add(controls, "visible").onChange(function (e) {
meshMaterial.visible = e;
});
F1.add(controls, "wireframe").onChange(function (e) {
meshMaterial.wireframe = e;
});
F1.add(controls, "wireframeWidth",0,10).onChange(function (e) {
meshMaterial.wireframeWidth = e;
});
F1.add(controls, "transparent").onChange(function (e) {
meshMaterial.transparent = e;
});
F1.add(controls, "opacity",0,1).onChange(function (e) {
meshMaterial.opacity = e;
});
F1.add(controls, "side",["front","back","double"]).onChange(function (e) {
switch (e) {
case "front":
meshMaterial.side = THREE.FrontSide;
break;
case "back":
meshMaterial.side = THREE.BackSide;
break;
case "double":
meshMaterial.side = THREE.DoubleSide;
break;
}
meshMaterial.needsUpdate = true;//要在遞次中讓材質更新須要增加這一句話
});
F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) {
//先把場景的物體消滅,再來增加
scene.remove(cube);
scene.remove(sphere);
scene.remove(plane);
switch (e) {
case "sphere":
scene.add(sphere);
break;
case "cube":
scene.add(cube);
break;
case "plane":
scene.add(plane);
break;
}
});
F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) {
switch (e) {
case "flat":
meshMaterial.shading = THREE.FlatShading;
break;
case "smooth":
meshMaterial.shading = THREE.SmoothShading;
break;
}
meshMaterial.needsUpdate = true;//要在遞次中讓材質更新須要增加這一句話
});
}
function initObject() {
//建立正方體,球和地面的幾何體
let cubeGeometry = new THREE.BoxGeometry(10, 10, 10);
let sphereGeometry = new THREE.SphereGeometry(10, 20, 20);
let planeGeometry = new THREE.PlaneGeometry(10, 10, 1, 1);
//建立一個法向量材質
meshMaterial = new THREE.MeshNormalMaterial();
cube = new THREE.Mesh(cubeGeometry, meshMaterial);
sphere = new THREE.Mesh(sphereGeometry, meshMaterial);
plane = new THREE.Mesh(planeGeometry, meshMaterial);
//把三者的位置一緻
cube.position.set(0,0,0);
sphere.position = cube.position;
plane.position = cube.position;
//在球的每一個面上顯現一個法向量,輕易觀察這類法向量材質的襯着體式格局
for(let i=0;i
let face = sphereGeometry.faces[i];//獲得每一個面的對象
let centroid = new THREE.Vector3();//先建立一個vector3對象,要運用這個對象找到每一個面的中間,
centroid.add(sphereGeometry.vertices[face.a]);
// 将這該面的三個極點的索引傳給sphereGeom.vertices找到其極點的坐标,再增加進centroid
centroid.add(sphereGeometry.vertices[face.b]);
centroid.add(sphereGeometry.vertices[face.c]);
centroid.divideScalar(3);//三角形的中間點坐标
let arrow = new THREE.ArrowHelper(
face.normal,
centroid,
2,
0xffcc55,
0.5,
0.5);//箭頭輔助線,相當于把法向量用箭頭示意出來
sphere.add(arrow);
}
scene.add(sphere);
}
function rotation() {
scene.traverse(function (e) {
if (e instanceof THREE.Mesh) {
e.rotation.y += controls.rotationSpeed;
}
})
}
//襯着函數
function render() {
rotation();
stats.update();
renderer.clear();
requestAnimationFrame(render);
renderer.render(scene, camera);
}
//功用函數
function setting() {
loadFullScreen();
loadAutoScreen(camera, renderer);
loadStats();
}
//運轉主函數,敲代碼的時刻總是敲錯,是以改了一個名字,叫Start更輕易
function Start() {
initThree();
initObject();
initDatGUI();
setting();
render();
}