Skip to content

Commit

Permalink
add expression and chunk
Browse files Browse the repository at this point in the history
  • Loading branch information
SantyWang committed Apr 18, 2023
1 parent 850d3c3 commit 07c7419
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 10 deletions.
2 changes: 1 addition & 1 deletion cocos/vfx/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export enum Space {
export enum ScalingMode {
HIERARCHY,
LOCAL,
NONE
SHAPE,
}

export enum FinishAction {
Expand Down
32 changes: 32 additions & 0 deletions cocos/vfx/expression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright (c) 2020 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
import { ParticleEmitterParams, ParticleExecContext } from "./particle-base";
import { ParticleDataSet } from "./particle-data-set";

export abstract class Expression {
public abstract tick (particles: ParticleDataSet, params: ParticleEmitterParams, context: ParticleExecContext);
public abstract bind (particles: ParticleDataSet, params: ParticleEmitterParams, context: ParticleExecContext);
public abstract evaluate (index: number);
}
Empty file.
5 changes: 4 additions & 1 deletion cocos/vfx/expression/float-expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
import { ccclass } from 'cc.decorator';
import { approx, lerp, Enum, RealCurve, CCClass, RealKeyframeValue } from '../../core';
import { constructLegacyCurveAndConvert } from '../../core/geometry/curve';
import { Expression } from '../expression';
import { ParticleEmitterParams, ParticleExecContext } from '../particle-base';
import { ParticleDataSet } from '../particle-data-set';

const setClassAttr = CCClass.Attr.setClassAttr;

Expand All @@ -37,7 +40,7 @@ export enum FloatExpressionMode {
}
// TODO: can not remove ccclass for now, we need ccclass specified deserialization to handle deserialization of RealCurve
@ccclass('cc.FloatExpression')
export class FloatExpression {
export abstract class FloatExpression extends Expression {
public static Mode = FloatExpressionMode;

/**
Expand Down
2 changes: 2 additions & 0 deletions cocos/vfx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import { FloatExpression } from './expression/float-expression';
import { ColorExpression } from './expression/color-expression';
import './vfx-manager';
import { ParticleRenderer } from './particle-renderer';
import { Expression } from './expression';

export {
ParticleEmitter,
ParticleRenderer,
FloatExpression,
ColorExpression,
EventHandler,
Expression
};

export * from './modules';
1 change: 0 additions & 1 deletion cocos/vfx/particle-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,6 @@ export class ParticleExecContext {

updateTransform (node: Node, inWorldSpace: boolean) {
if (node.flagChangedVersion !== this._lastTransformChangedVersion) {
Mat4.copy(this.localToWorld, node.worldMatrix);
Mat4.invert(this.worldToLocal, this.localToWorld);
if (inWorldSpace) {
Mat4.getRotation(this.rotationIfNeedTransform, this.localToWorld);
Expand Down
4 changes: 2 additions & 2 deletions cocos/vfx/particle-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,10 +511,10 @@ export class ParticleEmitter extends Component {
private _prewarmSystem () {
let prewarmTime = this.prewarmTime;
const timeStep = Math.max(this.prewarmTimeStep, 0.001);
const count = Math.ceil(this.prewarmTime / timeStep);
const count = Math.ceil(prewarmTime / timeStep);

for (let i = 0; i < count; ++i) {
const dt = Math.min(timeStep, this.prewarmTime);
const dt = Math.min(timeStep, prewarmTime);
prewarmTime -= dt;
this.tick(dt);
}
Expand Down
2 changes: 1 addition & 1 deletion editor/assets/chunks/builtin/internal/vfx-common.chunk
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ in vec3 a_normal; // mesh normal
in vec4 a_color; // mesh color
#endif

vec4 lpvs_main () {
vec4 vfx_vs_main () {
ParticleInput particleInput;
setupParticleInput(particleInput);
vec4 pos = vec4(particleInput.position.xyz, 1);
Expand Down
9 changes: 9 additions & 0 deletions editor/assets/chunks/builtin/internal/vfx-common.chunk.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ver": "1.0.7",
"importer": "effect-header",
"imported": true,
"uuid": "a58971af-4c9f-4223-b2ae-3dfbc6696f62",
"files": [],
"subMetas": {},
"userData": {}
}
123 changes: 123 additions & 0 deletions editor/assets/effects/vfx/builtin-vfx.effect
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
CCEffect %{
temporaries:
b1: &b1
targets:
- blend: true
blendSrc: src_alpha
blendDst: one
blendSrcAlpha: src_alpha
blendDstAlpha: one
b2: &b2
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendSrcAlpha: zero
blendDstAlpha: one
blendAlphaEq: max
b3: &b3
targets:
- blend: true
blendSrc: dst_color
blendDst: one
blendSrcAlpha: zero
blendDstAlpha: dst_alpha
d1: &d1 { depthTest: true, depthWrite: false }
r1: &r1 { cullMode: none }
p1: &p1
mainTexture: { value: grey }
mainTiling_Offset: { value: [1, 1, 0, 0] }
p2: &p2
<<: *p1
tintColor: { value: [0.5, 0.5, 0.5, 0.5], editor: { type: color } }

techniques:
- name: add
passes:
- vert: builtin/internal/vfx-common:vfx_vs_main
frag: tinted-fs:add
rasterizerState: *r1
depthStencilState: *d1
blendState: *b1
properties: *p2
- name: alpha-blend
passes:
- vert: builtin/internal/vfx-common:vfx_vs_main
frag: tinted-fs:add
rasterizerState: *r1
depthStencilState: *d1
blendState: *b2
properties: *p2
- name: add-multiply
passes:
- vert: builtin/internal/vfx-common:vfx_vs_main
frag: tinted-fs:multiply
rasterizerState: *r1
depthStencilState: *d1
blendState: *b3
properties: *p2
- name: add-smooth
passes:
- vert: builtin/internal/vfx-common:vfx_vs_main
frag: no-tint-fs:addSmooth
rasterizerState: *r1
depthStencilState: *d1
blendState: *b1
properties: *p1
- name: premultiply-blend
passes:
- vert: builtin/internal/vfx-common:vfx_vs_main
frag: no-tint-fs:premultiplied
rasterizerState: *r1
depthStencilState: *d1
blendState: *b2
properties: *p1
}%

// TODO: soft particle

CCProgram tinted-fs %{
precision mediump float;
#include <legacy/output>

in vec2 uv;
in vec4 color;

uniform sampler2D mainTexture;
uniform FragConstants {
vec4 tintColor;
};

vec4 add () {
vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);
return CCFragOutput(col);
}

vec4 multiply () {
vec4 col;
vec4 texColor = texture(mainTexture, uv);
col.rgb = tintColor.rgb * texColor.rgb * color.rgb * vec3(2.0);
return CCFragOutput(col);
}
}%

CCProgram no-tint-fs %{
precision mediump float;
#include <legacy/output>

in vec2 uv;
in vec4 color;

uniform sampler2D mainTexture;

vec4 addSmooth () {
vec4 col = color * texture(mainTexture, uv);
col.rgb *= col.a;
return CCFragOutput(col);
}

vec4 premultiplied () {
vec4 col = color * texture(mainTexture, uv) * color.a;
return CCFragOutput(col);
}
}%
80 changes: 76 additions & 4 deletions tests/vfx/particle-parameter.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Vec3 } from '../../cocos/core';
import { BATCH_OPERATION_THRESHOLD_VEC3, ParticleBoolArrayParameter, ParticleColorArrayParameter, ParticleFloatArrayParameter, ParticleParameterType, ParticleUint32ArrayParameter, ParticleVec3ArrayParameter } from '../../cocos/vfx/particle-parameter';
import { ParticleParameterType } from '../../cocos/vfx/enum';
import { BATCH_OPERATION_THRESHOLD_VEC3, ParticleBoolArrayParameter, ParticleColorArrayParameter, ParticleFloatArrayParameter, ParticleUint32ArrayParameter, ParticleVec3ArrayParameter } from '../../cocos/vfx/particle-parameter';
import { RandomStream } from '../../cocos/vfx/random-stream';

describe('ParticleVec3ArrayParameter', () => {
Expand Down Expand Up @@ -678,9 +679,9 @@ describe('ParticleVec3ArrayParameter', () => {
}
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.getVec3At(vec3, i);
expect(vec3.x).toBeCloseTo(val + randomStream2.getSignedFloat() * 1000, 4);
expect(vec3.y).toBeCloseTo(val + randomStream2.getSignedFloat() * 100, 5);
expect(vec3.z).toBeCloseTo(val + randomStream2.getSignedFloat() * 10, 5);
expect(vec3.x).toBeCloseTo(val + randomStream2.getSignedFloat() * 1000, 3);
expect(vec3.y).toBeCloseTo(val + randomStream2.getSignedFloat() * 100, 4);
expect(vec3.z).toBeCloseTo(val + randomStream2.getSignedFloat() * 10, 4);
}
});

Expand Down Expand Up @@ -760,6 +761,77 @@ describe('ParticleVec3ArrayParameter', () => {
}
});

test('multiply1fAt', () => {
expect(() => vec3Parameter.multiply1fAt(1, -1)).toThrowError();
expect(() => vec3Parameter.multiply1fAt(1, 10000)).toThrowError();
const val = Math.random() * 200 - 100;
vec3Parameter.fill1f(val, 0, vec3Parameter.capacity);
const randomIndex = Math.floor(Math.random() * vec3Parameter.capacity);
const x = Math.random();
vec3Parameter.multiply1fAt(x, randomIndex);
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.getVec3At(vec3, i);
if (i === randomIndex) {
expect(vec3.x).toBeCloseTo(x * val, 4);
expect(vec3.y).toBeCloseTo(x * val, 4);
expect(vec3.z).toBeCloseTo(x * val, 4);
} else {
expect(vec3.x).toBeCloseTo(val, 4);
expect(vec3.y).toBeCloseTo(val, 4);
expect(vec3.z).toBeCloseTo(val, 4);
}
}
const val2 = Math.random() * 200 - 100;
vec3Parameter.fill1f(val2, 0, vec3Parameter.capacity);
const randomStream = new RandomStream(Math.random() * 10000);
const randomStream2 = new RandomStream(randomStream.seed);
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.multiply1fAt(randomStream.getSignedFloat(), i);
}
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.getVec3At(vec3, i);
const random = randomStream2.getSignedFloat();
expect(vec3.x).toBeCloseTo(random * val2, 4);
expect(vec3.y).toBeCloseTo(random * val2, 4);
expect(vec3.z).toBeCloseTo(random * val2, 4);
}
});

test('add1fAt', () => {
expect(() => vec3Parameter.add1fAt(1, -1)).toThrowError();
expect(() => vec3Parameter.add1fAt(1, 10000)).toThrowError();
const val = Math.random() * 200 - 100;
vec3Parameter.fill1f(val, 0, vec3Parameter.capacity);
const randomIndex = Math.floor(Math.random() * vec3Parameter.capacity);
const x = Math.random();
vec3Parameter.add1fAt(x, randomIndex);
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.getVec3At(vec3, i);
if (i === randomIndex) {
expect(vec3.x).toBeCloseTo(x + val, 4);
expect(vec3.y).toBeCloseTo(x + val, 4);
expect(vec3.z).toBeCloseTo(x + val, 4);
} else {
expect(vec3.x).toBeCloseTo(val, 4);
expect(vec3.y).toBeCloseTo(val, 4);
expect(vec3.z).toBeCloseTo(val, 4);
}
}
const val2 = Math.random() * 200 - 100;
vec3Parameter.fill1f(val2, 0, vec3Parameter.capacity);
const randomStream = new RandomStream(Math.random() * 10000);
const randomStream2 = new RandomStream(randomStream.seed);
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.add1fAt(randomStream.getSignedFloat(), i);
}
for (let i = 0; i < vec3Parameter.capacity; i++) {
vec3Parameter.getVec3At(vec3, i);
const random = randomStream2.getSignedFloat();
expect(vec3.x).toBeCloseTo(random + val2, 4);
expect(vec3.y).toBeCloseTo(random + val2, 4);
expect(vec3.z).toBeCloseTo(random + val2, 4);
}
})
});

describe('ParticleFloatArrayParameter', () => {
Expand Down

0 comments on commit 07c7419

Please sign in to comment.