UNPKG

ng-cw-v12

Version:

Angular UI Component Library

382 lines (363 loc) 17 kB
import * as i0 from '@angular/core'; import { Component, ViewChild, Input, NgModule } from '@angular/core'; import * as THREE from 'three'; import { CommonModule } from '@angular/common'; // ─── 着色器代码 ───────────────────────────────────────────────────────────── const vertex = ` varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 1.0); } `; const fragment = ` precision highp float; uniform vec2 iResolution; uniform float iTime; uniform float uTimeSpeed; uniform float uColorBalance; uniform float uWarpStrength; uniform float uWarpFrequency; uniform float uWarpSpeed; uniform float uWarpAmplitude; uniform float uBlendAngle; uniform float uBlendSoftness; uniform float uRotationAmount; uniform float uNoiseScale; uniform float uGrainAmount; uniform float uGrainScale; uniform float uGrainAnimated; uniform float uContrast; uniform float uGamma; uniform float uSaturation; uniform vec2 uCenterOffset; uniform float uZoom; uniform vec3 uColor1; uniform vec3 uColor2; uniform vec3 uColor3; #define S(a,b,t) smoothstep(a,b,t) mat2 Rot(float a) { float s = sin(a), c = cos(a); return mat2(c, -s, s, c); } vec2 hash(vec2 p) { p = vec2(dot(p, vec2(2127.1, 81.17)), dot(p, vec2(1269.5, 283.37))); return fract(sin(p) * 43758.5453); } float noise(vec2 p) { vec2 i = floor(p), f = fract(p), u = f * f * (3.0 - 2.0 * f); float n = mix(mix(dot(-1.0 + 2.0 * hash(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)), dot(-1.0 + 2.0 * hash(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x), mix(dot(-1.0 + 2.0 * hash(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)), dot(-1.0 + 2.0 * hash(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y); return 0.5 + 0.5 * n; } void mainImage(out vec4 o, vec2 C) { float t = iTime * uTimeSpeed; vec2 uv = C / iResolution.xy; float ratio = iResolution.x / iResolution.y; vec2 tuv = uv - 0.5 + uCenterOffset; tuv /= max(uZoom, 0.001); float degree = noise(vec2(t * 0.1, tuv.x * tuv.y) * uNoiseScale); tuv.y *= 1.0 / ratio; tuv *= Rot(radians((degree - 0.5) * uRotationAmount + 180.0)); tuv.y *= ratio; float frequency = uWarpFrequency; float ws = max(uWarpStrength, 0.001); float amplitude = uWarpAmplitude / ws; float warpTime = t * uWarpSpeed; tuv.x += sin(tuv.y * frequency + warpTime) / amplitude; tuv.y += sin(tuv.x * (frequency * 1.5) + warpTime) / (amplitude * 0.5); vec3 colLav = uColor1; vec3 colOrg = uColor2; vec3 colDark = uColor3; float b = uColorBalance; float s = max(uBlendSoftness, 0.0); mat2 blendRot = Rot(radians(uBlendAngle)); float blendX = (tuv * blendRot).x; float edge0 = -0.3 - b - s; float edge1 = 0.2 - b + s; float v0 = 0.5 - b + s; float v1 = -0.3 - b - s; vec3 layer1 = mix(colDark, colOrg, S(edge0, edge1, blendX)); vec3 layer2 = mix(colOrg, colLav, S(edge0, edge1, blendX)); vec3 col = mix(layer1, layer2, S(v0, v1, tuv.y)); vec2 grainUv = uv * max(uGrainScale, 0.001); if (uGrainAnimated > 0.5) { grainUv += vec2(iTime * 0.05); } float grain = fract(sin(dot(grainUv, vec2(12.9898, 78.233))) * 43758.5453); col += (grain - 0.5) * uGrainAmount; col = (col - 0.5) * uContrast + 0.5; float luma = dot(col, vec3(0.2126, 0.7152, 0.0722)); col = mix(vec3(luma), col, uSaturation); col = pow(max(col, 0.0), vec3(1.0 / max(uGamma, 0.001))); col = clamp(col, 0.0, 1.0); o = vec4(col, 1.0); } void main() { mainImage(gl_FragColor, gl_FragCoord.xy); } `; class GrainientBackgroundComponent { constructor(ngZone) { this.ngZone = ngZone; /** 渐变混合中使用的主色(十六进制字符串) */ this.ncColor1 = '#FF9FFC'; /** 渐变混合中使用的辅助强调色(十六进制字符串) */ this.ncColor2 = '#5227FF'; /** 渐变混合中使用了深色底色(十六进制字符串) */ this.ncColor3 = '#B19EEF'; /** 渐变动画的速度倍增器(0-5) */ this.ncTimeSpeed = 0.25; /** 将色调平衡向深色或浅色方向调整(-1.0 到 1.0) */ this.ncColorBalance = 0.0; /** 波扭曲变形强度(0-4) */ this.ncWarpStrength = 1.0; /** 波的弯曲频率(0-12) */ this.ncWarpFrequency = 5.0; /** 弯曲动画的速度倍率(0-6)*/ this.ncWarpSpeed = 2.0; /** 扭曲变形的基准振幅(5-80) */ this.ncWarpAmplitude = 50.0; /** 颜色混合轴的旋转角度(deg -180-180) */ this.ncBlendAngle = 0.0; /** 柔化颜色图层之间的过渡边缘(0-0.4) */ this.ncBlendSoftness = 0.05; /** 旋转量受噪声驱动(0-1440) */ this.ncRotationAmount = 500.0; /** 调整驱动旋转的噪声频率(0-4) */ this.ncNoiseScale = 2.0; /** 颗粒感强度(0-0.4) */ this.ncGrainAmount = 0.1; /** 颗粒感尺度(0.2-8) */ this.ncGrainScale = 2.0; /** 让谷物随时间变化呈现动画效果 */ this._grainAnimated = false; /** 对最终颜色进行整体对比度调整(0-2.5) */ this.ncContrast = 1.5; /** 最终颜色的伽马校正(0.4-2.5) */ this.ncGamma = 1.0; /** 最终颜色的饱和度(0-2.5) */ this.ncSaturation = 1.0; /** 渐变中心的水平偏移量(-1-1) */ this.ncCenterX = 0.0; /** 渐变中心垂直偏移量(-1-1) */ this.ncCenterY = 0.0; /** 渐变场的缩放级别(0.3-3) */ this.ncZoom = 0.9; this.time0 = performance.now(); this.rafId = null; } set ncGrainAnimated(val) { this._grainAnimated = val !== null && val !== undefined && val !== false && val !== 'false'; } get ncGrainAnimated() { return this._grainAnimated; } ngOnInit() { } ngAfterViewInit() { this.ngZone.runOutsideAngular(() => { this.initScene(); this.setupResizeObserver(); this.animate(); }); } ngOnDestroy() { if (this.rafId) cancelAnimationFrame(this.rafId); if (this.resizeObserver) this.resizeObserver.disconnect(); if (this.renderer) { this.renderer.dispose(); this.renderer.forceContextLoss(); this.renderer.domElement.remove(); } } ngOnChanges(changes) { if (!this.material) return; this.updateUniforms(); } initScene() { const container = this.containerRef.nativeElement; const { width, height } = container.getBoundingClientRect(); this.renderer = new THREE.WebGLRenderer({ antialias: false, alpha: true }); this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)); this.renderer.setSize(width || 1, height || 1); container.appendChild(this.renderer.domElement); this.scene = new THREE.Scene(); this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); const geometry = new THREE.PlaneGeometry(2, 2); this.material = new THREE.ShaderMaterial({ vertexShader: vertex, fragmentShader: fragment, uniforms: { iTime: { value: 0 }, iResolution: { value: new THREE.Vector2(width, height) }, uTimeSpeed: { value: this.ncTimeSpeed }, uColorBalance: { value: this.ncColorBalance }, uWarpStrength: { value: this.ncWarpStrength }, uWarpFrequency: { value: this.ncWarpFrequency }, uWarpSpeed: { value: this.ncWarpSpeed }, uWarpAmplitude: { value: this.ncWarpAmplitude }, uBlendAngle: { value: this.ncBlendAngle }, uBlendSoftness: { value: this.ncBlendSoftness }, uRotationAmount: { value: this.ncRotationAmount }, uNoiseScale: { value: this.ncNoiseScale }, uGrainAmount: { value: this.ncGrainAmount }, uGrainScale: { value: this.ncGrainScale }, uGrainAnimated: { value: this.ncGrainAnimated ? 1.0 : 0.0 }, uContrast: { value: this.ncContrast }, uGamma: { value: this.ncGamma }, uSaturation: { value: this.ncSaturation }, uCenterOffset: { value: new THREE.Vector2(this.ncCenterX, this.ncCenterY) }, uZoom: { value: this.ncZoom }, uColor1: { value: new Float32Array(this.hexToRgb(this.ncColor1)) }, uColor2: { value: new Float32Array(this.hexToRgb(this.ncColor2)) }, uColor3: { value: new Float32Array(this.hexToRgb(this.ncColor3)) } } }); this.mesh = new THREE.Mesh(geometry, this.material); this.scene.add(this.mesh); } updateUniforms() { const u = this.material.uniforms; u['uTimeSpeed'].value = this.ncTimeSpeed; u['uColorBalance'].value = this.ncColorBalance; u['uWarpStrength'].value = this.ncWarpStrength; u['uWarpFrequency'].value = this.ncWarpFrequency; u['uWarpSpeed'].value = this.ncWarpSpeed; u['uWarpAmplitude'].value = this.ncWarpAmplitude; u['uBlendAngle'].value = this.ncBlendAngle; u['uBlendSoftness'].value = this.ncBlendSoftness; u['uRotationAmount'].value = this.ncRotationAmount; u['uNoiseScale'].value = this.ncNoiseScale; u['uGrainAmount'].value = this.ncGrainAmount; u['uGrainScale'].value = this.ncGrainScale; u['uGrainAnimated'].value = this.ncGrainAnimated ? 1.0 : 0.0; u['uContrast'].value = this.ncContrast; u['uGamma'].value = this.ncGamma; u['uSaturation'].value = this.ncSaturation; u['uCenterOffset'].value.set(this.ncCenterX, this.ncCenterY); u['uZoom'].value = this.ncZoom; u['uColor1'].value = new Float32Array(this.hexToRgb(this.ncColor1)); u['uColor2'].value = new Float32Array(this.hexToRgb(this.ncColor2)); u['uColor3'].value = new Float32Array(this.hexToRgb(this.ncColor3)); } hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); if (!result) return [1, 1, 1]; return [parseInt(result[1], 16) / 255, parseInt(result[2], 16) / 255, parseInt(result[3], 16) / 255]; } setupResizeObserver() { this.resizeObserver = new ResizeObserver(() => { this.ngZone.runOutsideAngular(() => { this.onResize(); }); }); this.resizeObserver.observe(this.containerRef.nativeElement); } onResize() { const container = this.containerRef.nativeElement; const { width, height } = container.getBoundingClientRect(); if (width === 0 || height === 0) return; this.renderer.setSize(width, height); this.material.uniforms['iResolution'].value.set(width, height); } animate() { this.rafId = requestAnimationFrame((t) => { this.animate(); this.render(t); }); } render(t) { this.material.uniforms['iTime'].value = (t - this.time0) * 0.001; this.renderer.render(this.scene, this.camera); } } GrainientBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: GrainientBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); GrainientBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: GrainientBackgroundComponent, selector: "nc-grainient-background", inputs: { ncColor1: "ncColor1", ncColor2: "ncColor2", ncColor3: "ncColor3", ncTimeSpeed: "ncTimeSpeed", ncColorBalance: "ncColorBalance", ncWarpStrength: "ncWarpStrength", ncWarpFrequency: "ncWarpFrequency", ncWarpSpeed: "ncWarpSpeed", ncWarpAmplitude: "ncWarpAmplitude", ncBlendAngle: "ncBlendAngle", ncBlendSoftness: "ncBlendSoftness", ncRotationAmount: "ncRotationAmount", ncNoiseScale: "ncNoiseScale", ncGrainAmount: "ncGrainAmount", ncGrainScale: "ncGrainScale", ncGrainAnimated: "ncGrainAnimated", ncContrast: "ncContrast", ncGamma: "ncGamma", ncSaturation: "ncSaturation", ncCenterX: "ncCenterX", ncCenterY: "ncCenterY", ncZoom: "ncZoom" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #container class=\"nc-grainient-canvas-container\"></div>\r\n<div class=\"nc-content-wrapper\">\r\n <ng-content></ng-content>\r\n</div>", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden}.nc-grainient-canvas-container{position:absolute;inset:0;z-index:0}.nc-content-wrapper{position:relative;z-index:1;width:100%;height:100%}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: GrainientBackgroundComponent, decorators: [{ type: Component, args: [{ selector: 'nc-grainient-background', templateUrl: './grainient-background.component.html', styleUrls: ['./grainient-background.component.less'] }] }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { containerRef: [{ type: ViewChild, args: ['container', { static: true }] }], ncColor1: [{ type: Input }], ncColor2: [{ type: Input }], ncColor3: [{ type: Input }], ncTimeSpeed: [{ type: Input }], ncColorBalance: [{ type: Input }], ncWarpStrength: [{ type: Input }], ncWarpFrequency: [{ type: Input }], ncWarpSpeed: [{ type: Input }], ncWarpAmplitude: [{ type: Input }], ncBlendAngle: [{ type: Input }], ncBlendSoftness: [{ type: Input }], ncRotationAmount: [{ type: Input }], ncNoiseScale: [{ type: Input }], ncGrainAmount: [{ type: Input }], ncGrainScale: [{ type: Input }], ncGrainAnimated: [{ type: Input }], ncContrast: [{ type: Input }], ncGamma: [{ type: Input }], ncSaturation: [{ type: Input }], ncCenterX: [{ type: Input }], ncCenterY: [{ type: Input }], ncZoom: [{ type: Input }] } }); class NcGrainientBackgroundModule { } NcGrainientBackgroundModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NcGrainientBackgroundModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, declarations: [GrainientBackgroundComponent], imports: [CommonModule], exports: [GrainientBackgroundComponent] }); NcGrainientBackgroundModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, imports: [[ CommonModule ]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, decorators: [{ type: NgModule, args: [{ declarations: [ GrainientBackgroundComponent ], imports: [ CommonModule ], exports: [ GrainientBackgroundComponent ] }] }] }); /** * Generated bundle index. Do not edit. */ export { GrainientBackgroundComponent, NcGrainientBackgroundModule }; //# sourceMappingURL=ng-cw-v12-grainient-background.js.map