Skip to content

Instantly share code, notes, and snippets.

@wonglok
Created October 12, 2020 05:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wonglok/7f76f00a6068c7999a24952f868a01b6 to your computer and use it in GitHub Desktop.
Save wonglok/7f76f00a6068c7999a24952f868a01b6 to your computer and use it in GitHub Desktop.
Action Magic
import { Clock, Euler, Points, Quaternion, ShaderMaterial, SphereBufferGeometry, Vector3, Vector4 } from "three"
let glsl = (v, ...args) => {
let str = ''
v.forEach((e, i) => {
str += e + (args[i] || '')
})
return str
}
class ValueDamper {
constructor (v = 0, ctx) {
// this.minY = limit.ny,
// this.maxY = limit.y
this.latestVal = v
this.dampedVal = v
this.diff = 0
this.clock = new Clock()
ctx.onLoop(() => {
this.deltaInterval = this.clock.getDelta()
this.diff = (this.latestVal - this.dampedVal) * (this.deltaInterval * 1000 / 60 * 0.25)
this.dampedVal += this.diff
})
}
set value (v) {
this.latestVal = v
}
get value () {
return this.dampedVal
}
get now () {
return this.latestVal
}
}
export class Ball {
constructor ({ o3d, ctx }) {
let geo = new SphereBufferGeometry(90, 42, 42)
let uniforms = {
time: { value: 0 },
diffuse: { value: new Vector4(0,0,0,1.0) },
ptSize: { value: 5.0 },
}
let mat = new ShaderMaterial({
uniforms,
transparent: true,
vertexShader: glsl`
uniform float ptSize;
varying vec2 vUv;
void main (void) {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xyz, 1.0);
gl_PointSize = ptSize;
}
`,
fragmentShader: glsl`
varying vec2 vUv;
uniform vec4 diffuse;
uniform float time;
const mat2 m = mat2(0.80, 0.60, -0.60, 0.80);
float noise(in vec2 p) {
return sin(p.x)*sin(p.y);
}
float fbm4( vec2 p ) {
float f = 0.0;
f += 0.5000 * noise( p ); p = m * p * 2.02;
f += 0.2500 * noise( p ); p = m * p * 2.03;
f += 0.1250 * noise( p ); p = m * p * 2.01;
f += 0.0625 * noise( p );
return f / 0.9375;
}
float fbm6( vec2 p ) {
float f = 0.0;
f += 0.500000*(0.5+0.5*noise( p )); p = m*p*2.02;
f += 0.250000*(0.5+0.5*noise( p )); p = m*p*2.03;
f += 0.125000*(0.5+0.5*noise( p )); p = m*p*2.01;
f += 0.062500*(0.5+0.5*noise( p )); p = m*p*2.04;
f += 0.031250*(0.5+0.5*noise( p )); p = m*p*2.01;
f += 0.015625*(0.5+0.5*noise( p ));
return f/0.96875;
}
float pattern (vec2 p, float time) {
float vout = fbm4( p + time + fbm6( p + fbm4( p + time )) );
return abs(vout);
}
void main (void) {
if (length(gl_PointCoord.xy - 0.5) > 0.5) {
discard;
} else {
vec3 patternColor = vec3(
1.0 - pattern(vec2(vUv * 5.0 + time * 5.0) + diffuse.x * 1.0 * cos(time * 0.15), time),
1.0 - pattern(vec2(vUv * 5.0 + time * 5.0) + diffuse.y * 1.0 * cos(time * 0.15), time),
1.0 - pattern(vec2(vUv * 5.0 + time * 5.0) + diffuse.z * 1.0 * cos(time * 0.15), time)
);
gl_FragColor = vec4(patternColor, 1.0);
}
}
`
})
let drawable = new Points(geo, mat)
this.drawable = drawable
this.scale = drawable.scale
this.rotation = drawable.rotation
o3d.add(drawable)
ctx.onLoop(() => {
uniforms.time.value = window.performance.now() * 1 / 1000
})
this.set = new Proxy(this, {
get: (obj, key) => {
// return obj[key]
if (key === '$vm') {
return obj
}
if (key === 'scale') {
return drawable.scale
}
if (uniforms[key]) {
return uniforms[key].value
}
},
set: (obj, key, value) => {
if (uniforms[key]) {
uniforms[key].value = value
}
return true
}
})
}
}
export class AreaAttack {
constructor ({ character, ctx, o3d }) {
this.o3d = o3d
this.character = character
this.bones = {}
this.character.actor.traverse(e => {
if (e.isBone) {
this.bones[e.name] = e
}
})
// console.log(this.bones)
let vfx = new Ball({ o3d: this.bones.mixamorigHips, ctx })
let damperRotation = new ValueDamper(0.25, ctx)
let leftHand = new Vector3()
let rightHand = new Vector3()
let head = new Quaternion()
let headEuler = new Euler()
ctx.onLoop(() => {
this.bones.mixamorigHead.getWorldQuaternion(head)
headEuler.setFromQuaternion(head)
this.bones.mixamorigLeftHand.getWorldPosition(leftHand)
this.bones.mixamorigRightHand.getWorldPosition(rightHand)
let distanceTo = leftHand.distanceTo(rightHand)
let righthandMiddleRotation = this.bones.mixamorigRightHandMiddle2.rotation.x
let headY = headEuler.y
let scale = 0.5 + distanceTo / 7
vfx.scale.set(
scale,
scale,
scale
)
damperRotation.value = righthandMiddleRotation * 0.5
vfx.rotation.y = damperRotation.value
vfx.set.diffuse
.copy(this.bones.mixamorigHips.quaternion)
vfx.set.diffuse.w = 1.0
vfx.set.ptSize = 5.0 + ((headY)) * 15.0
if (vfx.set.ptSize >= 10.0) {
vfx.set.ptSize = 10.0
}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment