import { Material } from "laya/d3/core/material/Material" ; import { RenderState } from "laya/d3/core/material/RenderState" ; import { VertexMesh } from "laya/d3/graphics/Vertex/VertexMesh" ; import { MathUtils3D } from "laya/d3/math/MathUtils3D" ; import { Vector2 } from "laya/d3/math/Vector2" ; import { Vector3 } from "laya/d3/math/Vector3" ; import { Vector4 } from "laya/d3/math/Vector4" ; import { Shader3D } from "laya/d3/shader/Shader3D" ; import { SubShader } from "laya/d3/shader/SubShader" ; import { MathUtil } from "laya/maths/MathUtil" ; import { BaseTexture } from "laya/resource/BaseTexture" ; import SeprableSSSFS from "../shader/SeparableSSS_GasBlur.fs" ; import SeprableSSSVS from "../shader/SeparableSSS_GasBlur.vs" ; export class SeparableSSS_BlitMaterial extends Material { static SHADERVALUE_COLORTEX : number = Shader3D . propertyNameToID ( "u_MainTex" ) ; static SHADERVALUE_DEPTHTEX : number = Shader3D . propertyNameToID ( "u_depthTex" ) ; static SHADERVALUE_BLURDIR : number = Shader3D . propertyNameToID ( "u_blurDir" ) ; static SHADERVALUE_SSSWIDTH : number = Shader3D . propertyNameToID ( "u_sssWidth" ) ; static SHADERVALUE_DISTANCETOPROJECTIONWINDOW : number = Shader3D . propertyNameToID ( "u_distanceToProjectionWindow" ) ; static SHADERVALUE_KENEL : number = Shader3D . propertyNameToID ( "u_kernel" ) ; static SHADERDEFINE_SAMPLE_HIGH ; static init ( ) { var attributeMap = { 'a_PositionTexcoord' : VertexMesh . MESH_POSITION0 } ; var uniformMap = { 'u_MainTex' : Shader3D . PERIOD_MATERIAL , 'u_depthTex' : Shader3D . PERIOD_MATERIAL , 'u_blurDir' : Shader3D . PERIOD_MATERIAL , 'u_sssWidth' : Shader3D . PERIOD_MATERIAL , 'u_distanceToProjectionWindow' : Shader3D . PERIOD_MATERIAL , 'u_kernel' : Shader3D . PERIOD_MATERIAL } ; var shader = Shader3D . add ( "SeparableSSS" ) ; var subShader = new SubShader ( attributeMap , uniformMap ) ; shader . addSubShader ( subShader ) ; var shaderpass = subShader . addShaderPass ( SeprableSSSVS , SeprableSSSFS ) ; var renderState = shaderpass . renderState ; renderState = shaderpass . renderState ; renderState . depthTest = RenderState . DEPTHTEST_ALWAYS ; renderState . depthWrite = false ; renderState . cull = RenderState . CULL_NONE ; renderState . blend = RenderState . BLEND_DISABLE ; } private _fallOff : Vector3 ; private _strength : Vector3 ; private _nSampler : number ; constructor ( ) { super ( ) ; this . setShaderName ( "SeparableSSS" ) ; this . _fallOff = new Vector3 ( 1.0 , 0.37 , 0.3 ) ; this . _strength = new Vector3 ( 0.48 , 0.41 , 0.28 ) ; this . _nSampler = 17 ; this . sssWidth = 0.0012 ; this . kenel = this . calculateKernel ( this . _nSampler , this . _strength , this . _fallOff ) ; } /**
     * 设置diffuse光照图片
     */ set colorTex ( value ) { this . shaderData . setTexture ( SeparableSSS_BlitMaterial . SHADERVALUE_COLORTEX , value ) ; } set blurDir ( value ) { this . shaderData . setVector2 ( SeparableSSS_BlitMaterial . SHADERVALUE_BLURDIR , value ) ; } set depthTex ( value ) { this . shaderData . setTexture ( SeparableSSS_BlitMaterial . SHADERVALUE_DEPTHTEX , value ) ; } set sssWidth ( value ) { value = Math . max ( value , 0 ) ; value = Math . min ( value , 0.025 ) ; this . shaderData . setNumber ( SeparableSSS_BlitMaterial . SHADERVALUE_SSSWIDTH , value ) ; } set kenel ( value ) { let shaderval = new Float32Array ( value . length * 4 ) ; for ( let i = 0 , n = value . length ; i < n ; i ++ ) { let ind = i * 4 ; shaderval [ ind ] = value [ i ] . x ; shaderval [ ind + 1 ] = value [ i ] . y ; shaderval [ ind + 2 ] = value [ i ] . z ; shaderval [ ind + 3 ] = value [ i ] . w ; } this . shaderData . setBuffer ( SeparableSSS_BlitMaterial . SHADERVALUE_KENEL , shaderval ) ; } set falloff ( value ) { Vector3 . max ( value , Vector3 . _ZERO , value ) ; Vector3 . min ( value , Vector3 . _ONE , value ) ; this . _fallOff = value ; this . kenel = this . calculateKernel ( this . _nSampler , this . _fallOff , this . _strength ) ; } set strength ( value ) { Vector3 . max ( value , Vector3 . _ZERO , value ) ; Vector3 . min ( value , Vector3 . _ONE , value ) ; this . _strength = value ; this . kenel = this . calculateKernel ( this . _nSampler , this . _fallOff , this . _strength ) ; } set nSamples ( value ) { this . _nSampler = value ; this . kenel = this . calculateKernel ( this . _nSampler , this . _fallOff , this . _strength ) ; } set cameraFiledOfView ( value ) { let distanceToProject = 1.0 / Math . tan ( 0.5 * value * MathUtils3D . Deg2Rad ) ; this . _shaderValues . setNumber ( SeparableSSS_BlitMaterial . SHADERVALUE_DISTANCETOPROJECTIONWINDOW , distanceToProject ) ; } internal param nSamples param strength param falloff private calculateKernel ( nSamples , strength , falloff ) { let range = nSamples > 20 ? 3.0 : 2.0 ; let exponent = 2.0 ; let Kernel = new Array < Vector4 > ( nSamples ) ; let step = 2.0 * range / ( nSamples - 1 ) ; for ( let i = 0 ; i < nSamples ; i ++ ) { let o = - range + i * step ; let sign = o < 0.0 ? - 1.0 : 1.0 ; Kernel [ i ] = new Vector4 ( ) ; Kernel [ i ] . w = range * sign * Math . abs ( Math . pow ( o , exponent ) ) / Math . pow ( range , exponent ) ; } for ( let i = 0 ; i < nSamples ; i ++ ) { let w0 = i > 0 ? Math . abs ( Kernel [ i ] . w - Kernel [ i - 1 ] . w ) : 0.0 ; let w1 = i < nSamples - 1 ? Math . abs ( Kernel [ i ] . w - Kernel [ i + 1 ] . w ) : 0.0 ; let area = ( w0 + w1 ) / 2.0 ; let t = this . prefile ( Kernel [ i ] . w , falloff ) ; Vector3 . scale ( t , area , t ) ; Kernel [ i ] . x = t . x ; Kernel [ i ] . y = t . y ; Kernel [ i ] . z = t . z ; } let t = Kernel [ Math . floor ( nSamples / 2 ) ] ; for ( var i = Math . floor ( nSamples / 2 ) ; i > 0 ; i -- ) { Kernel [ i ] = Kernel [ i - 1 ] ; } Kernel [ 0 ] = t ; let sum = new Vector3 ( 0.0 , 0.0 , 0.0 ) ; for ( let i = 0 ; i < nSamples ; i ++ ) { sum . x += Kernel [ i ] . x ; sum . y += Kernel [ i ] . y ; sum . z += Kernel [ i ] . z ; } for ( let i = 0 ; i < nSamples ; i ++ ) { Kernel [ i ] . x /= sum . x ; Kernel [ i ] . y /= sum . y ; Kernel [ i ] . z /= sum . z ; } Kernel [ 0 ] . x = ( 1.0 - strength . x ) + strength . x * Kernel [ 0 ] . x ; Kernel [ 0 ] . y = ( 1.0 - strength . y ) + strength . y * Kernel [ 0 ] . y ; Kernel [ 0 ] . z = ( 1.0 - strength . z ) + strength . z * Kernel [ 0 ] . z ; for ( let i = 1 ; i < nSamples ; i ++ ) { Kernel [ i ] . x *= strength . x ; Kernel [ i ] . y *= strength . y ; Kernel [ i ] . z *= strength . z ; } return Kernel ; } internal param r param falloff prefile ( r , falloff ) { let falloffArray = [ falloff . x , falloff . y , falloff . z ] ; let v1 = this . gaussian ( 0.0484 , r , falloffArray ) ; Vector3 . scale ( v1 , 0.100 , v1 ) ; let v2 = this . gaussian ( 0.187 , r , falloffArray ) ; Vector3 . scale ( v2 , 0.118 , v2 ) ; let v3 = this . gaussian ( 0.567 , r , falloffArray ) ; Vector3 . scale ( v3 , 0.113 , v3 ) ; let v4 = this . gaussian ( 1.99 , r , falloffArray ) ; Vector3 . scale ( v4 , 0.358 , v4 ) ; let v5 = this . gaussian ( 7.41 , r , falloffArray ) ; Vector3 . scale ( v5 , 0.078 , v5 ) ; let vec3 = new Vector3 ( v1 . x + v2 . x + v3 . x + v4 . x + v5 . x , v1 . y + v2 . y + v3 . y + v4 . y + v5 . y , v1 . z + v2 . z + v3 . z + v4 . z + v5 . z ) ; return vec3 ; } param variance param r param falloff gaussian ( variance , r , falloff ) { let g = new Vector3 ( ) ; let gg = new Array < number > ( ) ; for ( let i = 0 ; i < 3 ; i ++ ) { let rr = r / ( falloff [ i ] + 0.001 ) ; gg [ i ] = Math . exp ( ( - ( rr * rr ) ) / ( 2.0 * variance ) ) / ( 2.0 * 3.14 * variance ) ; } g . setValue ( gg [ 0 ] , gg [ 1 ] , gg [ 2 ] ) ; return g ; } }