Three.js的uv坐标贴图理解
·
前言
最近在做自定义几何体(平面)示例的时候,发现加上贴图后并没有得到想要的结果,代码是这样的:
//创建几何体
var geometry=new THREE.Geometry();
var vertices=[
new THREE.Vector3(0,0,0),
new THREE.Vector3(100,0,0),
new THREE.Vector3(100,100,0),
new THREE.Vector3(0,100,0),
];
var faces=[
new THREE.Face3(0, 1, 2),
new THREE.Face3(0, 2, 3)
];
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();//计算法向量 这决定了对光做出的反应
material = new THREE.MeshLambertMaterial({
map:new THREE.TextureLoader().load("./img/pic1.jpg"),
side: THREE.DoubleSide,
// color: "red",
opacity: 1,
depthWrite: false,
transparent: true // 定义此材质是否透明
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
理想的结果:
实际的结果:
然后想到了,自定义的geometry是不会自动设置UV坐标的,那如何给它设置合适的UV坐标呢。这需要对UV坐标有一定的了解。
UV坐标
可以将需要贴图的图片,给它设定一个坐标系作为图片的定位,该坐标系就是UV坐标了。在贴图时,可以根据图片的UV坐标,对应到Three.js的每个三角面进行贴图。
在Three.js中可以定义好uv坐标,与每个三角面一一对应。
代码如下:
//创建几何体
var geometry=new THREE.Geometry();
var vertices=[
new THREE.Vector3(0,0,0),
new THREE.Vector3(100,0,0),
new THREE.Vector3(100,100,0),
new THREE.Vector3(0,100,0),
];
var faces=[
new THREE.Face3(0, 1, 2),
new THREE.Face3(0, 2, 3)
];
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();//计算法向量 这决定了对光做出的反应
material = new THREE.MeshLambertMaterial({
map:new THREE.TextureLoader().load("./img/pic1.jpg"),
side: THREE.DoubleSide,
// color: "red",
opacity: 1,
depthWrite: false,
transparent: true // 定义此材质是否透明
});
//几何体UV坐标定义
var t0 = new THREE.Vector2(0, 0); //图片左下角
var t1 = new THREE.Vector2(1, 0); //图片右下角
var t2 = new THREE.Vector2(1, 1); //图片右上角
var t3 = new THREE.Vector2(0, 1); //图片左上角
var uv1 = [t0, t1, t2]; //选中图片一个三角区域像素——用于映射到一个三角面
var uv2 = [t0, t2, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
geometry.faceVertexUvs[0][0] = uv1;
geometry.faceVertexUvs[0][1] = uv2;
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
效果:
如果想要重复多次贴图或者只贴一部分,只需要设计好贴图的UV坐标既可以了,如下修改UV部分代码:
//几何体UV坐标定义
var t0 = new THREE.Vector2(0, 0); //图片左下角
var t1 = new THREE.Vector2(0.5, 0); //图片右下角
var t2 = new THREE.Vector2(0.5, 0.5); //图片右上角
var t3 = new THREE.Vector2(0, 0.5); //图片左上角
var uv1 = [t0, t1, t2]; //选中图片一个三角区域像素——用于映射到一个三角面
var uv2 = [t0, t2, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
geometry.faceVertexUvs[0][0] = uv1;
geometry.faceVertexUvs[0][1] = uv2;
效果:
实际上我们的几何体是有非常多的三角面组合而成的,为每个三角面设置好合适的uv坐标就可以实现多种多样的个性化贴图了。
完整示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>贴图与uv坐标</title>
<style>
body {
font-family: Monospace;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script type="text/javascript" src="../node_modules/three/build/three.js"></script>
<script type="text/javascript" src="../node_modules/three/examples/js/controls/OrbitControls.js"></script>
<script>
let camera, light, scene, renderer, mesh, material, raycaster, group, texture;
//初始化相机
function initCamera() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(400, 400, 400);
}
//初始化灯光
function initLight() {
light = new THREE.AmbientLight(0xffffff);
}
//初始化场景
function initScene() {
scene = new THREE.Scene();
//坐标辅助线
let helper = new THREE.AxisHelper(1000);
//网格辅助线
let gridHelper = new THREE.GridHelper(1000, 50);
scene.add(helper);
scene.add(light);
scene.add(gridHelper);
}
//初始化物体
function initMesh() {
//创建几何体
var geometry=new THREE.Geometry();
var vertices=[
new THREE.Vector3(0,0,0),
new THREE.Vector3(100,0,0),
new THREE.Vector3(100,100,0),
new THREE.Vector3(0,100,0),
];
var faces=[
new THREE.Face3(0, 1, 2),
new THREE.Face3(0, 2, 3)
];
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();//计算法向量 这决定了对光做出的反应
material = new THREE.MeshLambertMaterial({
map:new THREE.TextureLoader().load("./img/pic1.jpg"),
side: THREE.DoubleSide,
// color: "red",
opacity: 1,
depthWrite: false,
transparent: true // 定义此材质是否透明
});
//几何体UV坐标定义
var t0 = new THREE.Vector2(0, 0); //图片左下角
var t1 = new THREE.Vector2(0.5, 0); //图片右下角
var t2 = new THREE.Vector2(0.5, 0.5); //图片右上角
var t3 = new THREE.Vector2(0, 0.5); //图片左上角
var uv1 = [t0, t1, t2]; //选中图片一个三角区域像素——用于映射到一个三角面
var uv2 = [t0, t2, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
geometry.faceVertexUvs[0][0] = uv1;
geometry.faceVertexUvs[0][1] = uv2;
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
//初始化
function initRender() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xFFFFFF, 1.0);
document.body.appendChild(renderer.domElement);
//添加鼠标控制
let controls = new THREE.OrbitControls(camera, renderer.domElement);//创建控件对象
// controls.addEventListener('change', animate);//监听鼠标、键盘事件
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);
//围绕Y轴旋转
//group.rotateY(0.001 * Math.PI);
if (texture) {
// console.log("进来了");
texture.offset.y += 0.01;
}
}
function init() {
initCamera();
initLight();
initScene()
initMesh();
initRender()
animate();
}
init();
</script>
</body>
</html>
更多推荐
已为社区贡献2条内容
所有评论(0)