Skip to content

Commit

Permalink
feat(core): disables default mipmap generation, enables user to speci…
Browse files Browse the repository at this point in the history
…fy renderTarget (and toDataTexture) options

related issues: #14 and #15 

The library will no more generate mipmaps by default but will require to explicitly enable them, also, in general, the library will assume a more 'un-opinionated' stance regarding the output texture options.

BREAKING CHANGE: `generateMipmaps` is no longer `true` by default, both `minFilter` is  no longer `LinearMipMapLinearFilter` by default but `LinearFilter`, `wrapS` and `warpT` are no longer `RepeatWrapping` by default but `ClampToEdgeWrapping`
  • Loading branch information
daniele-pelagatti authored Nov 29, 2023
1 parent b9bcdd1 commit 147d278
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 81 deletions.
126 changes: 82 additions & 44 deletions src/core/QuadRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import {
ByteType,
ClampToEdgeWrapping,
ColorSpace,
DataTexture,
FloatType,
HalfFloatType,
IntType,
LinearFilter,
LinearMipMapLinearFilter,
LinearSRGBColorSpace,
Material,
Mesh,
MeshBasicMaterial,
OrthographicCamera,
PlaneGeometry,
RepeatWrapping,
RenderTargetOptions,
RGBAFormat,
Scene,
ShaderMaterial,
Expand All @@ -26,6 +26,8 @@ import {
WebGLRenderer,
WebGLRenderTarget
} from 'three'

import { QuadRendererTextureOptions } from './types'
/**
* Utility Type that translates `three` texture types to their TypedArray counterparts.
*
Expand All @@ -42,6 +44,37 @@ export type TextureDataTypeToBufferType<TType extends TextureDataType> =
TType extends typeof FloatType ? Float32Array :
never

export type QuadRendererOptions<TType extends TextureDataType, TMaterial extends Material> = {
/**
* Width of the render target
*/
width: number
/**
* height of the renderTarget
*/
height: number
/**
* TextureDataType of the renderTarget
*/
type: TType
/**
* ColorSpace of the renderTarget
*/
colorSpace: ColorSpace
/**
* material to use for rendering
*/
material: TMaterial
/**
* Renderer instance to use
*/
renderer?: WebGLRenderer
/**
* Additional renderTarget options
*/
renderTargetOptions?: QuadRendererTextureOptions
}

const getBufferForType = (type: TextureDataType, width: number, height: number) => {
let out: ArrayLike<number>
switch (type) {
Expand Down Expand Up @@ -82,23 +115,13 @@ let _canReadPixelsResult: boolean | undefined
* @param type
* @param renderer
* @param camera
* @param renderTargetOptions
* @returns
*/
const canReadPixels = (type: TextureDataType, renderer: WebGLRenderer, camera: OrthographicCamera) => {
const canReadPixels = (type: TextureDataType, renderer: WebGLRenderer, camera: OrthographicCamera, renderTargetOptions: RenderTargetOptions) => {
if (_canReadPixelsResult !== undefined) return _canReadPixelsResult

const testRT = new WebGLRenderTarget(1, 1, {
type,
colorSpace: LinearSRGBColorSpace,
format: RGBAFormat,
magFilter: LinearFilter,
minFilter: LinearFilter,
wrapS: RepeatWrapping,
wrapT: RepeatWrapping,
depthBuffer: false,
stencilBuffer: false,
generateMipmaps: true
})
const testRT = new WebGLRenderTarget(1, 1, renderTargetOptions)

renderer.setRenderTarget(testRT)
const mesh = new Mesh(new PlaneGeometry(), new MeshBasicMaterial({ color: 0xffffff }))
Expand Down Expand Up @@ -138,15 +161,32 @@ export class QuadRenderer<TType extends TextureDataType, TMaterial extends Mater
* @param sourceTexture
* @param renderer
*/
constructor (width: number, height: number, type: TType, colorSpace: ColorSpace, material: TMaterial, renderer?:WebGLRenderer) {
this._width = width
this._height = height
this._type = type
this._colorSpace = colorSpace
constructor (options: QuadRendererOptions<TType, TMaterial>) {
this._width = options.width
this._height = options.height
this._type = options.type
this._colorSpace = options.colorSpace

this._material = material
if (renderer) {
this._renderer = renderer
const rtOptions: RenderTargetOptions = {
// fixed options
format: RGBAFormat,
depthBuffer: false,
stencilBuffer: false,
// user options
type: this._type, // set in class property
colorSpace: this._colorSpace, // set in class property
anisotropy: options.renderTargetOptions?.anisotropy !== undefined ? options.renderTargetOptions?.anisotropy : 1,
generateMipmaps: options.renderTargetOptions?.generateMipmaps !== undefined ? options.renderTargetOptions?.generateMipmaps : false,
magFilter: options.renderTargetOptions?.magFilter !== undefined ? options.renderTargetOptions?.magFilter : LinearFilter,
minFilter: options.renderTargetOptions?.minFilter !== undefined ? options.renderTargetOptions?.minFilter : LinearFilter,
samples: options.renderTargetOptions?.samples !== undefined ? options.renderTargetOptions?.samples : undefined,
wrapS: options.renderTargetOptions?.wrapS !== undefined ? options.renderTargetOptions?.wrapS : ClampToEdgeWrapping,
wrapT: options.renderTargetOptions?.wrapT !== undefined ? options.renderTargetOptions?.wrapT : ClampToEdgeWrapping
}

this._material = options.material
if (options.renderer) {
this._renderer = options.renderer
} else {
this._renderer = QuadRenderer.instantiateRenderer()
this._rendererIsDisposable = true
Expand All @@ -161,7 +201,7 @@ export class QuadRenderer<TType extends TextureDataType, TMaterial extends Mater
this._camera.bottom = -0.5
this._camera.updateProjectionMatrix()

if (!canReadPixels(this._type, this._renderer, this._camera)) {
if (!canReadPixels(this._type, this._renderer, this._camera, rtOptions)) {
let alternativeType: TextureDataType | undefined
switch (this._type) {
case HalfFloatType:
Expand All @@ -182,18 +222,8 @@ export class QuadRenderer<TType extends TextureDataType, TMaterial extends Mater
this._quad.geometry.computeBoundingBox()
this._scene.add(this._quad)

this._renderTarget = new WebGLRenderTarget(width, height, {
type: this._type,
colorSpace,
format: RGBAFormat,
magFilter: LinearFilter,
minFilter: LinearMipMapLinearFilter,
wrapS: RepeatWrapping,
wrapT: RepeatWrapping,
depthBuffer: false,
stencilBuffer: false,
generateMipmaps: true
})
this._renderTarget = new WebGLRenderTarget(this.width, this.height, rtOptions)
this._renderTarget.texture.mapping = options.renderTargetOptions?.mapping !== undefined ? options.renderTargetOptions?.mapping : UVMapping
}

/**
Expand Down Expand Up @@ -242,23 +272,31 @@ export class QuadRenderer<TType extends TextureDataType, TMaterial extends Mater
* Performs a readPixel operation in the renderTarget
* and returns a DataTexture containing the read data
*
* @params options
* @returns
*/
public toDataTexture () {
return new DataTexture(
public toDataTexture (options?: QuadRendererTextureOptions) {
const returnValue = new DataTexture(
// fixed values
this.toArray(),
this.width,
this.height,
RGBAFormat,
this._type,
UVMapping,
RepeatWrapping,
RepeatWrapping,
LinearFilter,
LinearMipMapLinearFilter,
1,
// user values
options?.mapping || UVMapping,
options?.wrapS || ClampToEdgeWrapping,
options?.wrapT || ClampToEdgeWrapping,
options?.magFilter || LinearFilter,
options?.minFilter || LinearFilter,
options?.anisotropy || 1,
// fixed value
LinearSRGBColorSpace
)
// set this afterwards, we can't set it in constructor
returnValue.generateMipmaps = options?.generateMipmaps !== undefined ? options?.generateMipmaps : false

return returnValue
}

/**
Expand Down
16 changes: 16 additions & 0 deletions src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Mapping, RenderTargetOptions } from 'three'

/**
* This is the Metadata stored in an encoded Gainmap which is used
* to decode it and return an HDR image
Expand Down Expand Up @@ -62,3 +64,17 @@ export type GainMapMetadata = {
*/
gainMapMax: [number, number, number]
}

/**
*
*/
export type QuadRendererTextureOptions = Omit<RenderTargetOptions, 'type' | 'format'| 'colorSpace' | 'encoding' | 'depthTexture' | 'stencilBuffer' | 'depthBuffer' | 'internalFormat'> & {
/**
* @defaultValue {@link UVMapping}
*/
mapping?: Mapping,
/**
* @defaultValue 1
*/
anisotropy?: number
}
16 changes: 13 additions & 3 deletions src/decode/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,19 @@ export const decode = (params: DecodeParameters): InstanceType<typeof QuadRender
sdr,
gainMap
})
// TODO: three types are generic, eslint complains here, see how we can solve
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
const quadRenderer = new QuadRenderer(sdr.image.width, sdr.image.height, HalfFloatType, LinearSRGBColorSpace, material, renderer)
const quadRenderer = new QuadRenderer({
// TODO: three types are generic, eslint complains here, see how we can solve
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
width: sdr.image.width,
// TODO: three types are generic, eslint complains here, see how we can solve
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
height: sdr.image.height,
type: HalfFloatType,
colorSpace: LinearSRGBColorSpace,
material,
renderer,
renderTargetOptions: params.renderTargetOptions
})
try {
quadRenderer.render()
} catch (e) {
Expand Down
29 changes: 21 additions & 8 deletions src/decode/loaders/LoaderBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import {
} from 'three'

import { QuadRenderer } from '../../core/QuadRenderer'
import { type GainMapMetadata } from '../../core/types'
import { type GainMapMetadata, QuadRendererTextureOptions } from '../../core/types'
import { GainMapDecoderMaterial } from '../materials/GainMapDecoderMaterial'
import { getHTMLImageFromBlob } from '../utils/get-html-image-from-blob'

export class LoaderBase<TUrl = string> extends Loader<QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>, TUrl> {
private _renderer: WebGLRenderer
private _renderTargetOptions?: QuadRendererTextureOptions
/**
* @private
*/
Expand All @@ -36,6 +37,17 @@ export class LoaderBase<TUrl = string> extends Loader<QuadRenderer<typeof HalfFl
this._internalLoadingManager = new LoadingManager()
}

/**
* Specify the renderTarget options to use when rendering the gain map
*
* @param options
* @returns
*/
public setRenderTargetOptions (options: QuadRendererTextureOptions) {
this._renderTargetOptions = options
return this
}

/**
* @private
* @returns
Expand All @@ -55,14 +67,15 @@ export class LoaderBase<TUrl = string> extends Loader<QuadRenderer<typeof HalfFl
sdr: new Texture()
})

return new QuadRenderer(
16,
16,
HalfFloatType,
LinearSRGBColorSpace,
return new QuadRenderer({
width: 16,
height: 16,
type: HalfFloatType,
colorSpace: LinearSRGBColorSpace,
material,
this._renderer
)
renderer: this._renderer,
renderTargetOptions: this._renderTargetOptions
})
}

/**
Expand Down
8 changes: 6 additions & 2 deletions src/decode/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type Texture, type WebGLRenderer } from 'three'

import { type GainMapMetadata } from '../core/types'
import { type GainMapMetadata, type QuadRendererTextureOptions } from '../core/types'

/**
* Necessary parameters for decoding a Gainmap
Expand Down Expand Up @@ -36,6 +36,10 @@ export type DecodeParameters = {
/**
* WebGLRenderer used to decode the GainMap
*/
renderer?: WebGLRenderer
renderer?: WebGLRenderer,
/**
* Options to use when creating the output renderTarget
*/
renderTargetOptions?: QuadRendererTextureOptions

} & GainmapDecodingParameters & GainMapMetadata
2 changes: 1 addition & 1 deletion src/encode/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const encode = (params: EncodingParametersBase) => {

const dataTexture = getDataTexture(image)

const sdr = getSDRRendition(dataTexture, renderer, params.toneMapping)
const sdr = getSDRRendition(dataTexture, renderer, params.toneMapping, params.renderTargetOptions)

const gainMapRenderer = getGainMap({
...params,
Expand Down
14 changes: 7 additions & 7 deletions src/encode/find-texture-min-max.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ export const findTextureMinMax = (image: EXR | RGBE | LogLuv | DataTexture, mode
let w = srcTex.image.width
let h = srcTex.image.height

const quadRenderer = new QuadRenderer(
w,
h,
srcTex.type,
srcTex.colorSpace,
mat,
const quadRenderer = new QuadRenderer({
width: w,
height: h,
type: srcTex.type,
colorSpace: srcTex.colorSpace,
material: mat,
renderer
)
})

const frameBuffers: WebGLRenderTarget[] = []

Expand Down
15 changes: 8 additions & 7 deletions src/encode/get-gainmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ export const getGainMap = (params: { sdr: InstanceType<typeof QuadRenderer> } &
hdr: dataTexture
})

const quadRenderer = new QuadRenderer(
dataTexture.image.width,
dataTexture.image.height,
UnsignedByteType,
LinearSRGBColorSpace,
const quadRenderer = new QuadRenderer({
width: dataTexture.image.width,
height: dataTexture.image.height,
type: UnsignedByteType,
colorSpace: LinearSRGBColorSpace,
material,
renderer
)
renderer,
renderTargetOptions: params.renderTargetOptions
})
try {
quadRenderer.render()
} catch (e) {
Expand Down
Loading

0 comments on commit 147d278

Please sign in to comment.