feat: 优化着色器组件

This commit is contained in:
unanmed 2024-08-24 21:32:43 +08:00
parent 2561d7f23d
commit 57760d501e
2 changed files with 72 additions and 8 deletions

View File

@ -75,6 +75,8 @@ Mota.require('var', 'hook').once('reset', () => {
const transform = render.transform;
render.mount();
const ani = new Animation();
const shader = new Shader();
const layer = new LayerGroup();
@ -93,14 +95,35 @@ Mota.require('var', 'hook').once('reset', () => {
shader.appendChild(layer);
shader.size(480, 480);
shader.fs(`
uniform float u_offset;
void main() {
vec2 coord = v_texCoord;
if (coord.y > 0.25 && coord.y < 0.35) {
coord.y = sin((coord.y - 0.25) * 3.1415926535 / 0.2) * 0.1 + 0.25;
}
gl_FragColor = texture2D(u_sampler, coord);
// 计算当前像素到爆炸中心的距离
vec2 coordToCenter = v_texCoord - vec2(0.5, 0.5);
float distance = length(coordToCenter);
// 根据时间计算当前距离上的波动相位
float wavePhase = 100.0 * (distance - u_offset);
// 计算波动的强度(正弦波)并结合衰减
float wave = sin(wavePhase) * 0.02 / (1.0 + 10.0 * distance);
// 将波动效果应用到纹理坐标上,造成扭曲
vec2 warpedCoords = v_texCoord + normalize(coordToCenter) * wave;
// 采样纹理并输出颜色
gl_FragColor = texture2D(u_sampler, warpedCoords);
}
`);
shader.compileShader();
const offset = shader.getUniform('u_offset');
shader.delegateTicker(() => {
shader.gl.uniform1f(offset, ani.value.offset);
shader.update();
}, 20000);
ani.value.offset = 0;
ani.mode(linear()).time(10000).absolute().apply('offset', 1);
layer.requestAfterFrame(() => {
hero.setImage(core.material.images.images['hero2.png']);

View File

@ -1,8 +1,9 @@
import { isNil } from 'lodash-es';
import { logger } from '../common/logger';
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
import { isWebGL2Supported } from '../fx/webgl';
import { Container } from './container';
import { ERenderItemEvent, RenderItemPosition } from './item';
import { ERenderItemEvent, RenderItem, RenderItemPosition } from './item';
import { Transform } from './transform';
const SHADER_VERTEX_PREFIX_300 = /* glsl */ `#version 300 es
@ -94,6 +95,8 @@ export class Shader extends Container<EShaderEvent> {
private shaderModified: boolean = false;
/** 需要重新编译的着色器 */
private shaderDirty: boolean = true;
/** 是否需要重新渲染着色器 */
private shaderRanderDirty: boolean = true;
/** 当前程序是否被外部调用过 */
private programExterned: boolean = false;
@ -141,7 +144,6 @@ export class Shader extends Container<EShaderEvent> {
if (this.shaderDirty) {
this.cacheDirty = true;
this.compileShader();
this.shaderDirty = false;
}
if (this.cacheDirty) {
@ -150,10 +152,14 @@ export class Shader extends Container<EShaderEvent> {
ctx.save();
super.render(this.cache, transform);
ctx.restore();
this.drawScene();
this.cacheDirty = false;
}
if (this.shaderRanderDirty) {
this.drawScene();
this.shaderRanderDirty = false;
}
canvas.ctx.drawImage(this.canvas, 0, 0, this.width, this.height);
}
}
@ -175,9 +181,17 @@ export class Shader extends Container<EShaderEvent> {
this.canvas.height = height * scale;
}
update(item?: RenderItem<any>): void {
const isSelf = item === this && !this.cacheDirty;
super.update(item);
if (isSelf) this.cacheDirty = false;
this.shaderRanderDirty = true;
}
drawScene() {
const gl = this.gl;
if (!this.uniform || !gl) return;
// 清空画布
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
@ -305,6 +319,7 @@ export class Shader extends Container<EShaderEvent> {
Shader.deleteProgram(this, this.getProgram());
}
this.programExterned = false;
this.shaderDirty = false;
this.program = program.program;
this.shader = program.shader;
@ -313,6 +328,32 @@ export class Shader extends Container<EShaderEvent> {
this.gl?.useProgram(this.program);
}
/**
*
* @param name
*/
getAttribute(name: string) {
if (!this.attribute || !this.gl || !this.program) return null;
if (!isNil(this.attribute[name])) return this.attribute[name];
return (this.attribute[name] = this.gl.getAttribLocation(
this.program,
name
));
}
/**
* uniform位置
* @param name
*/
getUniform(name: string) {
if (!this.uniform || !this.gl || !this.program) return null;
if (!isNil(this.uniform[name])) return this.uniform[name];
return (this.uniform[name] = this.gl.getUniformLocation(
this.program,
name
));
}
// ----- 初始化部分
private init() {