From f2aea2c144f467fc029c2f778014ce8d0a5937d1 Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Sat, 14 Oct 2023 16:22:40 -0500 Subject: [PATCH] feat: sampler mipmapping (#11) --- src/RenderTarget.ts | 9 +++++++-- src/Sampler.ts | 9 ++++++++- src/WebGLRenderer.ts | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/RenderTarget.ts b/src/RenderTarget.ts index ebe282a..81a30f8 100644 --- a/src/RenderTarget.ts +++ b/src/RenderTarget.ts @@ -1,3 +1,4 @@ +import { Sampler } from './Sampler' import { Texture } from './Texture' import { ARRAY_TYPE } from './_utils' @@ -8,7 +9,11 @@ export class RenderTarget { /** * A {@link Texture} array to write color attachments to. */ - readonly textures: Texture[] = [] + readonly textures: Texture[] + /** + * A {@link Sampler} used for sampling texture attachments. + */ + public sampler: Sampler = new Sampler({ generateMipmaps: false }) /** * Used internally to flag for update on resize. Default is `true`. */ @@ -28,7 +33,7 @@ export class RenderTarget { */ readonly count: number = 1, ) { - this.textures = ARRAY_TYPE.from({ length: count }, () => new Texture()) + this.textures = ARRAY_TYPE.from({ length: count }, () => new Texture(undefined, this.sampler)) } /** diff --git a/src/Sampler.ts b/src/Sampler.ts index c0fdef7..5ed8264 100644 --- a/src/Sampler.ts +++ b/src/Sampler.ts @@ -36,6 +36,12 @@ export interface SamplerOptions { * Flags this sampler for update. Default is `true`. */ needsUpdate: boolean + /** + * Whether to generate mipmaps for increased perceived quality (WebGL only). Default is `true`. + * + * **Note**: this is not implemented in WebGPU. See https://github.com/gpuweb/gpuweb/issues/386. + */ + generateMipmaps: boolean } /** @@ -47,7 +53,8 @@ export class Sampler implements SamplerOptions { public wrapS: Wrapping = 'clamp' public wrapT: Wrapping = 'clamp' public anisotropy: number = 1 - public needsUpdate = true + public generateMipmaps: boolean = true + public needsUpdate: boolean = true constructor(options?: Partial) { if (options) Object.assign(this, options) diff --git a/src/WebGLRenderer.ts b/src/WebGLRenderer.ts index 28c182b..f4763e4 100644 --- a/src/WebGLRenderer.ts +++ b/src/WebGLRenderer.ts @@ -48,6 +48,14 @@ const GL_FILTERS: Record = { linear: GL_LINEAR, } as const +const GL_LINEAR_MIPMAP_NEAREST = 0x2701 +const GL_NEAREST_MIPMAP_LINEAR = 0x2702 + +const GL_MIPMAP_FILTERS: Record = { + nearest: GL_LINEAR_MIPMAP_NEAREST, + linear: GL_NEAREST_MIPMAP_LINEAR, +} as const + const GL_REPEAT = 0x2901 const GL_CLAMP_TO_EDGE = 0x812f const GL_MIRRORED_REPEAT = 0x8370 @@ -266,8 +274,9 @@ export class WebGLRenderer { this.gl.samplerParameteri(target, anisotropyExt.TEXTURE_MAX_ANISOTROPY_EXT, sampler.anisotropy) } + const MIN_FILTERS = sampler.generateMipmaps ? GL_MIPMAP_FILTERS : GL_FILTERS this.gl.samplerParameteri(target, GL_TEXTURE_MAG_FILTER, GL_FILTERS[sampler.magFilter]) - this.gl.samplerParameteri(target, GL_TEXTURE_MIN_FILTER, GL_FILTERS[sampler.minFilter]) + this.gl.samplerParameteri(target, GL_TEXTURE_MIN_FILTER, MIN_FILTERS[sampler.minFilter]) this.gl.samplerParameteri(target, GL_TEXTURE_WRAP_S, GL_WRAPPINGS[sampler.wrapS]) this.gl.samplerParameteri(target, GL_TEXTURE_WRAP_T, GL_WRAPPINGS[sampler.wrapT]) @@ -305,7 +314,11 @@ export class WebGLRenderer { if (!(texture.image instanceof HTMLVideoElement)) texture.needsUpdate = false } - this._updateSampler(texture.sampler) + if (texture.needsUpdate || texture.sampler.needsUpdate) { + if (texture.sampler.generateMipmaps) this.gl.generateMipmap(GL_TEXTURE_2D) + + this._updateSampler(texture.sampler) + } return target }