本例來源于官方案例
效果圖
立方體貼圖

全景貼圖
總體步驟
① 建立場景和相機
②建立物體
③ 建立渲染器
④建立GUI
html代碼
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body{
padding: 0;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container">
</div>
<script type="module">
</script>
</body>
</html>
導入檔案,建立全局變量和函數
import * as THREE from "./js/three.module.js";
import {OrbitControls} from "./js/OrbitControls.js";
import { GUI } from './js/dat.gui.module.js';
import Stats from './js/stats.module.js';
let renderer,scene,camera,spotLight,status,cameraCube,sceneCube,cubeMesh,SphereMaterial;
action();
function action() {
onload();
run();
}
function onload(){
}
function run()
{
}
function onResize()
{
}
①建立場景和相機
onload函數中
let container=document.getElementById("container");//擷取container
scene=new THREE.Scene();//建立場景(主)
camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,10000);
camera.position.set(0, 0, 1000);//建立相機并設定位置
sceneCube = new THREE.Scene();//建立立方體場景(副)
cameraCube=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,10000);
②建立物體
onload函數中
let ambientLight=new THREE.AmbientLight();//添加環境光
scene.add(ambientLight);
spotLight=new THREE.SpotLight(0xffffff);//添加點光源
spotLight.position.set(-600, 300,300);
spotLight.intensity=3;
scene.add(spotLight);
let spotLightMesh=new THREE.Mesh(new THREE.SphereGeometry(15,20,20),new THREE.MeshBasicMaterial());
spotLight.add(spotLightMesh);
let gridHelper=new THREE.GridHelper(30,20);
scene.add(gridHelper);
//立方體貼圖
let textureCube=new THREE.CubeTextureLoader().setPath("img/").load(["posx.jpg", "negx.jpg","posy.jpg","negy.jpg","posz.jpg","negz.jpg"]);
textureCube.encoding=THREE.sRGBEncoding;//在導入材質時,會預設将貼圖編碼格式定義為Three.LinearEncoding,故需将帶顔色資訊的貼圖(baseColorTexture, emissiveTexture, 和 specularGlossinessTexture)手動指定為Three.sRGBEncoding
textureCube.mapping=THREE.CubeReflectionMapping;//立方體反映射①
textureCube.format=THREE.RGBFormat;//預設THREE.RGBAFormat,對于JPG會自動設定為THREE.RGBFormat ②
// console.log(textureCube);
let SphereGeometry=new THREE.SphereBufferGeometry(300.0, 48, 24);
SphereMaterial=new THREE.MeshLambertMaterial({envMap:textureCube});
let SphereMesh=new THREE.Mesh(SphereGeometry,SphereMaterial);
scene.add(SphereMesh);
let cubeShader=THREE.ShaderLib["cube"];
console.log(THREE.ShaderLib);
let cubeMaterial=new THREE.ShaderMaterial({
fragmentShader:cubeShader.fragmentShader,
vertexShader:cubeShader.vertexShader,
uniforms:cubeShader.uniforms,
depthWrite:false,
side: THREE.BackSide
});
cubeMaterial.uniforms["tCube"].value=textureCube;
console.log(cubeMaterial);
//全景貼圖
let panorama=new THREE.TextureLoader().load("./img/2294472375_24a3b8ef46_o.jpg");
panorama.mapping = THREE.EquirectangularReflectionMapping;
panorama.magFilter = THREE.LinearFilter;//③
panorama.minFilter = THREE.LinearMipmapLinearFilter;//④
panorama.encoding = THREE.sRGBEncoding;
let panoramaShader=THREE.ShaderLib["equirect"];
let panoramaMaterial=new THREE.ShaderMaterial({
fragmentShader:panoramaShader.fragmentShader,
vertexShader: panoramaShader.vertexShader,
uniforms:panoramaShader.uniforms,
depthWrite: false,
side: THREE.BackSide
});
panoramaMaterial.uniforms["tEquirect"].value=panorama;
cubeMesh=new THREE.Mesh(new THREE.BoxBufferGeometry( 10, 100, 100 ),cubeMaterial);
sceneCube.add(cubeMesh);
解釋
①:textureCube.mapping:就是UV貼圖的類型,它的取值如下
THREE.CubeReflectionMapping:立方體反射映射
THREE.CubeRefractionMapping:立方體折射映射
THREE.EquirectangularReflectionMapping:圓柱反射映射
THREE.EquirectangularRefractionMapping:圓柱折射映射
THREE.SphericalReflectionMapping:球面反t射映射
② :textureCube.format
預設紋理格式為THREE.RGBAFormat。其他格式有:
THREE.AlphaFormat:對應于GL_ALPHA。Alpha 值
THREE.RGBFormat:Red, Green, Blue 三原色值
THREE.RGBAFormat:Red, Green, Blue 和 Alpha 值
THREE.LuminanceFormat:灰階值
THREE.LuminanceAlphaFormat:灰階值和 Alpha 值
THREE.RGBEFormat
③ panorama.magFilter
該屬性定義當一個紋理單元(texel)覆寫多個像素點時紋理如何采樣。預設為 THREE.LinearFilter,表示擷取4個最近的紋理單元執行雙向線性插值計算(顯示效果好)。另外的選項是 THREE.NearestFilter, 表示使用最近的texel(性能優)
④:panorama.minFilter
該屬性定義當一個紋理單元(texel)不足以覆寫單個像素點時紋理如何采樣。預設為 THREE.LinearMipMapLinearFilter, 表示使用多級紋理貼圖(mipmapping)以及一個三線性濾波器。
其他選項是:
THREE.NearestFilter:最近濾鏡。在紋理基層上執行最鄰近過濾。
THREE.NearestMipMapNearestFilter:選擇最臨近的mip層,并執行最臨近的過濾。
THREE.NearestMipMapLinearFilter:在mip層之間執行線性插補,并執行最臨近的過濾。
THREE.LinearFilter:在紋理基層上執行線性過濾。
THREE.LinearMipMapNearestFilter:選擇最臨近的mip層,并執行線性過濾。
THREE.LinearMipMapLinearFilter:在mip層之間執行線性插補,并執行線性過濾。
參考部落格 Three.js Texture紋理屬性詳解
THREE.ShaderMaterial 參考部落格Three.js進階材質THREE.ShaderMaterial
③建立渲染器
onload函數中
renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.autoClear=false;
renderer.gammaInput=true;
renderer.gammaOutput=true;//inear轉gamma
renderer.setSize(window.innerWidth,window.innerHeight);
container.appendChild(renderer.domElement);
status=new Stats();//建立頻率顯示
container.appendChild(status.dom);//頻率挂到左上角
let contorl=new OrbitControls(camera,renderer.domElement);//添加滑鼠滾動縮放,旋轉對象
window.addEventListener('resize',onResize,false);//浏覽器大小改變監聽
onResize函數中
function onResize() {
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
cameraCube.aspect = window.innerWidth / window.innerHeight;
cameraCube.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
}
run函數中
function run() {
requestAnimationFrame(run);
camera.lookAt(scene.position);
cameraCube.rotation.copy(camera.rotation);//指派相機的位置
renderer.render(sceneCube,cameraCube);
renderer.render(scene,camera);
status.update();
}
④建立GUI
onload函數中
let guiControls=new function(){
this.Cube=function () {
cubeMesh.material = cubeMaterial;
cubeMesh.visible = true;
SphereMaterial.envMap = textureCube;
SphereMaterial.needsUpdate = true;
};
this.Equirectangular=function () {
cubeMesh.material = panoramaMaterial;
cubeMesh.visible = true;
SphereMaterial.envMap=panorama;
SphereMaterial.needsUpdate = true;
}
};
let gui=new GUI();//建立gui
gui.add(guiControls,'Cube');
gui.add(guiControls,'Equirectangular');
總代碼
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body{
padding: 0;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container">
</div>
<script type="module">
import * as THREE from "./js/three.module.js";
import {OrbitControls} from "./js/OrbitControls.js";
import { GUI } from './js/dat.gui.module.js';
import Stats from './js/stats.module.js';
let renderer,scene,camera,spotLight,status,cameraCube,sceneCube,cubeMesh,SphereMaterial;
action();
function action() {
onload();
run();
}
function onload() {
let container=document.getElementById("container");//擷取container
scene=new THREE.Scene();//建立場景
camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,10000);
camera.position.set(0, 0, 1000);//建立相機并設定位置
sceneCube = new THREE.Scene();
cameraCube=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,10000);
let ambientLight=new THREE.AmbientLight();//添加環境光
scene.add(ambientLight);
spotLight=new THREE.SpotLight(0xffffff);//添加點光源
spotLight.position.set(-600, 300,300);
spotLight.intensity=3;
scene.add(spotLight);
let spotLightMesh=new THREE.Mesh(new THREE.SphereGeometry(15,20,20),new THREE.MeshBasicMaterial());
spotLight.add(spotLightMesh);
let gridHelper=new THREE.GridHelper(30,20);
scene.add(gridHelper);
//立方體貼圖
let textureCube=new THREE.CubeTextureLoader().setPath("img/").load(["posx.jpg", "negx.jpg","posy.jpg","negy.jpg","posz.jpg","negz.jpg"]);
textureCube.encoding=THREE.sRGBEncoding;//在導入材質時,會預設将貼圖編碼格式定義為Three.LinearEncoding,故需将帶顔色資訊的貼圖(baseColorTexture, emissiveTexture, 和 specularGlossinessTexture)手動指定為Three.sRGBEncoding
textureCube.mapping=THREE.CubeReflectionMapping;//立方體反映射
textureCube.format=THREE.RGBFormat;//預設THREE.RGBAFormat,對于JPG會自動設定為THREE.RGBFormat
console.log(textureCube);
let SphereGeometry=new THREE.SphereBufferGeometry(300.0, 48, 24);
SphereMaterial=new THREE.MeshLambertMaterial({envMap:textureCube});
let SphereMesh=new THREE.Mesh(SphereGeometry,SphereMaterial);
scene.add(SphereMesh);
let cubeShader=THREE.ShaderLib["cube"];
console.log(THREE.ShaderLib);
let cubeMaterial=new THREE.ShaderMaterial({
fragmentShader:cubeShader.fragmentShader,
vertexShader:cubeShader.vertexShader,
uniforms:cubeShader.uniforms,
depthWrite:false,
side: THREE.BackSide
});
cubeMaterial.uniforms["tCube"].value=textureCube;
console.log(cubeMaterial);
//全景貼圖
let panorama=new THREE.TextureLoader().load("./img/2294472375_24a3b8ef46_o.jpg");
panorama.mapping = THREE.EquirectangularReflectionMapping;
panorama.magFilter = THREE.LinearFilter;
panorama.minFilter = THREE.LinearMipmapLinearFilter;
panorama.encoding = THREE.sRGBEncoding;
let panoramaShader=THREE.ShaderLib["equirect"];
let panoramaMaterial=new THREE.ShaderMaterial({
fragmentShader:panoramaShader.fragmentShader,
vertexShader: panoramaShader.vertexShader,
uniforms:panoramaShader.uniforms,
depthWrite: false,
side: THREE.BackSide
});
panoramaMaterial.uniforms["tEquirect"].value=panorama;
cubeMesh=new THREE.Mesh(new THREE.BoxBufferGeometry( 10, 100, 100 ),cubeMaterial);
sceneCube.add(cubeMesh);
renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.autoClear=false;
renderer.gammaInput=true;
renderer.gammaOutput=true;//inear轉gamma
renderer.setSize(window.innerWidth,window.innerHeight);
container.appendChild(renderer.domElement);
let guiControls=new function(){
this.Cube=function () {
cubeMesh.material = cubeMaterial;
cubeMesh.visible = true;
SphereMaterial.envMap = textureCube;
SphereMaterial.needsUpdate = true;
};
this.Equirectangular=function () {
cubeMesh.material = panoramaMaterial;
cubeMesh.visible = true;
SphereMaterial.envMap=panorama;
SphereMaterial.needsUpdate = true;
}
};
let gui=new GUI();//建立gui
gui.add(guiControls,'Cube');
gui.add(guiControls,'Equirectangular');
status=new Stats();//建立頻率顯示
container.appendChild(status.dom);//頻率挂到左上角
let contorl=new OrbitControls(camera,renderer.domElement);//添加滑鼠滾動縮放,旋轉對象
window.addEventListener('resize',onResize,false);//浏覽器大小改變監聽
}
function onResize() {
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
cameraCube.aspect = window.innerWidth / window.innerHeight;
cameraCube.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
}
function run() {
requestAnimationFrame(run);
camera.lookAt(scene.position);
cameraCube.rotation.copy(camera.rotation);//指派相機的位置
renderer.render(sceneCube,cameraCube);
renderer.render(scene,camera);
status.update();
}
</script>
</body>
</html>