From 350f84acb395e77e58770cc3c13b8b90807b0738 Mon Sep 17 00:00:00 2001 From: FMS-Cat Date: Mon, 15 Mar 2021 01:39:25 +0900 Subject: [PATCH] feature: add a cube --- src/entities/Cube.ts | 85 +++++++++++++++++++++++++++++++++++++++ src/geometries/genCube.ts | 81 +++++++++++++++++++++++++++++++++++++ src/main.ts | 16 +++++--- src/shaders/cube.frag | 41 +++++++++++++++++++ src/shaders/cube.vert | 32 +++++++++++++++ 5 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 src/entities/Cube.ts create mode 100644 src/geometries/genCube.ts create mode 100644 src/shaders/cube.frag create mode 100644 src/shaders/cube.vert diff --git a/src/entities/Cube.ts b/src/entities/Cube.ts new file mode 100644 index 0000000..6cf3978 --- /dev/null +++ b/src/entities/Cube.ts @@ -0,0 +1,85 @@ +import { Quaternion, Vector3 } from '@fms-cat/experimental'; +import { Mesh } from '../heck/components/Mesh'; +import { Entity } from '../heck/Entity'; +import { Geometry } from '../heck/Geometry'; +import { Material } from '../heck/Material'; +import cubeVert from '../shaders/cube.vert'; +import cubeFrag from '../shaders/cube.frag'; +import { genCube } from '../geometries/genCube'; +import { Lambda } from '../heck/components/Lambda'; + +export class Cube { + public mesh: Mesh; + public geometry: Geometry; + public material: Material; + public entity: Entity; + + public constructor() { + this.entity = new Entity(); + + this.entity.transform.rotation = Quaternion.fromAxisAngle( + new Vector3( [ 1.0, 0.0, 0.0 ] ), + 0.4, + ).multiply( Quaternion.fromAxisAngle( + new Vector3( [ 0.0, 0.0, 1.0 ] ), + 0.4, + ) ); + this.entity.transform.scale = this.entity.transform.scale.scale( 0.8 ); + + this.geometry = this.__createGeometry(); + this.material = this.__createMaterial(); + + this.mesh = new Mesh( { + geometry: this.geometry, + material: this.material, + name: process.env.DEV && 'Cube/mesh', + } ); + this.entity.components.push( this.mesh ); + + this.entity.components.push( new Lambda( { + onUpdate: ( { deltaTime } ) => { + this.entity.transform.rotation = this.entity.transform.rotation.multiply( + Quaternion.fromAxisAngle( new Vector3( [ 0.0, 1.0, 0.0 ] ), deltaTime ) + ); + }, + visible: false, + } ) ); + } + + private __createGeometry(): Geometry { + const cube = genCube(); + + const geometry = new Geometry(); + + geometry.addAttribute( 'position', cube.position ); + geometry.addAttribute( 'normal', cube.normal ); + geometry.setIndex( cube.index ); + + geometry.count = cube.count; + geometry.mode = cube.mode; + + return geometry; + } + + private __createMaterial(): Material { + const material = new Material( cubeVert, cubeFrag ); + + material.addUniform( 'inflate', '1f', 0.01 ); + + if ( process.env.DEV ) { + if ( module.hot ) { + module.hot.accept( + [ + '../shaders/cube.vert', + '../shaders/cube.frag', + ], + () => { + material.replaceShader( cubeVert, cubeFrag ); + }, + ); + } + } + + return material; + } +} diff --git a/src/geometries/genCube.ts b/src/geometries/genCube.ts new file mode 100644 index 0000000..81efa4c --- /dev/null +++ b/src/geometries/genCube.ts @@ -0,0 +1,81 @@ +import { gl, glCat } from '../heck/canvas'; +import { GeometryAttribute, GeometryIndex } from '../heck/Geometry'; + +interface ResultGenCube { + position: GeometryAttribute; + normal: GeometryAttribute; + index: GeometryIndex; + count: number; + mode: GLenum; +} + +export function genCube(): ResultGenCube { + const pos: number[] = []; + const nor: number[] = []; + const ind: number[] = []; + + const p = [ + [ -1, -1, 1 ], + [ 1, -1, 1 ], + [ -1, 1, 1 ], + [ 1, 1, 1 ], + ]; + const n = [ + [ 0, 0, 1 ], + [ 0, 0, 1 ], + [ 0, 0, 1 ], + [ 0, 0, 1 ], + ]; + + for ( let i = 0; i < 6; i ++ ) { + let func = ( v: number[] ) => { + const vt: number[] = []; + + if ( i < 4 ) { + const t = i * Math.PI / 2.0; + vt[ 0 ] = Math.cos( t ) * v[ 0 ] - Math.sin( t ) * v[ 2 ]; + vt[ 1 ] = v[ 1 ]; + vt[ 2 ] = Math.sin( t ) * v[ 0 ] + Math.cos( t ) * v[ 2 ]; + } else { + const t = ( i - 0.5 ) * Math.PI; + vt[ 0 ] = v[ 0 ]; + vt[ 1 ] = Math.cos( t ) * v[ 1 ] - Math.sin( t ) * v[ 2 ]; + vt[ 2 ] = Math.sin( t ) * v[ 1 ] + Math.cos( t ) * v[ 2 ]; + } + + return vt; + }; + + pos.push( ...p.map( func ).flat() ); + nor.push( ...n.map( func ).flat() ); + ind.push( ...[ 0, 1, 3, 0, 3, 2 ].map( ( v ) => v + 4 * i ) ); + } + + const position: GeometryAttribute = { + buffer: glCat.createBuffer(), + type: gl.FLOAT, + size: 3 + }; + position.buffer.setVertexbuffer( new Float32Array( pos ) ); + + const normal: GeometryAttribute = { + buffer: glCat.createBuffer(), + type: gl.FLOAT, + size: 3 + }; + normal.buffer.setVertexbuffer( new Float32Array( nor ) ); + + const index: GeometryIndex = { + buffer: glCat.createBuffer(), + type: gl.UNSIGNED_SHORT + }; + index.buffer.setIndexbuffer( new Uint16Array( ind ) ); + + return { + position, + normal, + index, + count: ind.length, + mode: gl.TRIANGLES + }; +} diff --git a/src/main.ts b/src/main.ts index 5bd7edd..4e63bcc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,6 +26,7 @@ import { FlickyParticles } from './entities/FlickyParticles'; import { PixelSorter } from './entities/PixelSorter'; import { IBLLUT } from './entities/IBLLUT'; import { EnvironmentMap } from './entities/EnvironmentMap'; +import { Cube } from './entities/Cube'; // == music ======================================================================================== const audio = new AudioContext(); @@ -203,12 +204,12 @@ const environmentMap = new EnvironmentMap(); dog.root.children.push( environmentMap.entity ); // -- "objects" ------------------------------------------------------------------------------------ -const sphereParticles = new SphereParticles( { - particlesSqrt: 256, - textureRandom: randomTexture.texture, - textureRandomStatic: randomTextureStatic.texture -} ); -dog.root.children.push( sphereParticles.entity ); +// const sphereParticles = new SphereParticles( { +// particlesSqrt: 256, +// textureRandom: randomTexture.texture, +// textureRandomStatic: randomTextureStatic.texture +// } ); +// dog.root.children.push( sphereParticles.entity ); // const trails = new Trails( { // trails: 4096, @@ -221,6 +222,9 @@ dog.root.children.push( sphereParticles.entity ); const rings = new Rings(); dog.root.children.push( rings.entity ); +const cube = new Cube(); +dog.root.children.push( cube.entity ); + const flickyParticles = new FlickyParticles( { particlesSqrt: 8, textureRandom: randomTexture.texture, diff --git a/src/shaders/cube.frag b/src/shaders/cube.frag new file mode 100644 index 0000000..1f02dd0 --- /dev/null +++ b/src/shaders/cube.frag @@ -0,0 +1,41 @@ +#version 300 es + +precision highp float; + +const int MTL_PBR = 2; + +in float vLife; +in vec3 vNormal; +in vec4 vPosition; +in vec4 vPositionWithoutModel; + +layout (location = 0) out vec4 fragPosition; +layout (location = 1) out vec4 fragNormal; +layout (location = 2) out vec4 fragColor; +layout (location = 3) out vec4 fragWTF; + +#pragma glslify: noise = require( ./-simplex4d ); + +uniform float time; + +float fbm( vec4 p ) { + float v = 0.5 * noise( 1.0 * p ); + v += 0.25 * noise( 2.0 * p ); + v += 0.125 * noise( 4.0 * p ); + v += 0.0625 * noise( 8.0 * p ); + return v; +} + +void main() { + float rough = smoothstep( -0.6, 0.6, fbm( vPositionWithoutModel ) ); + // vec3 ndisp = rough * 0.2 * vec3( + // fbm( 1.577 + 4.0 * vPosition ), + // fbm( 12.577 + 4.0 * vPosition ), + // fbm( 27.577 + 4.0 * vPosition ) + // ); + + fragPosition = vPosition; + fragNormal = vec4( normalize( vNormal ), 1.0 ); + fragColor = vec4( vec3( 0.5 - 0.3 * rough ), 1.0 ); + fragWTF = vec4( vec3( 0.3 + 0.2 * rough, 0.9, 0.0 ), MTL_PBR ); +} diff --git a/src/shaders/cube.vert b/src/shaders/cube.vert new file mode 100644 index 0000000..aa61f5b --- /dev/null +++ b/src/shaders/cube.vert @@ -0,0 +1,32 @@ +#version 300 es + +in vec3 position; +in vec3 normal; +in vec2 uv; + +out vec4 vPositionWithoutModel; +out vec4 vPosition; +out vec3 vNormal; +out vec2 vUv; + +uniform vec2 resolution; +uniform mat4 projectionMatrix; +uniform mat4 viewMatrix; +uniform mat4 modelMatrix; +uniform mat4 normalMatrix; + +// ------ + +void main() { + vNormal = normalize( ( normalMatrix * vec4( normal, 1.0 ) ).xyz ); + + vPositionWithoutModel = vec4( position, 1.0 ); + vPosition = modelMatrix * vPositionWithoutModel; + vec4 outPos = projectionMatrix * viewMatrix * vPosition; + outPos.x *= resolution.y / resolution.x; + gl_Position = outPos; + + vPosition.w = outPos.z / outPos.w; + + vUv = uv; +}