mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-06-28 13:17:59 +08:00
feat: 3D 图像效果
This commit is contained in:
parent
7cd4469f2f
commit
58d2b5eb36
@ -35,7 +35,7 @@
|
|||||||
"mutate-animate": "^1.4.2",
|
"mutate-animate": "^1.4.2",
|
||||||
"ogg-opus-decoder": "^1.6.14",
|
"ogg-opus-decoder": "^1.6.14",
|
||||||
"opus-decoder": "^0.7.7",
|
"opus-decoder": "^0.7.7",
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.17"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.26.4",
|
"@babel/cli": "^7.26.4",
|
||||||
|
51
packages-user/client-modules/src/render/fx/base.ts
Normal file
51
packages-user/client-modules/src/render/fx/base.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Shader, ShaderProgram } from '@motajs/render-core';
|
||||||
|
|
||||||
|
export abstract class EffectBase<T> {
|
||||||
|
/** 当前使用的程序 */
|
||||||
|
protected readonly program: ShaderProgram;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly shader: Shader,
|
||||||
|
public readonly options: T
|
||||||
|
) {
|
||||||
|
const vs = this.getVertex(options);
|
||||||
|
const fs = this.getFragment(options);
|
||||||
|
const program = shader.createProgram(ShaderProgram, vs, fs);
|
||||||
|
program.requestCompile();
|
||||||
|
|
||||||
|
this.program = program;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取片段着色器代码
|
||||||
|
* @param options 配置信息
|
||||||
|
*/
|
||||||
|
protected abstract getVertex(options: T): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取顶点着色器代码
|
||||||
|
* @param options 配置信息
|
||||||
|
*/
|
||||||
|
protected abstract getFragment(options: T): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化着色器程序
|
||||||
|
* @param program 着色器程序
|
||||||
|
* @param options 配置信息
|
||||||
|
*/
|
||||||
|
abstract initProgram(program: ShaderProgram, options: T): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新着色器渲染
|
||||||
|
*/
|
||||||
|
requestUpdate() {
|
||||||
|
this.shader.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用此着色器
|
||||||
|
*/
|
||||||
|
use() {
|
||||||
|
this.shader.useProgram(this.program);
|
||||||
|
}
|
||||||
|
}
|
109
packages-user/client-modules/src/render/fx/image3d.ts
Normal file
109
packages-user/client-modules/src/render/fx/image3d.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import {
|
||||||
|
ITransformUpdatable,
|
||||||
|
ShaderProgram,
|
||||||
|
Transform3D
|
||||||
|
} from '@motajs/render-core';
|
||||||
|
import { EffectBase } from './base';
|
||||||
|
|
||||||
|
export class Image3DEffect
|
||||||
|
extends EffectBase<void>
|
||||||
|
implements ITransformUpdatable
|
||||||
|
{
|
||||||
|
/** 图片的模型变换 */
|
||||||
|
private model: Transform3D = new Transform3D();
|
||||||
|
/** 视角变换 */
|
||||||
|
private view: Transform3D = new Transform3D();
|
||||||
|
/** 投影变换 */
|
||||||
|
private proj: Transform3D = new Transform3D();
|
||||||
|
|
||||||
|
protected getVertex(): string {
|
||||||
|
return /* glsl */ `
|
||||||
|
uniform mat4 u_imageTransform;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
v_texCoord = a_texCoord;
|
||||||
|
gl_Position = u_imageTransform * a_position;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFragment(): string {
|
||||||
|
return /* glsl */ `
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = texture2D(u_sampler, v_texCoord);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
initProgram(program: ShaderProgram): void {
|
||||||
|
program.defineUniformMatrix(
|
||||||
|
'u_imageTransform',
|
||||||
|
this.shader.U_MATRIX_4x4
|
||||||
|
);
|
||||||
|
const shader = this.shader;
|
||||||
|
const aspect = shader.width / shader.height;
|
||||||
|
this.proj.perspective((Math.PI * 2) / 3, aspect, 0.01, 1000);
|
||||||
|
this.model.bind(this);
|
||||||
|
this.view.bind(this);
|
||||||
|
this.proj.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTransform(): void {
|
||||||
|
const matrix = this.program.getMatrix('u_imageTransform');
|
||||||
|
if (!matrix) return;
|
||||||
|
const trans = this.model.multiply(this.view).multiply(this.proj);
|
||||||
|
matrix.set(false, trans.mat);
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置模型变换
|
||||||
|
* @param model 模型变换
|
||||||
|
*/
|
||||||
|
setModel(model: Transform3D) {
|
||||||
|
this.model.bind();
|
||||||
|
this.model = model;
|
||||||
|
model.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置视角变换
|
||||||
|
* @param model 视角变换
|
||||||
|
*/
|
||||||
|
setView(view: Transform3D) {
|
||||||
|
this.view.bind();
|
||||||
|
this.view = view;
|
||||||
|
view.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置投影变换
|
||||||
|
* @param model 投影变换
|
||||||
|
*/
|
||||||
|
setProj(proj: Transform3D) {
|
||||||
|
this.proj.bind();
|
||||||
|
this.proj = proj;
|
||||||
|
proj.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模型变换
|
||||||
|
*/
|
||||||
|
getModel() {
|
||||||
|
return this.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取视角变换
|
||||||
|
*/
|
||||||
|
getView() {
|
||||||
|
return this.view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取投影变换
|
||||||
|
*/
|
||||||
|
getProj() {
|
||||||
|
return this.proj;
|
||||||
|
}
|
||||||
|
}
|
2
packages-user/client-modules/src/render/fx/index.ts
Normal file
2
packages-user/client-modules/src/render/fx/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './base';
|
||||||
|
export * from './image3d';
|
@ -110,6 +110,7 @@ export class PointEffect {
|
|||||||
private toAdd: Set<number[]> = new Set();
|
private toAdd: Set<number[]> = new Set();
|
||||||
/** 每个特效的开始时间 */
|
/** 每个特效的开始时间 */
|
||||||
private startTime: Map<number, number> = new Map();
|
private startTime: Map<number, number> = new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为着色器创建程序
|
* 为着色器创建程序
|
||||||
* @param shader 着色器渲染元素
|
* @param shader 着色器渲染元素
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mat3, ReadonlyMat3, ReadonlyVec3, vec2, vec3 } from 'gl-matrix';
|
import { mat3, mat4, ReadonlyMat3, ReadonlyVec3, vec2, vec3 } from 'gl-matrix';
|
||||||
|
|
||||||
export interface ITransformUpdatable {
|
export interface ITransformUpdatable {
|
||||||
updateTransform?(): void;
|
updateTransform?(): void;
|
||||||
@ -38,6 +38,7 @@ export class Transform {
|
|||||||
this.scaleY = 1;
|
this.scaleY = 1;
|
||||||
this.rad = 0;
|
this.rad = 0;
|
||||||
this.modified = false;
|
this.modified = false;
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,11 +190,9 @@ export class Transform {
|
|||||||
*/
|
*/
|
||||||
multiply(transform: Transform): Transform {
|
multiply(transform: Transform): Transform {
|
||||||
if (this.modified) {
|
if (this.modified) {
|
||||||
const res = new Transform();
|
const result = new Transform();
|
||||||
const mat = mat3.clone(this.mat);
|
mat3.multiply(result.mat, this.mat, transform.mat);
|
||||||
mat3.multiply(mat, mat, transform.mat);
|
return result;
|
||||||
res.mat = mat;
|
|
||||||
return res;
|
|
||||||
} else {
|
} else {
|
||||||
return transform.clone();
|
return transform.clone();
|
||||||
}
|
}
|
||||||
@ -253,7 +252,9 @@ export class Transform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 单位矩阵 */
|
/** 单位矩阵 */
|
||||||
static readonly identity = new Transform();
|
static get identity() {
|
||||||
|
return new Transform();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function multiplyVec3(mat: ReadonlyMat3, vec: ReadonlyVec3): vec3 {
|
function multiplyVec3(mat: ReadonlyMat3, vec: ReadonlyVec3): vec3 {
|
||||||
@ -278,3 +279,181 @@ function getScaling(mat: ReadonlyMat3): vec2 {
|
|||||||
function getRotation(mat: ReadonlyMat3): number {
|
function getRotation(mat: ReadonlyMat3): number {
|
||||||
return Math.atan2(mat[3], mat[0]);
|
return Math.atan2(mat[3], mat[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Transform3D {
|
||||||
|
mat: mat4 = mat4.create();
|
||||||
|
|
||||||
|
/** 绑定的可更新元素 */
|
||||||
|
bindedObject?: ITransformUpdatable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定可更新对象
|
||||||
|
* @param obj 要绑定的对象
|
||||||
|
*/
|
||||||
|
bind(obj?: ITransformUpdatable) {
|
||||||
|
this.bindedObject = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置为单位矩阵
|
||||||
|
*/
|
||||||
|
reset(): this {
|
||||||
|
mat4.identity(this.mat);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用缩放变换
|
||||||
|
* @param x X轴缩放
|
||||||
|
* @param y Y轴缩放
|
||||||
|
* @param z Z轴缩放
|
||||||
|
*/
|
||||||
|
scale(x: number, y: number, z: number): this {
|
||||||
|
mat4.scale(this.mat, this.mat, [x, y, z]);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用平移变换
|
||||||
|
* @param x X轴平移
|
||||||
|
* @param y Y轴平移
|
||||||
|
* @param z Z轴平移
|
||||||
|
*/
|
||||||
|
translate(x: number, y: number, z: number): this {
|
||||||
|
mat4.translate(this.mat, this.mat, [x, y, z]);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用旋转变换
|
||||||
|
* @param rad 旋转角度(弧度)
|
||||||
|
* @param axis 旋转轴
|
||||||
|
*/
|
||||||
|
rotate(rad: number, axis: vec3): this {
|
||||||
|
mat4.rotate(this.mat, this.mat, rad, axis);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用绕X轴旋转
|
||||||
|
* @param rad 旋转角度(弧度)
|
||||||
|
*/
|
||||||
|
rotateX(rad: number): this {
|
||||||
|
return this.rotate(rad, [1, 0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用绕Y轴旋转
|
||||||
|
* @param rad 旋转角度(弧度)
|
||||||
|
*/
|
||||||
|
rotateY(rad: number): this {
|
||||||
|
return this.rotate(rad, [0, 1, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用绕Z轴旋转
|
||||||
|
* @param rad 旋转角度(弧度)
|
||||||
|
*/
|
||||||
|
rotateZ(rad: number): this {
|
||||||
|
return this.rotate(rad, [0, 0, 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置视图矩阵
|
||||||
|
* @param eye 摄像机位置
|
||||||
|
* @param center 目标位置
|
||||||
|
* @param up 上方向量
|
||||||
|
*/
|
||||||
|
lookAt(eye: vec3, center: vec3, up: vec3): this {
|
||||||
|
mat4.lookAt(this.mat, eye, center, up);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置透视投影矩阵
|
||||||
|
* @param fovy 垂直视野角度(弧度)
|
||||||
|
* @param aspect 宽高比
|
||||||
|
* @param near 近平面
|
||||||
|
* @param far 远平面
|
||||||
|
*/
|
||||||
|
perspective(fovy: number, aspect: number, near: number, far: number): this {
|
||||||
|
mat4.perspective(this.mat, fovy, aspect, near, far);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置正交投影矩阵
|
||||||
|
* @param left 左平面
|
||||||
|
* @param right 右平面
|
||||||
|
* @param bottom 底平面
|
||||||
|
* @param top 顶平面
|
||||||
|
* @param near 近平面
|
||||||
|
* @param far 远平面
|
||||||
|
*/
|
||||||
|
ortho(
|
||||||
|
left: number,
|
||||||
|
right: number,
|
||||||
|
bottom: number,
|
||||||
|
top: number,
|
||||||
|
near: number,
|
||||||
|
far: number
|
||||||
|
): this {
|
||||||
|
mat4.ortho(this.mat, left, right, bottom, top, near, far);
|
||||||
|
this.bindedObject?.updateTransform?.();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 与另一个变换矩阵相乘
|
||||||
|
* @param transform 另一个变换矩阵
|
||||||
|
*/
|
||||||
|
multiply(transform: Transform3D): Transform3D {
|
||||||
|
const result = new Transform3D();
|
||||||
|
mat4.multiply(result.mat, this.mat, transform.mat);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 克隆当前变换矩阵
|
||||||
|
*/
|
||||||
|
clone(): Transform3D {
|
||||||
|
const clone = new Transform3D();
|
||||||
|
mat4.copy(clone.mat, this.mat);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将点应用变换
|
||||||
|
* @param point 要变换的点
|
||||||
|
*/
|
||||||
|
transformed(point: vec3): vec3 {
|
||||||
|
const result = vec3.create();
|
||||||
|
vec3.transformMat4(result, point, this.mat);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将点应用逆变换
|
||||||
|
* @param point 要逆变换的点
|
||||||
|
*/
|
||||||
|
untransformed(point: vec3): vec3 {
|
||||||
|
const inverse = mat4.create();
|
||||||
|
mat4.invert(inverse, this.mat);
|
||||||
|
const result = vec3.create();
|
||||||
|
vec3.transformMat4(result, point, inverse);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态方法:单位矩阵
|
||||||
|
*/
|
||||||
|
static get identity(): Transform3D {
|
||||||
|
return new Transform3D();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -54,7 +54,7 @@ importers:
|
|||||||
specifier: ^0.7.7
|
specifier: ^0.7.7
|
||||||
version: 0.7.10
|
version: 0.7.10
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.17
|
||||||
version: 3.5.17(typescript@5.8.3)
|
version: 3.5.17(typescript@5.8.3)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@babel/cli':
|
'@babel/cli':
|
||||||
|
Loading…
Reference in New Issue
Block a user