threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
113 lines • 6.44 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { updateMaterialDefines } from '../../materials';
import { AViewerPluginSync } from '../../viewer';
import { onChange, serialize } from 'ts-browser-helpers';
import { uiFolderContainer, uiSlider, uiToggle } from 'uiconfig.js';
import { shaderReplaceString } from '../../utils';
import { ShaderChunk } from 'three';
import ParallaxMappingPluginReliefShader from './shaders/ParallaxMappingPlugin.relief.glsl';
/**
* Parallax Mapping Plugin
* Adds a material extension to PhysicalMaterial which parallax mapping to bump map in the material.
* This is a port of Relief Parallax Mapping from [Rabbid76/graphics-snippets](https://github.com/Rabbid76/graphics-snippets/blob/master/html/technique/parallax_005_parallax_relief_mapping_derivative_tbn.html)
* @category Plugins
*/
let ParallaxMappingPlugin = class ParallaxMappingPlugin extends AViewerPluginSync {
constructor(enabled = true) {
super();
this.enabled = true;
this.stepCount = 12;
this.binaryStepCount = 3;
this.debugNormals = false;
this.debugHitHeight = false;
this._defines = {
['PARALLAX_NORMAL_MAP_QUALITY']: 0,
};
this._bumpMapExtension = {
shaderExtender: (shader, material, _renderer) => {
if (!material.bumpMap || this.isDisabled())
return;
shader.fragmentShader = shader.fragmentShader.replace('#include <normal_fragment_begin>', '');
shader.fragmentShader = shader.fragmentShader.replace('#include <normal_fragment_maps>', '');
shader.fragmentShader = shader.fragmentShader.replace('#include <map_fragment>', '#include <normal_fragment_begin>\n#include <normal_fragment_maps>\n#include <map_fragment>');
for (const s of ['map_fragment', 'alphamap_fragment', 'roughnessmap_fragment', 'metalnessmap_fragment', 'emissivemap_fragment', 'transmission_fragment']) {
shader.fragmentShader = shaderReplaceString(shader.fragmentShader, `#include <${s}>`, ShaderChunk[s].replace(/\bv\w+Uv\b/g, 'parallaxUv.xy', { replaceAll: true }));
}
if (this.debugNormals || this.debugHitHeight)
shader.fragmentShader = shaderReplaceString(shader.fragmentShader,
// .replace('texture2D( map, parallaxUv.xy )', 'texture2D( map, parallaxUv.xy )')
'texture2D( map, parallaxUv.xy )', this.debugNormals ? 'vec4(normal, 1.); normal = nonPerturbedNormal' : 'vec4(parallaxUv.z,0., 0., 1.)');
shader.fragmentShader = shaderReplaceString(shader.fragmentShader, '#include <normal_fragment_maps>', shaderReplaceString(shaderReplaceString(ShaderChunk.normal_fragment_maps, '#elif defined( USE_NORMALMAP_TANGENTSPACE )', '#elif defined( USE_NORMALMAP_TANGENTSPACE ) && !defined( USE_BUMPMAP )'), 'normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );',
// 'diffuseColor.rgb = vec3(0, dHdxy_fwd());'
// 'diffuseColor.rgb = CalculateNormal(vUv).rgb;'
'vec3 parallaxUv = reliefParallaxPerturbNormal(faceDirection, normal);'));
},
parsFragmentSnippet: () => {
return this.isDisabled() ? '' : (ParallaxMappingPluginReliefShader + '\n')
.replaceAll('PARALLAX_MAP_STEPS', this.stepCount.toString()) // replacing here to unroll for loop.
.replaceAll('PARALLAX_MAP_B_STEPS', this.binaryStepCount.toString());
},
isCompatible: (material) => {
return material.isPhysicalMaterial;
},
computeCacheKey: material => {
return '' + !this.isDisabled() + material.bumpMap?.uuid + this.debugNormals + this.debugHitHeight + this.stepCount.toString() + this.binaryStepCount.toString();
},
onObjectRender: (_object, material, _renderer) => {
if (this.isDisabled())
return; // todo: use extraDefines
updateMaterialDefines({
...this._defines,
}, material);
},
};
this.enabled = enabled;
this._updateExtension = this._updateExtension.bind(this);
}
_updateExtension() {
this._bumpMapExtension?.setDirty?.();
this._viewer?.setDirty();
}
onAdded(viewer) {
viewer.materialManager.registerMaterialExtension(this._bumpMapExtension);
return super.onAdded(viewer);
}
onRemove(viewer) {
viewer.materialManager.unregisterMaterialExtension(this._bumpMapExtension);
return super.onRemove(viewer);
}
};
ParallaxMappingPlugin.PluginType = 'ReliefParallaxMapping';
__decorate([
onChange(ParallaxMappingPlugin.prototype._updateExtension),
serialize(),
uiToggle('Enabled')
], ParallaxMappingPlugin.prototype, "enabled", void 0);
__decorate([
uiSlider('Step count', [1, 32], 1),
onChange(ParallaxMappingPlugin.prototype._updateExtension),
serialize()
], ParallaxMappingPlugin.prototype, "stepCount", void 0);
__decorate([
uiSlider('Binary search steps', [1, 8], 1),
onChange(ParallaxMappingPlugin.prototype._updateExtension),
serialize()
], ParallaxMappingPlugin.prototype, "binaryStepCount", void 0);
__decorate([
onChange(ParallaxMappingPlugin.prototype._updateExtension),
uiToggle('Debug Normals')
], ParallaxMappingPlugin.prototype, "debugNormals", void 0);
__decorate([
onChange(ParallaxMappingPlugin.prototype._updateExtension),
uiToggle('Debug Hit Height')
], ParallaxMappingPlugin.prototype, "debugHitHeight", void 0);
ParallaxMappingPlugin = __decorate([
uiFolderContainer('Parallax Bump Mapping (MatExt)')
], ParallaxMappingPlugin);
export { ParallaxMappingPlugin };
//# sourceMappingURL=ParallaxMappingPlugin.js.map