欢迎光临
我们一直在努力

学习threejs,实现熔岩特效

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️THREE.ShaderMaterial
      • 1.1.1 ☘️注意事项
      • 1.1.2 ☘️构造函数
      • 1.1.3 ☘️属性
      • 1.1.4 ☘️方法
    • 1.2 ☘️THREE.EffectComposer 后期处理
      • 1.2.1 ☘️代码示例
      • 1.2.2 ☘️构造函数
      • 1.2.3 ☘️属性
      • 1.2.4 ☘️方法
    • 1.3 ☘️THREE.BloomPass
      • 1.3.1 ☘️构造函数
      • 1.3.2 ☘️属性
      • 1.3.3 ☘️方法
    • 1.4 ☘️THREE.OutputPass
      • 1.4.1 ☘️构造函数
      • 1.4.2 ☘️属性
      • 1.4.3 ☘️方法
  • 二、🍀实现熔岩特效
    • 1. ☘️实现思路
    • 2. ☘️代码样例

一、🍀前言

本文详细介绍如何基于threejs在三维场景中实现熔岩特效,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.ShaderMaterial

THREE.ShaderMaterial使用自定义shader渲染的材质。 shader是一个用GLSL编写的小程序 ,在GPU上运行。

1.1.1 ☘️注意事项

  • ShaderMaterial 只有使用 WebGLRenderer 才可以绘制正常, 因为 vertexShader 和 fragmentShader 属性中GLSL代码必须使用WebGL来编译并运行在GPU中。
  • 从 THREE r72开始,不再支持在ShaderMaterial中直接分配属性。 必须使用 BufferGeometry实例,使用BufferAttribute实例来定义自定义属性。
  • 从 THREE r77开始,WebGLRenderTarget 或 WebGLCubeRenderTarget 实例不再被用作uniforms。 必须使用它们的texture 属性。
  • 内置attributes和uniforms与代码一起传递到shaders。 如果您不希望WebGLProgram向shader代码添加任何内容,则可以使用RawShaderMaterial而不是此类。
  • 您可以使用指令#pragma unroll_loop_start,#pragma unroll_loop_end 以便通过shader预处理器在GLSL中展开for循环。 该指令必须放在循环的正上方。循环格式必须与定义的标准相对应。
  • 循环必须标准化normalized。
  • 循环变量必须是i。
  • 对于给定的迭代,值 UNROLLED_LOOP_INDEX 将替换为 i 的显式值,并且可以在预处理器语句中使用。

#pragma unroll_loop_start
for ( int i = 0; i < 10; i ++ ) {

// …

}
#pragma unroll_loop_end

代码示例

const material = new THREE.ShaderMaterial( {
uniforms: {
time: { value: 1.0 },
resolution: { value: new THREE.Vector2() }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );

1.1.2 ☘️构造函数

ShaderMaterial( parameters : Object ) parameters – (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。

1.1.3 ☘️属性

共有属性请参见其基类Material。

.clipping : Boolean 定义此材质是否支持剪裁; 如果渲染器传递clippingPlanes uniform,则为true。默认值为false。

.defaultAttributeValues : Object 当渲染的几何体不包含这些属性但材质包含这些属性时,这些默认值将传递给shaders。这可以避免在缓冲区数据丢失时出错。

this.defaultAttributeValues = {
'color': [ 1, 1, 1 ],
'uv': [ 0, 0 ],
'uv2': [ 0, 0 ]
};

.defines : Object 使用 #define 指令在GLSL代码为顶点着色器和片段着色器定义自定义常量;每个键/值对产生一行定义语句:

defines: {
FOO: 15,
BAR: true
}

这将在GLSL代码中产生如下定义语句:

#define FOO 15
#define BAR true

.extensions : Object 一个有如下属性的对象:

this.extensions = {
derivatives: false, // set to use derivatives
fragDepth: false, // set to use fragment depth values
drawBuffers: false, // set to use draw buffers
shaderTextureLOD: false // set to use shader texture LOD
};

.fog : Boolean 定义材质颜色是否受全局雾设置的影响; 如果将fog uniforms传递给shader,则为true。默认值为false。

.fragmentShader : String 片元着色器的GLSL代码。这是shader程序的实际代码。在上面的例子中, vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。

.glslVersion : String 定义自定义着色器代码的 GLSL 版本。仅与 WebGL 2 相关,以便定义是否指定 GLSL 3.0。有效值为 THREE.GLSL1 或 THREE.GLSL3。默认为空。

.index0AttributeName : String 如果设置,则调用gl.bindAttribLocation 将通用顶点索引绑定到属性变量。默认值未定义。

.isShaderMaterial : Boolean 只读标志,用于检查给定对象是否属于 ShaderMaterial 类型。

.lights : Boolean 材质是否受到光照的影响。默认值为 false。如果传递与光照相关的uniform数据到这个材质,则为true。默认是false。

.linewidth : Float 控制线框宽度。默认值为1。

由于OpenGL Core Profile与大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。

.flatShading : Boolean 定义材质是否使用平面着色进行渲染。默认值为false。

.uniforms : Object 如下形式的对象:

{ "uniform1": { value: 1.0 }, "uniform2": { value: 2 } }

指定要传递给shader代码的uniforms;键为uniform的名称,值(value)是如下形式:

{ value: 1.0 }

这里 value 是uniform的值。名称必须匹配 uniform 的name,和GLSL代码中的定义一样。 注意,uniforms逐帧被刷新,所以更新uniform值将立即更新GLSL代码中的相应值。

.uniformsNeedUpdate : Boolean 可用于在 Object3D.onBeforeRender() 中更改制服时强制进行制服更新。默认为假。

.vertexColors : Boolean 定义是否使用顶点着色。默认为假。

.vertexShader : String 顶点着色器的GLSL代码。这是shader程序的实际代码。 在上面的例子中,vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。

.wireframe : Boolean 将几何体渲染为线框(通过GL_LINES而不是GL_TRIANGLES)。默认值为false(即渲染为平面多边形)。

.wireframeLinewidth : Float 控制线框宽度。默认值为1。

由于OpenGL Core Profile与大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。

1.1.4 ☘️方法

共有方法请参见其基类Material。

.clone () : ShaderMaterial this : ShaderMaterial 创建该材质的一个浅拷贝。需要注意的是,vertexShader和fragmentShader使用引用拷贝; attributes的定义也是如此; 这意味着,克隆的材质将共享相同的编译WebGLProgram; 但是,uniforms 是 值拷贝,这样对不同的材质我们可以有不同的uniforms变量。

1.2 ☘️THREE.EffectComposer 后期处理

THREE.EffectComposer 用于在three.js中实现后期处理效果。该类管理了产生最终视觉效果的后期处理过程链。 后期处理过程根据它们添加/插入的顺序来执行,最后一个过程会被自动渲染到屏幕上。

1.2.1 ☘️代码示例

import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
// 初始化 composer
const composer = new EffectComposer(renderer);
// 创建 RenderPass 并添加到 composer
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// 添加其他后期处理通道(如模糊)
// composer.addPass(blurPass);
// 在动画循环中渲染
function animate() {
composer.render();
requestAnimationFrame(animate);
}

1.2.2 ☘️构造函数

EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget ) renderer – 用于渲染场景的渲染器。 renderTarget – (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。

1.2.3 ☘️属性

.passes : Array 一个用于表示后期处理过程链(包含顺序)的数组。

渲染通道:
BloomPass 该通道会使得明亮区域参入较暗的区域。模拟相机照到过多亮光的情形
DotScreenPass 将一层黑点贴到代表原始图片的屏幕上
FilmPass 通过扫描线和失真模拟电视屏幕
MaskPass 在当前图片上贴一层掩膜,后续通道只会影响被贴的区域
RenderPass 该通道在指定的场景和相机的基础上渲染出一个新的场景
SavePass 执行该通道时,它会将当前渲染步骤的结果复制一份,方便后面使用。这个通道实际应用中作用不大;
ShaderPass 使用该通道你可以传入一个自定义的着色器,用来生成高级的、自定义的后期处理通道
TexturePass 该通道可以将效果组合器的当前状态保存为一个纹理,然后可以在其他EffectCoposer对象中将该纹理作为输入参数

.readBuffer : WebGLRenderTarget 内部读缓冲区的引用。过程一般从该缓冲区读取先前的渲染结果。

.renderer : WebGLRenderer 内部渲染器的引用。

.renderToScreen : Boolean 最终过程是否被渲染到屏幕(默认帧缓冲区)。

.writeBuffer : WebGLRenderTarget 内部写缓冲区的引用。过程常将它们的渲染结果写入该缓冲区。

1.2.4 ☘️方法

.addPass ( pass : Pass ) : undefined pass – 将被添加到过程链的过程

将传入的过程添加到过程链。

.dispose () : undefined 释放此实例分配的 GPU 相关资源。每当您的应用程序不再使用此实例时调用此方法。

.insertPass ( pass : Pass, index : Integer ) : undefined pass – 将被插入到过程链的过程。

index – 定义过程链中过程应插入的位置。

将传入的过程插入到过程链中所给定的索引处。

.isLastEnabledPass ( passIndex : Integer ) : Boolean passIndex – 被用于检查的过程

如果给定索引的过程在过程链中是最后一个启用的过程,则返回true。 由EffectComposer所使用,来决定哪一个过程应当被渲染到屏幕上。

.removePass ( pass : Pass ) : undefined pass – 要从传递链中删除的传递。

从传递链中删除给定的传递。

.render ( deltaTime : Float ) : undefined deltaTime – 增量时间值。

执行所有启用的后期处理过程,来产生最终的帧,

.reset ( renderTarget : WebGLRenderTarget ) : undefined renderTarget – (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。

重置所有EffectComposer的内部状态。

.setPixelRatio ( pixelRatio : Float ) : undefined pixelRatio – 设备像素比

设置设备的像素比。该值通常被用于HiDPI设备,以阻止模糊的输出。 因此,该方法语义类似于WebGLRenderer.setPixelRatio()。

.setSize ( width : Integer, height : Integer ) : undefined width – EffectComposer的宽度。 height – EffectComposer的高度。

考虑设备像素比,重新设置内部渲染缓冲和过程的大小为(width, height)。 因此,该方法语义类似于WebGLRenderer.setSize()。

.swapBuffers () : undefined 交换内部的读/写缓冲。

1.3 ☘️THREE.BloomPass

THREE.BloomPass是 Three.js 后期处理模块中用于实现辉光效果(Bloom)的通道,可模拟强光溢出、柔化高亮区域的效果,常用于增强场景的光照表现。

1.3.1 ☘️构造函数

const bloomPass = new BloomPass(
strength, // 辉光强度
kernelSize, // 模糊核大小
sigma, // 模糊强度
resolution // 分辨率缩放(可选)
);

  • strength number 默认1 辉光效果的强度(值越大越明亮)。
  • kernelSize number 默认25 模糊核大小(必须为奇数,如 15, 25, 35)。值越大模糊范围越广。
  • sigma number 默认4.0 高斯模糊的锐度(值越大越模糊)。
  • resolution number 默认256 内部渲染缓冲区的分辨率(值越低性能越好,但效果越粗糙)。

1.3.2 ☘️属性

.enabled:boolean 是否启用此通道(默认 true)。设为 false 可临时禁用效果。

.strength:number 动态调整辉光强度(等同于构造函数参数)。

.renderToScreen:boolean 是否直接渲染到屏幕(默认 false)。若为最后通道,需设为 true。

1.3.3 ☘️方法

.setSize(width, height) 调整通道的渲染尺寸(通常由 EffectComposer 自动调用)。 width: 画布宽度(像素)。 height: 画布高度(像素)。

1.4 ☘️THREE.OutputPass

OutputPass 是 Three.js 后期处理(Post-Processing)中的一个通道(Pass),用于控制最终渲染输出的颜色空间、色调映射(Tone Mapping)和抗锯齿等效果。它通常作为 EffectComposer 的最后一个通道,负责将处理后的图像输出到屏幕。

1.4.1 ☘️构造函数

new OutputPass(resolution) resolution (Vector2): 可选参数,指定输出分辨率。默认值为 null,自动匹配画布尺寸。

1.4.2 ☘️属性

.output:WebGLRenderTarget 类型: WebGLRenderTarget 描述: 存储最终渲染结果的渲染目标对象。 .uniforms:Object 类型: Object 描述: 包含着色器统一变量(Uniforms)的对象,用于控制输出效果。常用属性: toneMappingExposure (Number): 色调映射曝光值,默认 1.0。 toneMappingType (Number): 色调映射算法类型,默认 NoToneMapping。 .needsSwap:boolean 类型: Boolean 描述: 是否需要交换帧缓冲区,通常设为 true 以确保输出到屏幕。

1.4.3 ☘️方法

.setSize(width, height) 调整通道的渲染尺寸(通常由 EffectComposer 自动调用)。 width: 画布宽度(像素)。 height: 画布高度(像素)。 .render(renderer, writeBuffer, readBuffer) 功能: 执行渲染操作(通常由 EffectComposer 自动调用)。

二、🍀实现熔岩特效

1. ☘️实现思路

通过threejs的ShaderMaterial自定义着色器实现熔岩特效。具体代码参考下面代码样例。

2. ☘️代码样例

<!DOCTYPE html>
<html lang="en">
<head>
<title>熔岩特效</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>

<div id="container"></div>
<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> – shader material demo. featuring lava shader by <a href="http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057" target="_blank" rel="noopener">TheGameMaker</a></div>

<script id="fragmentShader" type="x-shader/x-fragment">

uniform float time;

uniform float fogDensity;
uniform vec3 fogColor;

uniform sampler2D texture1;
uniform sampler2D texture2;

varying vec2 vUv;

void main( void ) {

vec2 position = 1.0 + 2.0 * vUv;

vec4 noise = texture2D( texture1, vUv );
vec2 T1 = vUv + vec2( 1.5, 1.5 ) * time * 0.02;
vec2 T2 = vUv + vec2( 0.5, 2.0 ) * time * 0.01;

T1.x += noise.x * 2.0;
T1.y += noise.y * 2.0;
T2.x -= noise.y * 0.2;
T2.y += noise.z * 0.2;

float p = texture2D( texture1, T1 * 2.0 ).a;

vec4 color = texture2D( texture2, T2 * 2.0 );
vec4 temp = color * ( vec4( p, p, p, p ) * 2.0 ) + ( color * color 0.1 );

if( temp.r > 1.0 ) { temp.bg += clamp( temp.r 2.0, 0.0, 100.0 ); }
if( temp.g > 1.0 ) { temp.rb += temp.g 1.0; }
if( temp.b > 1.0 ) { temp.rg += temp.b 1.0; }

gl_FragColor = temp;

float depth = gl_FragCoord.z / gl_FragCoord.w;
const float LOG2 = 1.442695;
float fogFactor = exp2( fogDensity * fogDensity * depth * depth * LOG2 );
fogFactor = 1.0 clamp( fogFactor, 0.0, 1.0 );

gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );

}

</script>

<script id="vertexShader" type="x-shader/x-vertex">

uniform vec2 uvScale;
varying vec2 vUv;

void main()
{

vUv = uvScale * uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;

}

</script>

<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/"
}
}
</script>

<script type="module">

import * as THREE from 'three';

import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { BloomPass } from 'three/addons/postprocessing/BloomPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';

let camera, renderer, composer, timer;

let uniforms, mesh;

init();

function init() {

const container = document.getElementById( 'container' );

camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 3000 );
camera.position.z = 4;

const scene = new THREE.Scene();

timer = new THREE.Timer();
timer.connect( document );

const textureLoader = new THREE.TextureLoader();

const cloudTexture = textureLoader.load( './images/cloud.png' );
const lavaTexture = textureLoader.load( './images/lavatile.jpg' );

lavaTexture.colorSpace = THREE.SRGBColorSpace;

cloudTexture.wrapS = cloudTexture.wrapT = THREE.RepeatWrapping;
lavaTexture.wrapS = lavaTexture.wrapT = THREE.RepeatWrapping;

uniforms = {

'fogDensity': { value: 0.45 },
'fogColor': { value: new THREE.Vector3( 0, 0, 0 ) },
'time': { value: 1.0 },
'uvScale': { value: new THREE.Vector2( 3.0, 1.0 ) },
'texture1': { value: cloudTexture },
'texture2': { value: lavaTexture }

};

const size = 0.65;

const material = new THREE.ShaderMaterial( {

uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent

} );

mesh = new THREE.Mesh( new THREE.TorusGeometry( size, 0.3, 30, 30 ), material );
mesh.rotation.x = 0.3;
scene.add( mesh );

//

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
renderer.autoClear = false;
container.appendChild( renderer.domElement );

//

const renderModel = new RenderPass( scene, camera );
const effectBloom = new BloomPass( 1.25 );
const outputPass = new OutputPass();

composer = new EffectComposer( renderer );

composer.addPass( renderModel );
composer.addPass( effectBloom );
composer.addPass( outputPass );

//

window.addEventListener( 'resize', onWindowResize );

}

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );
composer.setSize( window.innerWidth, window.innerHeight );

}

//

function animate() {

timer.update();

const delta = 5 * timer.getDelta();

uniforms[ 'time' ].value += 0.2 * delta;

mesh.rotation.y += 0.0125 * delta;
mesh.rotation.x += 0.05 * delta;

renderer.clear();
composer.render( 0.01 );

}

</script>

</body>
</html>

效果如下: 在这里插入图片描述 源码

赞(0)
未经允许不得转载:171主机测评 » 学习threejs,实现熔岩特效
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址