<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./libs/three.min.js"></script>
<script src="./libs/OrbitControls.js"></script>
<script src="./libs/FBXLoader.js"></script>
<script src="./libs/inflate.min.js"></script>
<script src="./libs/stats.min.js"></script>
<title>效果</title>
<style>
* {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container">
</div>
<script>
let container, stats;
let camera, scene, renderer, controls;
let time = { value: 0 };
init();
animate();
effect();
function init() {
container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 15000);
camera.position.set(1550, 850, 4290);
scene = new THREE.Scene();
scene.background = new THREE.Color(0x101010);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
const light = new THREE.HemisphereLight(0xffffff, 0x909090, 0.8);
scene.add(light);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
scene.add(directionalLight);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 1;
controls.maxDistance = 10000;
controls.target.set(0, 1, 0);
controls.update();
stats = new Stats();
container.appendChild(stats.dom);
window.addEventListener('resize', onWindowResize, false);
}
function effect() {
loadFbx("./model/shanghai.fbx", function (obj) {
scene.add(obj);
obj.traverse(function (child) {
// 处理材质
if (child.material) {
if (Array.isArray(child.material)) {
child.material.forEach((elem) => {
handleBeofreMaterial(elem);
});
} else {
handleBeofreMaterial(child.material);
}
}
})
})
}
function handleBeofreMaterial(material) {
material.transparent = true;
material.depthWrite = false;
material.side = 2;
material.blending = 2;
material.color = new THREE.Color("#444");
material.opacity = 0.5;
material.onBeforeCompile = function (shader) {
shader.uniforms.time = time;
shader.uniforms.u_speed = { value: 1 }; // 扩散速度
shader.uniforms.u_radius = { value: 100 }; // 扩散半径
shader.uniforms.u_width = { value: Math.PI / 2 }; // 圆环半径
shader.uniforms.hightColor = { value: new THREE.Color("#ff0000") }; // 扩散颜色
let fragmentShader = shader.fragmentShader + "";
let vertexShader = shader.vertexShader + "";
const fragment = `
float lerp (float x,float y,float t ) {
return ( 1.0 - t ) * x + t * y;
}
float distanceTo(vec2 src, vec2 dst) {
float dx = src.x - dst.x;
float dy = src.y - dst.y;
float dv = dx * dx + dy * dy;
return sqrt(dv);
}
float atan2(float y, float x){
float t0, t1, t2, t3, t4;
t3 = abs(x);
t1 = abs(y);
t0 = max(t3, t1);
t1 = min(t3, t1);
t3 = float(1) / t0;
t3 = t1 * t3;
t4 = t3 * t3;
t0 = -float(0.013480470);
t0 = t0 * t4 + float(0.057477314);
t0 = t0 * t4 - float(0.121239071);
t0 = t0 * t4 + float(0.195635925);
t0 = t0 * t4 - float(0.332994597);
t0 = t0 * t4 + float(0.999995630);
t3 = t0 * t3;
t3 = (abs(y) > abs(x)) ? float(1.570796327) - t3 : t3;
t3 = (x < 0.0) ? float(3.141592654) - t3 : t3;
t3 = (y < 0.0) ? -t3 : t3;
return t3;
}
uniform vec3 hightColor;
uniform float u_speed;
uniform float u_radius;
uniform float u_width;
uniform float time;
varying vec3 v_position;
void main() {`;
const fragmentColor = `
float u_time = u_speed * time;
vec2 curr = vec2(v_position.x, v_position.z);
float vLength = distanceTo(vec2(5.0, 0.0), curr);
float len = mod(u_time, u_radius);
float vOpacity = diffuseColor.a;
vec3 vColor = outgoingLight;
float angle = atan2(v_position.x, v_position.z) + PI;
float angleT = mod(angle + u_time, PI2);
float length = distanceTo(vec2(0.0, 0.0), curr);
float d_opacity = 1.0 - angleT / PI * (PI / u_width);
if (length > u_radius) { d_opacity = 0.0; };
vec3 rColor = vec3(1.0, 1.0, 1.0);
if (d_opacity > 0.0) {
rColor = vec3(
lerp(vColor.r, hightColor.r, d_opacity),
lerp(vColor.g, hightColor.g, d_opacity),
lerp(vColor.b, hightColor.b, d_opacity)
);
}
gl_FragColor = vec4( vColor * rColor, d_opacity);
`;
shader.fragmentShader = fragmentShader.replace("void main() {", fragment)
shader.fragmentShader = shader.fragmentShader.replace("gl_FragColor = vec4( outgoingLight, diffuseColor.a );", fragmentColor);
const vertex = `
varying vec3 v_position;
void main() {
v_position = position;
`;
shader.vertexShader = vertexShader.replace("void main() {", vertex);
}
}
function loadFbx(url, callback) {
const loader = new THREE.FBXLoader();
loader.load(url, function (obj) {
callback(obj);
});
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function animate() {
requestAnimationFrame(animate);
render();
controls.update();
stats.update();
}
function render() {
renderer.render(scene, camera);
time.value += 0.015;
}
</script>
</body>
</html>
评论1