<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type = "text/css">
html, body{
margin: 0;
height: 100%;
}
canvas{
display: block;
}
</style>
<body onload="drawFire2();">
</body>
<script src="../build/three.js"></script>
<script src="../node_modules/three/examples/js/renderers/Projector.js"></script>
<script src="../node_modules/three/examples/js/renderers/CanvasRenderer.js"></script>
<script src="../node_modules/three/examples/js/libs/stats.min.js"></script>
<script src="../node_modules/three/examples/js/libs/tween.min.js"></script>
<script src="../THREE.MeshLine/demo/js/dat.gui.min.js"></script>
<script src="../node_modules/three/examples/js/controls/OrbitControls.js"></script>
<script type="text/javascript" src="../build/three.js"></script><script id="vertexShader" type="x-shader/x-vertex">
precision mediump float;
precision mediump int;
attribute vec4 color;
uniform float blend;
uniform sampler2D gradient;
uniform sampler2D blendPattern;
varying vec2 vUv;
varying float vFade;
varying float dissolve;
void main() {
vUv = uv;
dissolve = texture2D(blendPattern, vUv).r * 0.1;
vec4 localPosition = vec4( position*(1.+(dissolve*5.)), 1);
vFade = clamp((localPosition.y + 3.0) / 6.0, 0.0, 1.0);
gl_Position = projectionMatrix * modelViewMatrix * localPosition;
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
precision mediump float;
precision mediump int;
uniform float time;
uniform float blend;
uniform sampler2D gradient;
uniform sampler2D blendPattern;
varying float vFade;
varying vec2 vUv;
varying float dissolve;
void main() {
float spread = 0.2;
float fadeAmount = smoothstep(
max(0., vFade - spread),
min(1., vFade + spread),
blend + dissolve*1.2
);
gl_FragColor = texture2D(gradient, vec2(vUv.x, fadeAmount));
}
</script>
<script>
var fireX = 0.7;
var fireY = 0.7;
var fireZ = 0.7;
var renderer;
function initRender() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor(new THREE.Color(0x000000));
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
}
//
var camera;
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.set(0, 0, 10);
}
//
let scene = new THREE.Scene();
let tempFireObj = new THREE.Group();
scene.add(tempFireObj);
//
var light;
function initLight() {
let light = new THREE.PointLight(0xffffff, 1, 100)
light.position.set(10, 10, 20);
tempFireObj.add(light);
}
//
function initModel(){ //初始化轴辅助
var object = new THREE.AxesHelper(500);
scene.add(object);
}
//
var stats;
function initStats() {
stats = new Stats();
document.body.appendChild(stats.dom);
}
//
var controls1;
function initControls() {
controls1 = new THREE.OrbitControls(camera,renderer.domElement);
controls1.enableDamping = true;
controls1.enableZoom = true;
controls1.autoRotate = false;
controls1.enablePan = true;
}
//
function initRoughTexture() {
var texture = new THREE.TextureLoader().load(
"/example/textures/Rough.jpg",
function () {
console.log("loaded");
},
undefined,
function (e) {
console.log("error", e);
}
);
texture.crossOrigin = ""; //"anonymous";
let plane = new THREE.PlaneGeometry(100, 100, 100, 100)
let planeMaterial = new THREE.MeshStandardMaterial({
color: 0x999999,
roughness: 0.8,
displacementMap: texture,
displacementScale: 2,
displacementBias: -1.4,
map: texture,
});
let groundMesh = new THREE.Mesh(plane, planeMaterial);
groundMesh.rotateX(-90 * THREE.Math.DEG2RAD);
groundMesh.position.y = -2;
tempFireObj.add(groundMesh);
}
class fire {
constructor(density = 30, height = 8, r = 0.2, resolution = 64) {
this.object = new THREE.Group();
this.fireballs = [];
this.height = height;
this.radius = r;
//加载纹理
var texture = new THREE.TextureLoader().load(
"/example/textures/Tendrils.png",
function () {
console.log("loaded");
},
undefined,
function (e) {
console.log("error", e);
}
);
texture.crossOrigin = ""; //"anonymous";
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
var fireGradient = new THREE.TextureLoader().load(
"/example/textures/Fire2.png",
function () {
console.log("loaded");
},
undefined,
function (e) {
console.log("error", e);
}
);
texture.crossOrigin = ""; //"anonymous";
//设置属性,调用着色器
this.fireMaterial = new THREE.ShaderMaterial({
uniforms: {
time: {
value: 1.0
},
blend: {
value: 1.0
},
gradient: {
type: "t",
value: fireGradient
},
blendPattern: {
type: "t",
value: texture
},
},
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
transparent: true,
side: THREE.DoubleSide,
//blending:THREE.AdditiveBlending
});
this.light = new THREE.PointLight(0xFF5500, 1, 100)
this.light.position.set(0, 0.4, 0);
this.lightIntensity = Math.random() * 5;
this.object.add(this.light);
//this.fireMaterial = new THREE.MeshStandardMaterial(0x661100);
for (var i = 0; i < density; i++) {
let geometry = new THREE.SphereGeometry(1, resolution, resolution);
let mat = this.fireMaterial.clone();
mat.uniforms.blendPattern.value = texture;
mat.uniforms.gradient.value = fireGradient;
mat.needsUpdate = true;
let sphere = new THREE.Mesh(geometry, mat);
sphere.position.y = Math.random() * height;
sphere.position.x = (0.5 - Math.random()) * this.radius;
sphere.position.z = (0.5 - Math.random()) * this.radius;
sphere.rotateX(Math.random() * 1);
sphere.rotateZ(Math.PI + (0.5 - Math.random()));
sphere.rotateY(Math.random() * 3);
sphere.dirX = ((0.5 - Math.random()) * 0.02);
sphere.dirY = 0.02;
sphere.dirZ = ((0.5 - Math.random()) * 0.02);
this.fireballs.push(sphere);
}
this.object.add(...this.fireballs);
}
update() {
this.fireballs.forEach(ball => {
ball.position.y += ball.dirY + Math.sin(ball.position.y * 0.002);
ball.position.x += Math.sin(ball.position.y * 0.5) * ball.dirX;
ball.position.z += Math.cos(ball.position.y * 0.25) * ball.dirZ;
if (ball.position.y > this.height) {
ball.position.y = -0.01
ball.position.x = (0.5 - Math.random()) * this.radius;
ball.position.z = (0.5 - Math.random()) * this.radius;
}
let p = ball.position.y / this.height;
// ball.rotateZ((1.2-p)*0.01);
ball.rotateY((1.2 - p) * 0.01)
ball.scale.set(0.4 + p, 0.4 + p, 0.4 + p);
///ball.opacity = p;
ball.material.uniforms.blend.value = p;
//ball.material.needsUpdate = true;
})
this.light.intensity += (this.lightIntensity - this.light.intensity) * 0.02;
if (Math.random() > 0.8) {
this.lightIntensity = Math.random() * 6;
}
}
env(val, envelope = [0., 0., 0.1, 1., 1., 0.]) {
function lerp(v0, v1, t) {
return v0 * (1 - t) + v1 * t
}
}
}
let f = new fire();
f.object.position.y = -2;
f.object.scale.set(fireX,fireY,fireZ);
tempFireObj.add(f.object);
// let cubeGeometry = new THREE.CubeGeometry(2, 2)
// let cubeMaterial = new THREE.MeshStandardMaterial();
// let cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial);
// scene.add(cubeMesh)
//
//
function resize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
stats.update();
//controls1.update();
f.update();
renderer.render(scene, camera);
}
function drawFire2() {
initRender();
initCamera();
initLight();
initModel();
initRoughTexture(); //测试用
//initControls();
initStats();
resize();
animate();
}
</script>
</body>
</html>
WEBGL真实火焰实现(完整)
最新推荐文章于 2024-07-12 13:36:10 发布