import { TextureBase } from '@awayjs/renderer';
import { EffectEnvMapMethod, _Shader_EffectEnvMapMethod } from './EffectEnvMapMethod';
/**
* EffectFresnelEnvMapMethod provides a method to add fresnel-based reflectivity to an object using cube maps, which gets
* stronger as the viewing angle becomes more grazing.
*/
export class EffectFresnelEnvMapMethod extends EffectEnvMapMethod {
private _fresnelPower: number;
private _normalReflectance: number;
public static assetType: string = '[asset EffectFresnelEnvMapMethod]';
/**
* @inheritDoc
*/
public get assetType(): string {
return EffectFresnelEnvMapMethod.assetType;
}
/**
* The power used in the Fresnel equation. Higher values make the fresnel effect more pronounced. Defaults to 5.
*/
public get fresnelPower(): number {
return this._fresnelPower;
}
public set fresnelPower(value: number) {
this._fresnelPower = value;
}
/**
* The minimum amount of reflectance, ie the reflectance when the view direction is normal to the surface or light direction.
*/
public get normalReflectance(): number {
return this._normalReflectance;
}
public set normalReflectance(value: number) {
if (this._normalReflectance == value)
return;
this._normalReflectance = value;
this.invalidate();
}
/**
* Creates a new EffectFresnelEnvMapMethod object.
*
* @param envMap The environment map containing the reflected scene.
* @param alpha The reflectivity of the material.
*/
constructor(envMap: TextureBase, alpha: number = 1, fresnelPower: number = 5, normalReflectance: number = 0) {
super(envMap, alpha);
this._fresnelPower = fresnelPower;
this._normalReflectance = normalReflectance;
}
}
import { ShaderRegisterCache, ShaderRegisterData, ShaderRegisterElement } from '@awayjs/stage';
import { ShaderBase } from '@awayjs/renderer';
/**
* _Shader_EffectFresnelEnvMapMethod provides a method to add fresnel-based reflectivity to an object using cube maps, which gets
* stronger as the viewing angle becomes more grazing.
*/
export class _Shader_EffectFresnelEnvMapMethod extends _Shader_EffectEnvMapMethod {
/**
* @inheritDoc
*/
public _getFragmentCode(targetReg: ShaderRegisterElement, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string {
const dataRegister: ShaderRegisterElement = registerCache.getFreeFragmentConstant();
let code: string = '';
const viewDirReg: ShaderRegisterElement = sharedRegisters.viewDirFragment;
const normalReg: ShaderRegisterElement = sharedRegisters.normalFragment;
this._fragmentIndex = dataRegister.index * 4;
const temp: ShaderRegisterElement = registerCache.getFreeFragmentVectorTemp();
registerCache.addFragmentTempUsages(temp, 1);
const temp2: ShaderRegisterElement = registerCache.getFreeFragmentVectorTemp();
registerCache.addFragmentTempUsages(temp2, 1);
// r = V - 2(V.N)*N
code += 'dp3 ' + temp + '.w, ' + viewDirReg + '.xyz, ' + normalReg + '.xyz\n' +
'add ' + temp + '.w, ' + temp + '.w, ' + temp + '.w\n' +
'mul ' + temp + '.xyz, ' + normalReg + '.xyz, ' + temp + '.w\n' +
'sub ' + temp + '.xyz, ' + temp + '.xyz, ' + viewDirReg + '.xyz\n' +
this._envMap._getFragmentCode(temp, registerCache, sharedRegisters, temp) +
'sub ' + temp2 + '.w, ' + temp + '.w, fc0.x\n' + // -.5
'kil ' + temp2 + '.w\n' + // used for real time reflection mapping - if alpha is not 1 (mock texture) kil output
'sub ' + temp + ', ' + temp + ', ' + targetReg + '\n';
// calculate fresnel term
code += 'dp3 ' + viewDirReg + '.w, ' + viewDirReg + '.xyz, ' + normalReg + '.xyz\n' + // dot(V, H)
'sub ' + viewDirReg + '.w, ' + dataRegister + '.w, ' + viewDirReg + '.w\n' + // base = 1-dot(V, H)
'pow ' + viewDirReg + '.w, ' + viewDirReg + '.w, ' + dataRegister + '.z\n' + // exp = pow(base, 5)
'sub ' + normalReg + '.w, ' + dataRegister + '.w, ' + viewDirReg + '.w\n' + // 1 - exp
'mul ' + normalReg + '.w, ' + dataRegister + '.y, ' + normalReg + '.w\n' + // f0*(1 - exp)
'add ' + viewDirReg + '.w, ' + viewDirReg + '.w, ' + normalReg + '.w\n' + // exp + f0*(1 - exp)
// total alpha
'mul ' + viewDirReg + '.w, ' + dataRegister + '.x, ' + viewDirReg + '.w\n';
if (this._maskMap) {
code += this._maskMap._getFragmentCode(temp2, registerCache, sharedRegisters, sharedRegisters.uvVarying) +
'mul ' + viewDirReg + '.w, ' + temp2 + '.x, ' + viewDirReg + '.w\n';
}
// blend
code += 'mul ' + temp + ', ' + temp + ', ' + viewDirReg + '.w\n' +
'add ' + targetReg + ', ' + targetReg + ', ' + temp + '\n';
registerCache.removeFragmentTempUsage(temp);
registerCache.removeFragmentTempUsage(temp2);
return code;
}
protected _updateProperties() {
const index: number = this._fragmentIndex;
const data: Float32Array = this._shader.fragmentConstantData;
data[index] = this._method.alpha;
data[index + 1] = ( this._method).normalReflectance;
data[index + 2] = ( this._method).fresnelPower;
}
}
ShaderBase.registerAbstraction(_Shader_EffectFresnelEnvMapMethod, EffectFresnelEnvMapMethod);