troika-three-text
Advanced tools
Comparing version 0.44.0 to 0.45.0
@@ -6,2 +6,19 @@ # Change Log | ||
# [0.45.0](https://github.com/protectwise/troika/compare/v0.44.0...v0.45.0) (2022-01-02) | ||
### Features | ||
* **troika-three-text:** SDFs for all fonts are now stored in the same texture ([7e871f7](https://github.com/protectwise/troika/commit/7e871f77c17dbbb68ca5c2240f569d4b102031f0)) | ||
### Performance Improvements | ||
* **troika-three-text:** avoid extra draw call on double sided materials as of Three r130 ([6222ef3](https://github.com/protectwise/troika/commit/6222ef300ac364dcb0bb099a7469622e9287651e)) | ||
* **troika-three-text:** make the glyphColors buffer transferable ([c8c92fa](https://github.com/protectwise/troika/commit/c8c92faa70a8ad0fa08cadf38f8e4d4d2e933c10)) | ||
# [0.44.0](https://github.com/protectwise/troika/compare/v0.43.1-alpha.0...v0.44.0) (2021-11-14) | ||
@@ -8,0 +25,0 @@ |
{ | ||
"name": "troika-three-text", | ||
"version": "0.44.0", | ||
"version": "0.45.0", | ||
"description": "SDF-based text rendering for Three.js", | ||
@@ -18,4 +18,4 @@ "author": "Jason Johnston <jason.johnston@protectwise.com>", | ||
"bidi-js": "^1.0.2", | ||
"troika-three-utils": "^0.44.0", | ||
"troika-worker-utils": "^0.44.0" | ||
"troika-three-utils": "^0.45.0", | ||
"troika-worker-utils": "^0.45.0" | ||
}, | ||
@@ -36,3 +36,3 @@ "peerDependencies": { | ||
}, | ||
"gitHead": "a6b913e475a3a8459b2f758c709b8feb16966ed1" | ||
"gitHead": "a1ab2b36832518827f444a8654053a4b0d5d95d7" | ||
} |
import { | ||
Float32BufferAttribute, | ||
BufferGeometry, | ||
PlaneBufferGeometry, | ||
@@ -7,3 +9,4 @@ InstancedBufferGeometry, | ||
Box3, | ||
Vector3 | ||
DoubleSide, | ||
BackSide, | ||
} from 'three' | ||
@@ -17,7 +20,28 @@ | ||
if (!geom) { | ||
geom = templateGeometries[detail] = new PlaneBufferGeometry(1, 1, detail, detail).translate(0.5, 0.5, 0) | ||
// Geometry is two planes back-to-back, which will always be rendered FrontSide only but | ||
// appear as DoubleSide by default. FrontSide/BackSide are emulated using drawRange. | ||
// We do it this way to avoid the performance hit of two draw calls for DoubleSide materials | ||
// introduced by Three.js in r130 - see https://github.com/mrdoob/three.js/pull/21967 | ||
const front = new PlaneBufferGeometry(1, 1, detail, detail) | ||
const back = front.clone() | ||
const frontAttrs = front.attributes | ||
const backAttrs = back.attributes | ||
const combined = new BufferGeometry() | ||
const vertCount = frontAttrs.uv.count | ||
for (let i = 0; i < vertCount; i++) { | ||
backAttrs.position.array[i * 3] *= -1 // flip position x | ||
backAttrs.normal.array[i * 3 + 2] *= -1 // flip normal z | ||
} | ||
;['position', 'normal', 'uv'].forEach(name => { | ||
combined.setAttribute(name, new Float32BufferAttribute( | ||
[...frontAttrs[name].array, ...backAttrs[name].array], | ||
frontAttrs[name].itemSize) | ||
) | ||
}) | ||
combined.setIndex([...front.index.array, ...back.index.array.map(n => n + vertCount)]) | ||
combined.translate(0.5, 0.5, 0) | ||
geom = templateGeometries[detail] = combined | ||
} | ||
return geom | ||
} | ||
const tempVec3 = new Vector3() | ||
@@ -85,2 +109,9 @@ const glyphBoundsAttrName = 'aTroikaGlyphBounds' | ||
// Since our base geometry contains triangles for both front and back sides, we can emulate | ||
// the "side" by restricting the draw range. | ||
setSide(side) { | ||
const verts = this.getIndex().count | ||
this.setDrawRange(side === BackSide ? verts / 2 : 0, side === DoubleSide ? verts : verts / 2) | ||
} | ||
set detail(detail) { | ||
@@ -87,0 +118,0 @@ if (detail !== this._detail) { |
import { | ||
Color, | ||
DoubleSide, | ||
FrontSide, | ||
Matrix4, | ||
@@ -466,4 +467,20 @@ Mesh, | ||
} | ||
// We need to force the material to FrontSide to avoid the double-draw-call performance hit | ||
// introduced in Three.js r130: https://github.com/mrdoob/three.js/pull/21967 - The sidedness | ||
// is instead applied via drawRange in the GlyphsGeometry. | ||
material._hadOwnSide = material.hasOwnProperty('side') | ||
this.geometry.setSide(material._actualSide = material.side) | ||
material.side = FrontSide | ||
} | ||
onAfterRender(renderer, scene, camera, geometry, material, group) { | ||
// Restore original material side | ||
if (material._hadOwnSide) { | ||
material.side = material._actualSide | ||
} else { | ||
delete material.side // back to inheriting from base material | ||
} | ||
} | ||
/** | ||
@@ -470,0 +487,0 @@ * Shortcut to dispose the geometry specific to this instance. |
@@ -50,5 +50,5 @@ import { Color, DataTexture, LinearFilter, RGBAFormat } from 'three' | ||
* https://webglstats.com/webgl/parameter/MAX_TEXTURE_SIZE and should allow for a | ||
* reasonably large number of glyphs (default glyph size of 64 and safe texture size of | ||
* 2048^2 allows for 1024 glyphs.) This can be increased if you need to increase the | ||
* glyph size and/or have an extraordinary number of glyphs. | ||
* reasonably large number of glyphs (default glyph size of 64^2 and safe texture size of | ||
* 2048^2, times 4 channels, allows for 4096 glyphs.) This can be increased if you need to | ||
* increase the glyph size and/or have an extraordinary number of glyphs. | ||
*/ | ||
@@ -64,7 +64,12 @@ function configureTextBuilder(config) { | ||
/** | ||
* Repository for all font SDF atlas textures | ||
* Repository for all font SDF atlas textures and their glyph mappings. There is a separate atlas for | ||
* each sdfGlyphSize. Each atlas has a single Texture that holds all glyphs for all fonts. | ||
* | ||
* { | ||
* [font]: { | ||
* sdfTexture: DataTexture | ||
* [sdfGlyphSize]: { | ||
* glyphCount: number, | ||
* sdfTexture: Texture, | ||
* fonts: Map<fontURL, { | ||
* glyphs: Map<glyphID, {path, atlasIndex, sdfViewBox}> | ||
* }> | ||
* } | ||
@@ -147,11 +152,9 @@ * } | ||
// Init the atlas for this font if needed | ||
// Init the atlas if needed | ||
const {textureWidth, sdfExponent} = CONFIG | ||
const {sdfGlyphSize} = args | ||
let atlasKey = `${args.font}@${sdfGlyphSize}` | ||
let atlas = atlases[atlasKey] | ||
let atlas = atlases[sdfGlyphSize] | ||
if (!atlas) { | ||
atlas = atlases[atlasKey] = { | ||
count: 0, | ||
glyphs: new Map(), //glyphId->{} | ||
atlas = atlases[sdfGlyphSize] = { | ||
glyphCount: 0, | ||
sdfTexture: new DataTexture( | ||
@@ -168,7 +171,12 @@ new Uint8Array(sdfGlyphSize * textureWidth * 4), | ||
LinearFilter | ||
) | ||
), | ||
glyphsByFont: new Map() | ||
} | ||
atlas.sdfTexture.font = args.font | ||
} | ||
let fontGlyphs = atlas.glyphsByFont.get(args.font) | ||
if (!fontGlyphs) { | ||
atlas.glyphsByFont.set(args.font, fontGlyphs = new Map()) | ||
} | ||
// Issue request to the typesetting engine in the worker | ||
@@ -184,3 +192,3 @@ typesetInWorker(args).then(result => { | ||
glyphIds.forEach((glyphId, i) => { | ||
let glyphInfo = atlas.glyphs.get(glyphId) | ||
let glyphInfo = fontGlyphs.get(glyphId) | ||
@@ -197,3 +205,3 @@ // If this is a glyphId not seen before, add it to the atlas | ||
const atlasIndex = atlas.count++ | ||
const atlasIndex = atlas.glyphCount++ | ||
const sdfViewBox = [ | ||
@@ -205,3 +213,3 @@ pathBounds[0] - fontUnitsMargin, | ||
] | ||
atlas.glyphs.set(glyphId, (glyphInfo = { path, atlasIndex, sdfViewBox })) | ||
fontGlyphs.set(glyphId, (glyphInfo = { path, atlasIndex, sdfViewBox })) | ||
@@ -240,3 +248,3 @@ // Collect those that need SDF generation | ||
if (sdfResults.length) { | ||
sdfResults.forEach(({ atlasIndex, textureData, timing }) => { | ||
sdfResults.forEach(({ atlasIndex, textureData }) => { | ||
const texImg = atlas.sdfTexture.image | ||
@@ -433,2 +441,5 @@ | ||
} | ||
if (result.glyphColors) { | ||
transferables.push(result.glyphColors.buffer) | ||
} | ||
return transferables | ||
@@ -435,0 +446,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
721290
10286
+ Addedtroika-three-utils@0.45.0(transitive)
+ Addedtroika-worker-utils@0.45.0(transitive)
- Removedtroika-three-utils@0.44.0(transitive)
- Removedtroika-worker-utils@0.44.0(transitive)
Updatedtroika-three-utils@^0.45.0
Updatedtroika-worker-utils@^0.45.0