微信网站建设公司费用,导航类网站模板,广州档案馆建设网站,杭州翰臣科技有限公司Shadertoy是一个流行的在线平台#xff0c;用于创建和分享WebGL片段着色器。里面有很多令人惊叹的画面#xff0c;甚至3D场景。本人也移植了几个ShaderToy上的着色器。本文将详细介绍移植过程中需要注意的关键点。
1. 基本结构差异
想要移植ShaderToy的shader到three.js用于创建和分享WebGL片段着色器。里面有很多令人惊叹的画面甚至3D场景。本人也移植了几个ShaderToy上的着色器。本文将详细介绍移植过程中需要注意的关键点。
1. 基本结构差异
想要移植ShaderToy的shader到three.js需要先了解他们直接的差异。他们之间的差异主要在以下几个方面 ShaderToy没有顶点着色器 ShaderTory上面的shader只有片元着色器没有几何移植到three.js上需要构造一个默认的顶点着色器同时提供几何信息。这个也比较简单使用两个三角形铺面整个视口即可。其实用其他的方式也可以例如用一个大的三角形只要有个物体几何能充满整个视口即可。 ShaderToy提供了很多内置变量 ShaderToy提供了不少内置变量,在three.js中需要咱们自己用uniform来传入。ShaderToy内置变量处理方法如下
全局变量含义three.js修改方案核心代码uniform vec3 iResolution;视口大小单位像素uniforms.iResolution { value: new THREE.Vector2(options.width, options.hieght) }uniform float iTime;从开始运行到现在的时间单位秒var clock new THREE.Clock();this.uniforms.iTime.value this.clock.getElapsedTime();uniform float iTimeDelta;上一帧渲染到现在的时间单位秒var clock new THREE.Clock();this.uniforms.iTimeDelta.value this.clock.getDelta();uniform int iFrame;第几帧this.uniforms.iFrame.value this.uniforms.iFrame.value 1;uniform float iChannelTime[4];//uniform vec3 iChannelResolution[4];每个通道的分辨率单位像素uniforms[“iChannelResolution”] { type: “v3v”, value: [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), ] };uniform vec4 iMouse;是vec4类型xy是鼠标当前位置与单击位置zw是单击位置document.addEventListener(‘mousemove’, (e) { material.uniforms.iMouse.value.x e.clientX; material.uniforms.iMouse.value.y window.innerHeight - e.clientY; }); document.addEventListener(‘mousedown’, (e) { material.uniforms.iMouse.value.z e.clientX; material.uniforms.iMouse.value.w window.innerHeight - e.clientY; });uniform samplerXX iChanneli;通道的纹理uniforms[“iChannel” i] { type: “t”, value: texture }
ShaderToy语法的差异
ShaderToy语法核心都是 GLSL只是在在变量命名、输入输出方式、内置函数/变量等方面存在区别。以下是关键语法差异的对比
ShaderToythree.js入口函数是mainImage(out vec4 fragColor, in vec2 fragCoord)入口函数是void main()fragCoord当前像素的坐标用的是gl_FragCoord用变量fragColor作为输出通过 gl_FragColor 变量输出不需要定义变量精度需定义精度precision highp float; precision highp int;precision highp sampler2D;precision highp samplerCube;
移植基本模版
!DOCTYPE html
html langenheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleShadertoy to Three.js/titlestylebody {margin: 0;overflow: hidden;}canvas {display: block;}/style
/headbodyscript src./three.min.js/scriptscriptconst scene new THREE.Scene();const camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer new THREE.WebGLRenderer({ antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);console.log(renderer.capabilities.isWebGL2)const geometry new THREE.BufferGeometry();geometry.setAttribute(position, new THREE.Float32BufferAttribute([-1, -1, 0,1, -1, 0,1, 1, 0,-1, 1, 0], 3))geometry.setIndex([0, 1, 2, 0, 2, 3]);const material new THREE.RawShaderMaterial({uniforms: {iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },iTime: { value: 0 },mouse: { value: new THREE.Vector4(0, 0, 0, 0) },},// glslVersion: THREE.GLSL3,vertexShader: #version 300 esin vec3 position;void main() {gl_Position vec4(position, 1.0);},fragmentShader: #version 300 es
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp samplerCube;
out vec4 fragColor;uniform vec2 iResolution;
uniform float iTime;void main( )
{vec2 uv gl_FragCoord.xy/iResolution.xy;// [0,1]uv - 0.5;uv.x * iResolution.x / iResolution.y;float d length(uv);float r 0.3;float c smoothstep(r, r 0.002, d);fragColor vec4(vec3(c), 1.);
}
});const plane new THREE.Mesh(geometry, material);scene.add(plane);window.addEventListener(resize, () {camera.aspect window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);material.uniforms.iResolution.value.set(window.innerWidth, window.innerHeight);});document.addEventListener(mousemove, (e) {material.uniforms.iMouse.value.x e.clientX;material.uniforms.iMouse.value.y window.innerHeight - e.clientY;});document.addEventListener(mousedown, (e) {material.uniforms.iMouse.value.z e.clientX;material.uniforms.iMouse.value.w window.innerHeight - e.clientY;});function animate() {requestAnimationFrame(animate);material.uniforms.iTime.value performance.now() / 1000; // 秒为单位renderer.render(scene, camera);}animate();/script
/body/html这个模版是画圆的实例效果如下 有以下几点需要注意
两个三角形面片的坐标已经在[-1, 1]之间不需要在VertexShader进行坐标变换所有顶点着色器代码没有MVP矩阵
#version 300 es
in vec3 position;
void main() {gl_Position vec4(position, 1.0);
}使用了RawShaderMaterial而不是ShaderMaterial这样可对Shader代码进行完全掌控语法上使用了WebGL2.0的语法如果使用1.0的语法需去掉版本声明、一些关键字
最后展示一个稍微复杂点的Shader效果
结语
将Shadertoy着色器移植到Three.js需要对两者之间的差异有清晰理解。正确处理全局变量、语法、渲染管线等关方面的差异可将绝大多数Shadertoy效果成功移植到Three.js项目中。