![]()
16. 高级纹理技术
1. 概述
高级纹理技术包括压缩纹理、Mipmap、纹理数组、渲染到纹理等,用于优化性能和实现复杂视觉效果。
┌─────────────────────────────────────────────────────────────┐ │ 高级纹理技术体系 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 纹理压缩 │ │ ├── BasisTexture:通用压缩格式 │ │ ├── KTX2:Khronos 纹理格式 │ │ └── DDS:DirectDraw Surface │ │ │ │ Mipmap │ │ ├── 自动生成 │ │ ├── 手动生成 │ │ └── 自定义 Mipmap │ │ │ │ 渲染到纹理 │ │ ├── WebGLRenderTarget │ │ ├── 实时反射 │ │ └── 后期效果 │ │ │ └─────────────────────────────────────────────────────────────┘
2. 压缩纹理
2.1 BasisTexture
npminstallthree/examples/jsm/libs/basis
import{BasisTextureLoader}from'three/examples/jsm/loaders/BasisTextureLoader.js';constbasisLoader=newBasisTextureLoader();basisLoader.setTranscoderPath('three/examples/jsm/libs/basis/');basisLoader.load('texture.basis',(texture)=>{constmaterial=newTHREE.MeshStandardMaterial({map:texture});});
2.2 KTX2 纹理
import{KTX2Loader}from'three/examples/jsm/loaders/KTX2Loader.js';constktx2Loader=newKTX2Loader();ktx2Loader.setTranscoderPath('three/examples/jsm/libs/basis/');ktx2Loader.load('texture.ktx2',(texture)=>{constmaterial=newTHREE.MeshStandardMaterial({map:texture});});
2.3 DDS 纹理
import{DDSLoader}from'three/examples/jsm/loaders/DDSLoader.js';constddsLoader=newDDSLoader();ddsLoader.load('texture.dds',(texture)=>{constmaterial=newTHREE.MeshStandardMaterial({map:texture});});
3. Mipmap
3.1 自动生成 Mipmap
consttexture=textureLoader.load('texture.jpg');texture.generateMipmaps=true;texture.minFilter=THREE.LinearMipmapLinearFilter;
3.2 手动生成 Mipmap
constcanvas=document.createElement('canvas');canvas.width=512;canvas.height=512;constctx=canvas.getContext('2d');// 绘制各级 Mipmapconstmipmaps=[];letsize=512;while(size>=1){constmipCanvas=document.createElement('canvas');mipCanvas.width=size;mipCanvas.height=size;constmipCtx=mipCanvas.getContext('2d');mipCtx.drawImage(canvas,0,0,size,size);mipmaps.push({data:mipCtx.getImageData(0,0,size,size).data,width:size,height:size});size/=2;}consttexture=newTHREE.DataTexture(mipmaps[0].data,512,512);texture.mipmaps=mipmaps;texture.minFilter=THREE.LinearMipmapLinearFilter;
4. 渲染到纹理(Render Target)
4.1 WebGLRenderTarget
// 创建渲染目标constrenderTarget=newTHREE.WebGLRenderTarget(512,512,{minFilter:THREE.LinearFilter,magFilter:THREE.LinearFilter,format:THREE.RGBAFormat});// 创建场景和相机用于渲染到纹理constrtScene=newTHREE.Scene();constrtCamera=newTHREE.PerspectiveCamera(45,1,0.1,1000);// 渲染到纹理renderer.setRenderTarget(renderTarget);renderer.render(rtScene,rtCamera);renderer.setRenderTarget(null);// 使用渲染结果作为纹理constmaterial=newTHREE.MeshStandardMaterial({map:renderTarget.texture});
4.2 实时反射纹理
// 创建 CubeCamera 用于实时反射constcubeRenderTarget=newTHREE.WebGLCubeRenderTarget(256);constcubeCamera=newTHREE.CubeCamera(0.1,1000,cubeRenderTarget);// 更新反射functionupdateReflection(){sphere.visible=false;cubeCamera.update(renderer,scene);sphere.visible=true;constenvMap=cubeRenderTarget.texture;reflectiveMaterial.envMap=envMap;}
5. 纹理数组
// 创建纹理数组consttextures=[textureLoader.load('texture1.jpg'),textureLoader.load('texture2.jpg'),textureLoader.load('texture3.jpg')];// 纹理数组材质constmaterial=newTHREE.MeshStandardMaterial({map:textures[0]});// 切换纹理letcurrentIndex=0;functionswitchTexture(){currentIndex=(currentIndex+1)%textures.length;material.map=textures[currentIndex];material.needsUpdate=true;}
6. 纹理动画
// 纹理偏移动画consttexture=textureLoader.load('water.jpg');texture.wrapS=THREE.RepeatWrapping;texture.wrapT=THREE.RepeatWrapping;texture.repeat.set(4,4);letoffset=0;functionanimateTexture(){offset+=0.01;texture.offset.set(offset,offset);requestAnimationFrame(animateTexture);}animateTexture();
7. 完整示例
import*asTHREEfrom'three';import{OrbitControls}from'three/examples/jsm/controls/OrbitControls.js';constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x111122);constcamera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(5,4,8);camera.lookAt(0,0,0);constrenderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);constcontrols=newOrbitControls(camera,renderer.domElement);controls.enableDamping=true;// 光源constambientLight=newTHREE.AmbientLight(0x404040,0.4);scene.add(ambientLight);constdirectionalLight=newTHREE.DirectionalLight(0xffffff,1);directionalLight.position.set(5,10,7);directionalLight.castShadow=true;scene.add(directionalLight);// 辅助对象constaxesHelper=newTHREE.AxesHelper(5);scene.add(axesHelper);constgridHelper=newTHREE.GridHelper(10,20);scene.add(gridHelper);// 创建动态纹理(CanvasTexture)constcanvas=document.createElement('canvas');canvas.width=512;canvas.height=512;constctx=canvas.getContext('2d');functiondrawTexture(){consttime=Date.now()*0.001;ctx.fillStyle='#112233';ctx.fillRect(0,0,canvas.width,canvas.height);for(leti=0;i<50;i++){constx=canvas.width/2+Math.sin(time+i)*200;consty=canvas.height/2+Math.cos(time*1.3+i)*200;consthue=(time*50+i*36)%360;ctx.fillStyle=`hsl(${hue}, 100%, 60%)`;ctx.beginPath();ctx.arc(x,y,10,0,Math.PI*2);ctx.fill();}dynamicTexture.needsUpdate=true;requestAnimationFrame(drawTexture);}constdynamicTexture=newTHREE.CanvasTexture(canvas);drawTexture();// 立方体constgeometry=newTHREE.BoxGeometry(2,2,2);constmaterial=newTHREE.MeshStandardMaterial({map:dynamicTexture,metalness:0.5,roughness:0.3});constcube=newTHREE.Mesh(geometry,material);cube.castShadow=true;cube.receiveShadow=true;scene.add(cube);// 创建渲染到纹理的目标constrenderTarget=newTHREE.WebGLRenderTarget(512,512,{minFilter:THREE.LinearFilter,magFilter:THREE.LinearFilter});// 辅助场景(用于渲染到纹理)constrtScene=newTHREE.Scene();rtScene.background=newTHREE.Color(0xff6600);constrtGeometry=newTHREE.SphereGeometry(0.8,32,32);constrtMaterial=newTHREE.MeshStandardMaterial({color:0xff6600,metalness:0.5});constrtSphere=newTHREE.Mesh(rtGeometry,rtMaterial);rtScene.add(rtSphere);constrtCamera=newTHREE.PerspectiveCamera(45,1,0.1,10);rtCamera.position.set(2,2,3);rtCamera.lookAt(0,0,0);constrtLight=newTHREE.DirectionalLight(0xffffff,1);rtLight.position.set(2,3,4);rtScene.add(rtLight);// 更新渲染到纹理functionupdateRenderTarget(){rtSphere.rotation.y+=0.02;renderer.setRenderTarget(renderTarget);renderer.render(rtScene,rtCamera);renderer.setRenderTarget(null);// 应用到另一个物体if(rtMaterial2)rtMaterial2.map=renderTarget.texture;requestAnimationFrame(updateRenderTarget);}// 第二个立方体,使用渲染目标纹理constrtGeometry2=newTHREE.BoxGeometry(1.5,1.5,1.5);constrtMaterial2=newTHREE.MeshStandardMaterial({map:renderTarget.texture});constrtCube=newTHREE.Mesh(rtGeometry2,rtMaterial2);rtCube.position.set(2.5,0.5,1.5);rtCube.castShadow=true;scene.add(rtCube);updateRenderTarget();// 平面constplaneGeometry=newTHREE.PlaneGeometry(8,8);constplaneMaterial=newTHREE.MeshStandardMaterial({color:0x336699,side:THREE.DoubleSide});constplane=newTHREE.Mesh(planeGeometry,planeMaterial);plane.rotation.x=-Math.PI/2;plane.position.y=-1.5;plane.receiveShadow=true;scene.add(plane);// GUI 控制importGUIfrom'lil-gui';constgui=newGUI();consttextureFolder=gui.addFolder('纹理控制');textureFolder.add(material,'metalness',0,1).name('金属度');textureFolder.add(material,'roughness',0,1).name('粗糙度');textureFolder.add(dynamicTexture,'wrapS',{ClampToEdgeWrapping:THREE.ClampToEdgeWrapping,RepeatWrapping:THREE.RepeatWrapping}).name('包裹模式').onChange(()=>dynamicTexture.needsUpdate=true);textureFolder.add(dynamicTexture.repeat,'x',0.1,4).name('重复X').onChange(()=>dynamicTexture.needsUpdate=true);textureFolder.add(dynamicTexture.repeat,'y',0.1,4).name('重复Y').onChange(()=>dynamicTexture.needsUpdate=true);textureFolder.open();// 动画functionanimate(){requestAnimationFrame(animate);cube.rotation.x+=0.005;cube.rotation.y+=0.01;controls.update();renderer.render(scene,camera);}animate();window.addEventListener('resize',onWindowResize,false);functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}
8. 总结
| 技术 | 类/方法 | 用途 |
|---|
| 压缩纹理 | BasisTextureLoader, KTX2Loader | 减少内存和带宽 |
| Mipmap | generateMipmaps | 提高远处纹理质量 |
| 渲染到纹理 | WebGLRenderTarget | 动态纹理、后期效果 |
| CubeCamera | CubeCamera | 实时环境贴图 |
| 纹理数组 | 多个 Texture | 纹理切换 |
| 纹理动画 | offset, rotation | 动态效果 |
| 纹理属性 | 说明 |
|---|
generateMipmaps | 是否生成 Mipmap |
minFilter | 缩小过滤 |
magFilter | 放大过滤 |
needsUpdate | 需要更新 |
mipmaps | 自定义 Mipmap 数组 |