一、贴图
贴图(Texture Mapping),也翻译为纹理映射,“贴图”这个翻译更直观。
贴图,就是把图片贴在 3D 物体材质的表面,让它具有一定的纹理,来为 3D 物体添加细节的一种方法。这使我们能够添加表面细节,而无需将这些细节建模到我们的3D对象中,从而大大精简3D模型的多边形边数,提高模型渲染性能。
二、准备基础代码
在场景里创建一个立方体。
为了方便观察效果,还添加了网格辅助和轨道控制器。
HTML:
<script type="importmap">
{
"imports":{
"three":"./js/three.module.min.js",
"addons/":"./js/jsm/"
}
}
</script>
<script type="module" src="js/myjs.js"></script>
JS:
import * as THREE from "three";
import { OrbitControls } from "addons/controls/OrbitControls.js";
let winH = window.innerHeight;
let winW = window.innerWidth;
// 场景
const scene = new THREE.Scene();
scene.background = new THREE.Color("#cccccc");
// 物体
const geometry = new THREE.BoxGeometry(1,1,1);
const material = new THREE.MeshBasicMaterial({
color:"#ff3300"
});
const box = new THREE.Mesh( geometry, material );
box.position.set(0,0,0);
scene.add( box );
// grid
const gridHelper = new THREE.GridHelper(10,10);
scene.add( gridHelper);
// 相机
const camera = new THREE.PerspectiveCamera(50, winW/winH, 1, 1000);
camera.position.set(0,5,5);
camera.lookAt(scene.position);
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize( winW, winH );
document.body.appendChild( renderer.domElement );
renderer.render( scene, camera );
// 轨道控制器
const controls = new OrbitControls( camera, renderer.domElement );
controls.update();
// 动画
function animateFun(){
controls.update(); // 现在动画里更新控制器
// 渲染
renderer.render( scene, camera);
requestAnimationFrame(animateFun);
}
animateFun();
三、纹理贴图示例
纹理贴图用到的是基础材质 THREE.MeshBasicMaterial
和 THREE.TextureLoader
。
-
THREE.MeshBasicMaterial
:基础材质是不受光照影响,可以直接给物体设置颜色,也可以将图片贴到物体表面。 -
THREE.TextureLoader
:纹理加载器。纹理贴图加载器TextureLoader
的load()
方法加载一张图片可以返回一个纹理对象Texture
,纹理对象Texture
可以作为模型材质贴图.map
属性的值。
修订代码,为立方体的材质(meterial)添加纹理贴图。
const texture = new THREE.TextureLoader().load("../images/woods2.jpg");
const material = new THREE.MeshBasicMaterial({
map:texture
});
这里用的纹理图是:
效果:
四、透明贴图示例
如果贴图要透明,可以设置材质的透明属性 transparent:true;
。
同时,要准备好 alpha 图片,做 alpha贴图的纹理。
alpha 图片,其实就是一个黑白图,跟 PS 蒙版是一个道理:黑色不可见,白色可见,灰色代表半透明。
这里使用两张素材如下:
修改 meterial 代码如下:(两张纹理图,都要加载进去)。
const texture = new THREE.TextureLoader().load("../images/head1.jpg");
const textureAlpha = new THREE.TextureLoader().load("../images/head2.jpg");
const material = new THREE.MeshBasicMaterial({
map:texture, // 纹理贴图
alphaMap:textureAlpha, // alpha 贴图
transparent:true // 开启透明属性
});
为什么立方体只有一半?
这是因为,纹理渲染面属性值 side 有四个值 :
-
THREE.FrontSide:默认。只渲染前面。
-
THREE.BackSide:只渲染后面
-
THREE.DoubleSide:前后面都渲染。
-
THREE.TwoPassDoubleSide:将按前后顺序分两次渲染双面透明材料,以减轻透明伪影。
默认 meterial 的“平面”是只渲染前面,因此立方体转向后,背面的图是看不到的。把 side 属性改为 THREE.DoubleSide 即可。
const material = new THREE.MeshBasicMaterial({
map:texture,
transparent:true,
alphaMap:textureAlpha,
side: THREE.DoubleSide // 前后面都渲染。
});
五、环境贴图示例
环境贴图(environment mapping),顾名思义,就是给材质贴上环境的画面。
这个主要让材质反映出周围的画面。比如,在一个草地上,让一个立方体映出草地周围的画面。
1. 给场景添加立方纹理
修改前面的基础结构代码给场景添加立方纹理,把场景设置为一个公园。
// 场景
const scene = new THREE.Scene();
// 给场景添加立方纹理
const cubeTexture = new THREE.CubeTextureLoader().setPath("../texture3/").load([
"posx.jpg","negx.jpg",
"posy.jpg","negy.jpg",
"posz.jpg","negz.jpg"
]);
scene.background = cubeTexture;
这里公园用的素材是官方案例 \examples\textures\cube\Park2
里面的素材。
2. 给材质添加环境贴图
const material = new THREE.MeshBasicMaterial({
envMap: cubeTexture // 给材质应用环境贴图:此时的环境的贴图就是立方纹理,所以就使用立方纹理。
});
也可以同时使用纹理贴图和环境贴图。
const material = new THREE.MeshBasicMaterial({
map:texture,
envMap: cubeTexture
});