I use textures to illuminate the entire scene and model.
Now there is a question, how to make a part of the model (with white text) produce a halo effect similar to a light?
If possible, how many methods can we achieve it?
I really hope for your help, thank you!
This is the code.
<template>
<div ref="container"></div>
</template>
<script setup>
import {ref, onMounted} from "vue";
import * as THREE from "three";
// GLTF加载器
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";
// 解压器
import {DRACOLoader} from "three/examples/jsm/loaders/DRACOLoader";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls.js";
import {HDRJPGLoader} from "@monogrid/gainmap-js";
import {RoomEnvironment} from 'three/examples/jsm/environments/RoomEnvironment.js';
import {GUI} from "three/examples/jsm/libs/lil-gui.module.min.js";
import Stats from "three/examples/jsm/libs/stats.module.js";
const container = ref(null);
let // 场景 相机 渲染 轨道控制器 glb文件内容
scene, camera, renderer, control, content, cube;
let gui, stats;
let hdrJpgEquirectangularMap;
const params = {
exposure: 2.0,
cameraX: 7.4,
cameraY: 12.5,
cameraZ: 60,
targetX: 6.45,
targetY: 12.8,
targetZ: 2.56,
};
// 挂载
onMounted(() => {
// 初始化
init();
// 渲染
render();
// 监听窗口变化
window.addEventListener("resize", () => {
// 重置渲染器宽高比
renderer.setSize(window.innerWidth, window.innerHeight);
// 重置相机宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相机投影矩阵
camera.updateProjectionMatrix();
});
});
function initScene() {
scene = new THREE.Scene();
}
function initCamera() {
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000,
);
camera.position.set(params.cameraX, params.cameraY, params.cameraZ)
camera.updateProjectionMatrix();
}
function initRenderer() {
// 创建渲染器 antialias 抗锯齿
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.toneMapping = THREE.ACESFilmicToneMapping;
// 尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置像素比
renderer.setPixelRatio(window.devicePixelRatio);
container.value.appendChild(renderer.domElement);
}
function initControl() {
control = new OrbitControls(camera, renderer.domElement);
control.target.set(params.targetX, params.targetY, params.targetZ);
control.update();
}
// 加载模型
function loadModel() {
// 解压器(用于解压经过压缩过的glb文件)
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('./draco/');
// 加载器
new GLTFLoader().setDRACOLoader(dracoLoader).load("characters.glb", (glb) => {
// glb文件场景
const _scene = glb.scene || glb.scenes[0];
if (!_scene) {
// Valid, but not supported by this viewer.
throw new Error(
'This model contains no scene, and cannot be viewed here. However, it may contain individual 3D resources.',
);
}
// glb文件内容
content = _scene;
// 文件场景添加到当前场景中
scene.add(content);
},
function (xhr) {
// 加载进度
// console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
},
function (error) {
console.log("An error happened:", error);
}
);
};
// 加载贴图
function loadTexture() {
new HDRJPGLoader(renderer).load("textures/sun_gain_map.jpg", (texture) => {
hdrJpgEquirectangularMap = texture.renderTarget.texture;
hdrJpgEquirectangularMap.mapping = THREE.EquirectangularReflectionMapping;
hdrJpgEquirectangularMap.needsUpdate = true;
// 环境背景
scene.environment = hdrJpgEquirectangularMap;
scene.background = hdrJpgEquirectangularMap;
// 曝光度
renderer.toneMappingExposure = params.exposure;
},
function (progress) {
// console.log("Progress", ((progress.loaded / progress.total) * 100).toFixed(2));
},
);
}
function initStats() {
stats = new Stats();
container.value.appendChild(stats.dom);
}
function initGui() {
gui = new GUI();
gui.add(params, "exposure", 0, 15, 0.01).name("曝光度").onFinishChange((value) => {
// 曝光度
renderer.toneMappingExposure = value;
});
// region camera
const cameraPosition = gui.addFolder('camera position');
cameraPosition.add(params, 'cameraX', -300, 300, 2).onFinishChange((value) => {
camera.position.x = value;
camera.updateProjectionMatrix();
});
cameraPosition.add(params, 'cameraY', -300, 300, 2).onFinishChange((value) => {
camera.position.y = value;
camera.updateProjectionMatrix();
});
cameraPosition.add(params, 'cameraZ', -300, 300, 2).onFinishChange((value) => {
camera.position.z = value;
camera.updateProjectionMatrix();
});
// endregion camera
gui.open();
}
function render() {
requestAnimationFrame(render);
stats.begin();
renderer.render(scene, camera);
stats.end();
}
function init() {
initScene();
initRenderer();
initCamera();
initControl();
loadTexture();
loadModel();
initStats();
initGui();
}
</script>