feature: instanced condition

This commit is contained in:
FMS-Cat
2021-03-25 02:57:55 +09:00
parent cb012552b2
commit c3e4c6e5a1
4 changed files with 186 additions and 53 deletions

View File

@@ -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 );
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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 );