mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-06-28 05:07:59 +08:00
feat: 3D 图像效果
This commit is contained in:
parent
7cd4469f2f
commit
58d2b5eb36
@ -35,7 +35,7 @@
|
||||
"mutate-animate": "^1.4.2",
|
||||
"ogg-opus-decoder": "^1.6.14",
|
||||
"opus-decoder": "^0.7.7",
|
||||
"vue": "^3.5.13"
|
||||
"vue": "^3.5.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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 startTime: Map<number, number> = new Map();
|
||||
|
||||
/**
|
||||
* 为着色器创建程序
|
||||
* @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 {
|
||||
updateTransform?(): void;
|
||||
@ -38,6 +38,7 @@ export class Transform {
|
||||
this.scaleY = 1;
|
||||
this.rad = 0;
|
||||
this.modified = false;
|
||||
this.bindedObject?.updateTransform?.();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,11 +190,9 @@ export class Transform {
|
||||
*/
|
||||
multiply(transform: Transform): Transform {
|
||||
if (this.modified) {
|
||||
const res = new Transform();
|
||||
const mat = mat3.clone(this.mat);
|
||||
mat3.multiply(mat, mat, transform.mat);
|
||||
res.mat = mat;
|
||||
return res;
|
||||
const result = new Transform();
|
||||
mat3.multiply(result.mat, this.mat, transform.mat);
|
||||
return result;
|
||||
} else {
|
||||
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 {
|
||||
@ -278,3 +279,181 @@ function getScaling(mat: ReadonlyMat3): vec2 {
|
||||
function getRotation(mat: ReadonlyMat3): number {
|
||||
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
|
||||
version: 0.7.10
|
||||
vue:
|
||||
specifier: ^3.5.13
|
||||
specifier: ^3.5.17
|
||||
version: 3.5.17(typescript@5.8.3)
|
||||
devDependencies:
|
||||
'@babel/cli':
|
||||
|
Loading…
Reference in New Issue
Block a user