mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-07 14:36:28 +02:00
feature: instanced condition
This commit is contained in:
@@ -1,39 +1,167 @@
|
||||
import { Vector3 } from '@fms-cat/experimental';
|
||||
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||
import { gl, glCat } from '../globals/canvas';
|
||||
import { Entity } from '../heck/Entity';
|
||||
import { InstancedGeometry } from '../heck/InstancedGeometry';
|
||||
import { createSVGTableTexture } from '../utils/createSVGTableTexture';
|
||||
import { ConditionChar } from './ConditionChar';
|
||||
import conditionVert from '../shaders/condition.vert';
|
||||
import conditionFrag from '../shaders/condition.frag';
|
||||
import { Material } from '../heck/Material';
|
||||
import { dummyRenderTargetFourDrawBuffers, dummyRenderTargetOneDrawBuffers } from '../globals/dummyRenderTarget';
|
||||
import { Mesh } from '../heck/components/Mesh';
|
||||
import { auto } from '../globals/automaton';
|
||||
|
||||
const POINTS_MAX = 256;
|
||||
|
||||
export class Condition extends Entity {
|
||||
public constructor() {
|
||||
super();
|
||||
this.transform.scale = new Vector3( [ 0.05, 0.05, 0.05 ] );
|
||||
|
||||
const pathC = createSVGTableTexture( 'M5,5l-9,0l-1,-1l0,-8l1,-1l9,0l0,2l-8,0l0,6l8,0Z' );
|
||||
const pathO = createSVGTableTexture( 'M5,4l0,-8l-1,-1l-8,0l-1,1l0,8l1,1l8,0Z' );
|
||||
const pathOi = createSVGTableTexture( 'M3,3l0,-6l-6,0l0,6Z' );
|
||||
const pathN = createSVGTableTexture( 'M5,4l0,-9l-2,0l0,8l-6,0l0,-8l-2,0l0,9l1,1l8,0Z' );
|
||||
const pathD = createSVGTableTexture( 'M5,4l0,-8l-1,-1l-9,0l0,10l9,0Z' );
|
||||
const pathI = createSVGTableTexture( 'M1,5l0,-10l-2,0l0,10Z' );
|
||||
const pathT = createSVGTableTexture( 'M5,5l0,-2l-4,0l0,-8l-2,0l0,8l-4,0l0,2Z' );
|
||||
// -- paths ------------------------------------------------------------------------------------
|
||||
const texture = createSVGTableTexture( [
|
||||
'M5,5l-9,0l-1,-1l0,-8l1,-1l9,0l0,2l-8,0l0,6l8,0Z',
|
||||
'M5,4l0,-8l-1,-1l-8,0l-1,1l0,8l1,1l8,0Z',
|
||||
'M3,3l0,-6l-6,0l0,6Z',
|
||||
'M5,4l0,-9l-2,0l0,8l-6,0l0,-8l-2,0l0,9l1,1l8,0Z',
|
||||
'M5,4l0,-8l-1,-1l-9,0l0,10l9,0Z',
|
||||
'M1,5l0,-10l-2,0l0,10Z',
|
||||
'M5,5l0,-2l-4,0l0,-8l-2,0l0,8l-4,0l0,2Z',
|
||||
] );
|
||||
|
||||
const tableAndPos: [ GLCatTexture, number ][] = [
|
||||
[ pathC, -20 ],
|
||||
[ pathO, -14 ],
|
||||
[ pathOi, -14 ],
|
||||
[ pathN, -8 ],
|
||||
[ pathD, -2 ],
|
||||
[ pathOi, -2 ],
|
||||
[ pathI, 2 ],
|
||||
[ pathT, 6 ],
|
||||
[ pathI, 10 ],
|
||||
[ pathO, 14 ],
|
||||
[ pathOi, 14 ],
|
||||
[ pathN, 20 ],
|
||||
const tablePos: number[] = [
|
||||
0, -40,
|
||||
1, -28,
|
||||
2, -28,
|
||||
3, -16,
|
||||
4, -4,
|
||||
2, -4,
|
||||
5, 4,
|
||||
6, 12,
|
||||
5, 20,
|
||||
1, 28,
|
||||
2, 28,
|
||||
3, 40,
|
||||
];
|
||||
tableAndPos.forEach( ( [ table, pos ], i ) => {
|
||||
const svgEntity = new ConditionChar( { table, pos, i } );
|
||||
this.children.push( svgEntity );
|
||||
|
||||
// -- create buffers ---------------------------------------------------------------------------
|
||||
const arrayPos = [];
|
||||
const arrayInd = [];
|
||||
|
||||
for ( let i = 0; i < POINTS_MAX; i ++ ) {
|
||||
const x = i / POINTS_MAX;
|
||||
arrayPos.push( x, 0, x, 1, x, 2 );
|
||||
|
||||
for ( let j = 0; j < 3; j ++ ) {
|
||||
const j1 = ( j + 1 ) % 3;
|
||||
arrayInd.push(
|
||||
i * 3 + j,
|
||||
i * 3 + 3 + j,
|
||||
i * 3 + 3 + j1,
|
||||
i * 3 + j,
|
||||
i * 3 + 3 + j1,
|
||||
i * 3 + j1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
arrayPos.push( 1, 0, 1, 1, 1, 2 );
|
||||
|
||||
const bufferPos = glCat.createBuffer();
|
||||
bufferPos.setVertexbuffer( new Float32Array( arrayPos ) );
|
||||
|
||||
const bufferInd = glCat.createBuffer();
|
||||
bufferInd.setIndexbuffer( new Uint16Array( arrayInd ) );
|
||||
|
||||
const arrayIter: number[] = [];
|
||||
|
||||
for ( let i = 0; i < 16; i ++ ) {
|
||||
for ( let j = 0; j < 12; j ++ ) {
|
||||
arrayIter.push(
|
||||
( tablePos[ j * 2 + 0 ] + 0.5 ) / 7.0,
|
||||
tablePos[ j * 2 + 1 ],
|
||||
i,
|
||||
j,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const bufferIter = glCat.createBuffer();
|
||||
bufferIter.setVertexbuffer( new Float32Array( arrayIter ) );
|
||||
|
||||
// -- create geometry --------------------------------------------------------------------------
|
||||
const geometry = new InstancedGeometry();
|
||||
|
||||
geometry.vao.bindVertexbuffer( bufferPos, 0, 2 );
|
||||
geometry.vao.bindIndexbuffer( bufferInd );
|
||||
geometry.vao.bindVertexbuffer( bufferIter, 1, 4, 1 );
|
||||
|
||||
geometry.count = 18 * POINTS_MAX;
|
||||
geometry.mode = gl.TRIANGLES;
|
||||
geometry.indexType = gl.UNSIGNED_SHORT;
|
||||
geometry.primcount = 12 * 16;
|
||||
|
||||
// -- create materials -------------------------------------------------------------------------
|
||||
const materials = {
|
||||
forward: new Material(
|
||||
conditionVert,
|
||||
conditionFrag,
|
||||
{
|
||||
defines: { 'FORWARD': 'true' },
|
||||
initOptions: { geometry, target: dummyRenderTargetOneDrawBuffers },
|
||||
},
|
||||
),
|
||||
deferred: new Material(
|
||||
conditionVert,
|
||||
conditionFrag,
|
||||
{
|
||||
defines: { 'DEFERRED': 'true' },
|
||||
initOptions: { geometry, target: dummyRenderTargetFourDrawBuffers },
|
||||
},
|
||||
),
|
||||
shadow: new Material(
|
||||
conditionVert,
|
||||
conditionFrag,
|
||||
{
|
||||
defines: { 'SHADOW': 'true' },
|
||||
initOptions: { geometry, target: dummyRenderTargetOneDrawBuffers },
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
for ( const material of Object.values( materials ) ) {
|
||||
material.addUniformTexture( 'samplerSvg', texture );
|
||||
|
||||
auto( 'Condition/phaseOffset', ( { value } ) => {
|
||||
material.addUniform( 'phaseOffset', '1f', value );
|
||||
} );
|
||||
|
||||
auto( 'Condition/phaseWidth', ( { value } ) => {
|
||||
material.addUniform( 'phaseWidth', '1f', value );
|
||||
} );
|
||||
}
|
||||
|
||||
if ( process.env.DEV ) {
|
||||
if ( module.hot ) {
|
||||
module.hot.accept(
|
||||
[
|
||||
'../shaders/condition.vert',
|
||||
'../shaders/condition.frag',
|
||||
],
|
||||
() => {
|
||||
materials.forward.replaceShader( conditionVert, conditionFrag );
|
||||
materials.deferred.replaceShader( conditionVert, conditionFrag );
|
||||
materials.shadow.replaceShader( conditionVert, conditionFrag );
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// -- create meshes ----------------------------------------------------------------------------
|
||||
const mesh = new Mesh( {
|
||||
geometry,
|
||||
materials,
|
||||
name: process.env.DEV && `Condition/mesh`,
|
||||
} );
|
||||
this.components.push( mesh );
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ const int MTL_UNLIT = 1;
|
||||
in float vPhase;
|
||||
in vec3 vNormal;
|
||||
in vec4 vPosition;
|
||||
in vec4 vHuh;
|
||||
|
||||
#ifdef FORWARD
|
||||
out vec4 fragColor;
|
||||
@@ -30,22 +31,23 @@ in vec4 vPosition;
|
||||
#endif
|
||||
|
||||
uniform float time;
|
||||
uniform float svgi;
|
||||
uniform float phaseOffset;
|
||||
uniform float phaseWidth;
|
||||
|
||||
void main() {
|
||||
float phase = fract( 2.0 * vPhase + 0.1 * time + 0.1 * svgi + phaseOffset );
|
||||
float phase = fract( 2.0 * vPhase + 0.01 * vHuh.z + 0.1 * time + 0.1 * vHuh.y + phaseOffset );
|
||||
if ( phase > phaseWidth ) { discard; }
|
||||
|
||||
vec3 color = 2.0 * vec3( exp( -0.2 * vHuh.z ) );
|
||||
|
||||
#ifdef FORWARD
|
||||
fragColor = vec4( 1.0 );
|
||||
fragColor = vec4( color, 1.0 );
|
||||
#endif
|
||||
|
||||
#ifdef DEFERRED
|
||||
fragPosition = vPosition;
|
||||
fragNormal = vec4( vNormal, 1.0 );
|
||||
fragColor = vec4( 1.0 );
|
||||
fragColor = vec4( color, 1.0 );
|
||||
fragWTF = vec4( vec3( 0.0, 0.0, 0.0 ), MTL_UNLIT );
|
||||
#endif
|
||||
|
@@ -3,10 +3,12 @@
|
||||
const float TAU = 6.283185307;
|
||||
|
||||
layout (location = 0) in vec2 what;
|
||||
layout (location = 1) in vec4 huh;
|
||||
|
||||
out float vPhase;
|
||||
out vec3 vNormal;
|
||||
out vec4 vPosition;
|
||||
out vec4 vHuh;
|
||||
|
||||
uniform float time;
|
||||
uniform vec2 resolution;
|
||||
@@ -20,9 +22,11 @@ uniform sampler2D samplerSvg;
|
||||
|
||||
void main() {
|
||||
vPhase = what.x;
|
||||
vec4 tex = texture( samplerSvg, vec2( what.x, 0.5 ) );
|
||||
vHuh = huh;
|
||||
|
||||
vPosition = vec4( tex.xy, 0.0, 1.0 );
|
||||
vec4 tex = texture( samplerSvg, vec2( what.x, huh.x ) );
|
||||
|
||||
vPosition = vec4( tex.xy + vec2( huh.y, 0.0 ), 6.0 - 12.0 * huh.z, 1.0 );
|
||||
|
||||
mat3 basis = orthBasis( vec3( tex.zw, 0.0 ) );
|
||||
float theta = what.y / 3.0 * TAU;
|
@@ -1,39 +1,38 @@
|
||||
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||
import { gl, glCat } from '../globals/canvas';
|
||||
|
||||
export function createSVGTableTexture( pathStr: string, width = 1024 ): GLCatTexture {
|
||||
const svgNamespaceURI = 'http://www.w3.org/2000/svg';
|
||||
const path = document.createElementNS( svgNamespaceURI, 'path' );
|
||||
path.setAttribute( 'd', pathStr );
|
||||
export function createSVGTableTexture( pathStrs: string[], width = 1024 ): GLCatTexture {
|
||||
const table: number[] = []; // x, y, dx, dy
|
||||
|
||||
const pathLength = path.getTotalLength();
|
||||
const eps = 0.25 / width * pathLength;
|
||||
pathStrs.map( ( pathStr ) => {
|
||||
const svgNamespaceURI = 'http://www.w3.org/2000/svg';
|
||||
const path = document.createElementNS( svgNamespaceURI, 'path' );
|
||||
path.setAttribute( 'd', pathStr );
|
||||
|
||||
const table = new Float32Array( 4 * width ); // x, y, dx, dy
|
||||
const pathLength = path.getTotalLength();
|
||||
const eps = 0.25 / width * pathLength;
|
||||
|
||||
for ( let i = 0; i < width; i ++ ) {
|
||||
const phase = ( ( i + 0.5 ) / width ) * pathLength;
|
||||
for ( let i = 0; i < width; i ++ ) {
|
||||
const phase = ( ( i + 0.5 ) / width ) * pathLength;
|
||||
|
||||
const point = path.getPointAtLength( phase );
|
||||
const point = path.getPointAtLength( phase );
|
||||
|
||||
const pointdn = path.getPointAtLength( phase - eps );
|
||||
const pointdp = path.getPointAtLength( phase + eps );
|
||||
const pointdn = path.getPointAtLength( phase - eps );
|
||||
const pointdp = path.getPointAtLength( phase + eps );
|
||||
|
||||
const dx = pointdp.x - pointdn.x;
|
||||
const dy = pointdp.y - pointdn.y;
|
||||
const dl = Math.sqrt( dx * dx + dy * dy );
|
||||
const dx = pointdp.x - pointdn.x;
|
||||
const dy = pointdp.y - pointdn.y;
|
||||
const dl = Math.sqrt( dx * dx + dy * dy );
|
||||
|
||||
table[ 4 * i + 0 ] = point.x;
|
||||
table[ 4 * i + 1 ] = point.y;
|
||||
table[ 4 * i + 2 ] = dx / dl;
|
||||
table[ 4 * i + 3 ] = dy / dl;
|
||||
}
|
||||
table.push( point.x, point.y, dx / dl, dy / dl );
|
||||
}
|
||||
} );
|
||||
|
||||
const texture = glCat.createTexture();
|
||||
texture.setTextureFromArray(
|
||||
width,
|
||||
1,
|
||||
table,
|
||||
pathStrs.length,
|
||||
new Float32Array( table ),
|
||||
{ internalformat: gl.RGBA32F, format: gl.RGBA, type: gl.FLOAT },
|
||||
);
|
||||
texture.textureWrap( gl.REPEAT );
|
||||
|
Reference in New Issue
Block a user