31 - three.js 笔记 - MeshNormalMaterial 材质
程序员文章站
2022-06-11 11:37:53
...
MeshNormalMaterial
是一种将法向量映射到 RGB 颜色的材质。
网格在每一个面上渲染的颜色都不一样,法向量是与面垂直的向量,由于一个物体各个面上的法向量都不同,所以每个面映射的颜色也不同。
示例:MeshNormalMaterial.html
示例中将flatShading
设置为true
为了更好看到每个面的颜色。
并且为每个面都添加了一个辅助箭头,可以清晰看到每个面的法向量的位置。
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeshNormalMaterial 计算法向颜色的材质</title>
<style>
body {
margin: 0;
overflow: hidden; /*溢出隐藏*/
}
</style>
<script src="../../libs/build/three-r93.min.js"></script>
<script src="../../libs/examples/js/controls/OrbitControls.js"></script>
<script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
<script src="../../libs/examples/js/libs/stats.min.js"></script>
<script src="../../libs/examples/js/Detector.js"></script>
</head>
<body>
<script>
let stats = initStats();
let scene, camera, renderer, controls, guiControls;
// 场景
function initScene() {
scene = new THREE.Scene();
}
// 相机
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 5000);
camera.position.set(0, 0, 250);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
// 渲染器
function initRenderer() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x050505);
document.body.appendChild(renderer.domElement);
}
// 灯光
function initLight() {
let spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-10, 200, 30);
scene.add(spotLight);
}
// 控制器
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);
// 添加惯性
controls.enableDamping = true;
// 最大偏移角度
controls.maxPolarAngle = 0.49 * Math.PI;
// 旋转速度
controls.rotateSpeed = 0.05;
// 最大可视距离
controls.maxDistance = 500;
// 最小可视距离
controls.minDistance = 100;
}
// 调试插件
let flag = false;
function initGui() {
guiControls = new function () {
this.opacity = normalMaterial.opacity;
this.transparent = normalMaterial.transparent;
this.wireframe = normalMaterial.wireframe;
this.flatShading = normalMaterial.flatShading;
this.side = 'front';
this.arrow = false;
};
let gui = new dat.GUI();
gui.add(guiControls, 'opacity',0, 1).onChange(function (e) {
normalMaterial.opacity = e;
});
gui.add(guiControls, 'transparent').onChange(function (e) {
normalMaterial.transparent = e;
});
gui.add(guiControls, 'wireframe').onChange(function (e) {
normalMaterial.wireframe = e;
});
gui.add(guiControls, 'flatShading').onChange(function (e) {
normalMaterial.flatShading = e;
console.log(normalMaterial.flatShading);
// 材质flatShading被修改时需要重新编译材质
normalMaterial.needsUpdate = true;
});
gui.add(guiControls, 'arrow').onChange(function (e) {
if (e){
for (let f = 0, fl = sphere.geometry.faces.length; f < fl; f++){
let face = sphere.geometry.faces[f];
let centroid = new THREE.Vector3(0, 0, 0);
centroid.add(sphere.geometry.vertices[face.a]);
centroid.add(sphere.geometry.vertices[face.b]);
centroid.add(sphere.geometry.vertices[face.c]);
centroid.divideScalar(3);
let arrow = new THREE.ArrowHelper(face.normal,centroid, 10, 0x33ffff, 10, 0.1);
sphere.add(arrow);
}
}else{
scene.remove(sphere);
initContent();
}
});
gui.add(guiControls,'side',['front','back','double']).onChange(function (e) {
switch (e){
case "front":
normalMaterial.side = THREE.FrontSide;
break;
case "back":
normalMaterial.side = THREE.BackSide;
break;
case "double":
normalMaterial.side = THREE.DoubleSide;
break;
}
normalMaterial.needsUpdate = true;
});
}
let sphere;
let normalMaterial;
// 场景中的内容
function initContent() {
let sphereGeometry = new THREE.SphereGeometry(80, 35, 35);
normalMaterial = new THREE.MeshNormalMaterial();
normalMaterial.flatShading = true;
sphere = new THREE.Mesh(sphereGeometry, normalMaterial);
scene.add(sphere);
}
// 性能插件
function initStats() {
let stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);
return stats;
}
// 更新
function update() {
stats.update();
controls.update();
sphere.rotation.y -= 0.01;
}
// 初始化
function init() {
// 兼容性判断,若不兼容会提示信息
if (!Detector.webgl) Detector.addGetWebGLMessage();
initScene();
initCamera();
initRenderer();
initLight();
initControls();
initContent();
initGui();
window.addEventListener('resize', onWindowResize, false);
}
// 窗口变动触发的方法
function onWindowResize() {
// 重新设置相机的宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相机投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);
}
// 循环渲染
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
update();
}
// 页面绘制完后加载
window.onload = function () {
init();
animate();
};
</script>
</body>
</html>
上一篇: PHP实现的sqlite数据库连接类