绘制图中的嵌套矩形框
方法:
vec3 drawRect(
vec2 st,
vec2 center,
float width,
float height,
float thickness,
vec3 fillColor,
vec3 strokeColor
)
{
vec3 color = vec3(0);
float halfWidth = width * .5;
float halfHeight = height * .5;
float halfTickness = thickness * .5;
vec2 bottomLeft = vec2(center.x - halfWidth, center.y - halfHeight);
vec2 topRight = vec2(center.x + halfWidth, center.y + halfHeight);
//STROKE
vec2 stroke = vec2(0.0);
stroke += step(bottomLeft-halfTickness, st) * (1.0 - step(bottomLeft+halfTickness, st));
stroke += step(topRight-halfTickness, st) * (1.0 - step(topRight+halfTickness, st));
vec2 strokeLimit = step(bottomLeft-halfTickness, st) * (1.0 - step(topRight+halfTickness, st));
stroke *= strokeLimit.x * strokeLimit.y;
color = mix (color, strokeColor, min(stroke.x + stroke.y, 1.0));
//
//FILL
vec2 fill = vec2(0.0);
fill += step(bottomLeft+halfTickness, st) * (1.0 - step(topRight-halfTickness, st));
vec2 fillLimit = step(bottomLeft+halfTickness, st) * (1.0 - step(topRight-halfTickness, st));
fill *= fillLimit.x * fillLimit.y;
color = mix (color, fillColor, min(fill.x + fill.y, 1.0));
return color;
}
color += drawRect(uv,vec2(0.5),0.9,0.9,0.03,vec3(1),vec3(0));
封装自定义shader
/*
* @Author: hongbin
* @Date: 2023-09-02 19:16:55
* @LastEditors: hongbin
* @LastEditTime: 2023-09-11 12:18:54
* @Description:根据音频频域数据 绘制矩形
*/
import * as THREE from "three";
import { autoUpdateUniform } from "./AudioMaterial";
const drawRect = `
vec3 drawRect(
vec2 st,
vec2 center,
float width,
float height,
float thickness,
vec3 fillColor,
vec3 strokeColor
)
{
vec3 color = vec3(0);
float halfWidth = width * .5;
float halfHeight = height * .5;
float halfTickness = thickness * .5;
vec2 bottomLeft = vec2(center.x - halfWidth, center.y - halfHeight);
vec2 topRight = vec2(center.x + halfWidth, center.y + halfHeight);
//STROKE
vec2 stroke = vec2(0.0);
stroke += step(bottomLeft-halfTickness, st) * (1.0 - step(bottomLeft+halfTickness, st));
stroke += step(topRight-halfTickness, st) * (1.0 - step(topRight+halfTickness, st));
vec2 strokeLimit = step(bottomLeft-halfTickness, st) * (1.0 - step(topRight+halfTickness, st));
stroke *= strokeLimit.x * strokeLimit.y;
color = mix (color, strokeColor, min(stroke.x + stroke.y, 1.0));
//
//FILL
vec2 fill = vec2(0.0);
fill += step(bottomLeft+halfTickness, st) * (1.0 - step(topRight-halfTickness, st));
vec2 fillLimit = step(bottomLeft+halfTickness, st) * (1.0 - step(topRight-halfTickness, st));
fill *= fillLimit.x * fillLimit.y;
color = mix (color, fillColor, min(fill.x + fill.y, 1.0));
return color;
}
`;
const defaultParams = {
/** 采用固定值0.3 还是跟随音频数据 默认矩形框一整个显示 */
ttf: false,
/** 线条的宽度
* @default '0.001 + 0.001* float(i)' */
lineWidth: "0.001 + 0.001* float(i)",
/** 矩形框的数量 */
count: 10,
lightColor: new THREE.Color("#fff"),
brightness: 1,
transparent: false,
sampling: 0.6,
side: THREE.FrontSide as THREE.Side,
columnar: false,
columnHeight: 0.1,
columnMargin: 0,
};
export class AudioRectMaterial extends THREE.ShaderMaterial {
@autoUpdateUniform
static audioTexture: THREE.DataTexture;
static audioTextureUniforms: Array<Record<string, THREE.IUniform>> = [];
constructor(p?: Partial<typeof defaultParams>) {
const params = { ...defaultParams, ...p };
const floatCount = 1 / params.count;
params.count = Math.floor(10 / params.count);
const uniforms = {
iChannel0: { value: AudioRectMaterial.audioTexture },
lightColor: {
value: p?.lightColor || params.lightColor.clone(),
},
brightness: { value: params.brightness },
};
AudioRectMaterial.audioTextureUniforms.push(uniforms);
const rectFrame = `
float f = float(i+1) * 0.${params.count} ;
color += drawRect(uv,vec2(0.5),f,f,${params.lineWidth},back,white); `;
const columnar = `
color += drawRect(uv,vec2(0.5,float(${
params.columnMargin
}) + float(i) * float(${floatCount}) + ${
params.columnHeight / 2
}),1.,0.,${params.columnHeight},back,white);
`;
super({
uniforms,
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewPosition;
}`,
fragmentShader: `
varying vec2 vUv;
uniform sampler2D iChannel0;
uniform vec3 lightColor;
uniform float brightness;
const vec3 back = vec3(0);
const vec3 white = vec3(1);
${drawRect}
void main()
{
${
params.ttf
? "float fft = texture( iChannel0, vUv).x;"
: `float fft = texture( iChannel0, vec2(${params.sampling})).x * 1.2;`
}
// fft = 1.;
vec2 uv = vUv;
int stepCount = int(fft * 10.) / ${params.count};
vec3 color;
for (int i = 0; i < stepCount; i++) {
${params.columnar ? columnar : rectFrame}
}
gl_FragColor = vec4(color * lightColor * brightness, ${
params.transparent ? `color.r` : "1."
});
}
`,
transparent: params.transparent,
side: params.side,
});
}
}
./AudioMaterial
音频纹理 请见three.js shadertoy使用手册 - 使用音频Channel和图片Channel/将音频传入glsl shader