@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
148 lines (120 loc) • 4.6 kB
text/typescript
import { EffectAttribute } from "postprocessing";
import { Uniform } from "three";
import { MODULES } from "../../../engine/engine_modules.js";
import { serializable } from "../../../engine/engine_serialization.js";
import { PostProcessingEffect } from "../PostProcessingEffect.js";
import { PostProcessingEffectOrder } from "../utils.js";
// import type { createSharpeningEffectType } from "./Sharpening.effect";
// let __SHARPENING_MODULE: typeof import("./Sharpening.effect");
// /** @hidden */
// export function internal_SetSharpeningEffectModule(module: typeof import("./Sharpening.effect")) {
// __SHARPENING_MODULE = module;
// }
/**
* [SharpeningEffect](https://engine.needle.tools/docs/api/SharpeningEffect) Sharpening effect enhances the details and edges in the rendered scene by increasing the contrast between adjacent pixels.
* This effect can make textures and fine details appear clearer and more defined, improving the overall visual quality of the scene.
* It is particularly useful in scenes where details may be lost due to blurriness or low resolution.
* @summary Sharpening Post-Processing Effect
* @category Effects
* @group Components
*/
export class SharpeningEffect extends PostProcessingEffect {
get typeName() {
return "Sharpening";
}
order: number | undefined = PostProcessingEffectOrder.Sharpening;
private _effect?: any;
onCreateEffect() {
this._effect ??= new (createSharpeningEffectType())();
return this.effect;
}
private get effect() {
return this._effect;
}
set amount(value: number) {
this._amount = value;
if (this._effect)
this._effect.uniforms.get("amount")!.value = value;
}
get amount() {
if (this._effect)
return this._effect.uniforms.get("amount")!.value;
return this._amount;
}
private _amount = 1;
set radius(value: number) {
this._radius = value;
if (this._effect)
this._effect.uniforms.get("radius")!.value = value;
}
get radius() {
if (this._effect)
return this._effect.uniforms.get("radius")!.value;
return this._radius;
}
private _radius = 1;
// @serializable()
// set threshold(value: number) {
// this.effect.uniforms.get("threshold")!.value = value;
// }
// get threshold() {
// return this.effect.uniforms.get("threshold")!.value;
// }
}
function createSharpeningEffectType() {
const vert = `
void mainSupport() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const frag = `
uniform sampler2D tDiffuse;
uniform float amount;
uniform float radius;
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
float tx = 1.0 / resolution.x;
float ty = 1.0 / resolution.y;
vec2 texelSize = vec2(tx, ty);
vec4 blurred = vec4(0.0);
float total = 0.0;
for (float x = -radius; x <= radius; x++) {
for (float y = -radius; y <= radius; y++) {
vec2 offset = vec2(x, y) * texelSize;
vec4 diffuse = texture2D(tDiffuse, uv + offset);
float weight = exp(-length(offset) * amount);
blurred += diffuse * weight;
total += weight;
}
}
if (total > 0.0) {
blurred /= total;
}
// Calculate the sharpened color using inputColor
vec4 sharp = inputColor + clamp(inputColor - blurred, 0.0, 1.0) * amount;
// Keep original alpha
sharp.a = inputColor.a;
// Ensure the sharp color does not go below 0 or above 1
// This means: sharpening must happen AFTER tonemapping.
sharp = clamp(sharp, 0.0, 1.0);
outputColor = sharp;
}
`
class _SharpeningEffect extends MODULES.POSTPROCESSING.MODULE!.Effect {
constructor() {
super("Sharpening", frag, {
vertexShader: vert,
blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.NORMAL,
uniforms: new Map<string, Uniform<any>>([
["amount", new Uniform(1)],
["radius", new Uniform(1)],
// ["threshold", new Uniform(0)],
]),
attributes: EffectAttribute.CONVOLUTION
});
}
}
return _SharpeningEffect;
}