protectwise / troika Goto Github PK
View Code? Open in Web Editor NEWA JavaScript framework for interactive 3D and 2D visualizations
License: MIT License
A JavaScript framework for interactive 3D and 2D visualizations
License: MIT License
Hi,
would it be possible to use notoSans for this Characters?
i tryed https://google-webfonts-helper.herokuapp.com/fonts/noto-sans?subsets=cyrillic,vietnamese,latin
woff but cannot see any character only latin
Following on from cursor positioning and text selection (#27, #25), we need text editing.
The big unknown here is how to input text. On screen it should take input from the keyboard just like HTML inputs. (Maybe use a hidden input/textarea behind the scenes?)
In XR, we may need an in-world keyboard. We could also look into utilizing speech-to-text.
Objects with origins extremely near each other currently result in the BoundingSphereOctree we use for raycasting optimization becoming excessively deep. We should implement a minimum leaf size below which no further subdivision happens. This would likely improve performance in many cases, and may avoid some possible issues that could crop up as the node size approaches epsilon.
The UIBlockLayer3DFacade impl for backgrounds and borders relies on renderOrder
to ensure correct transparency blending in deep UI trees. This doesn't play well with other objects in the scene, however, requiring the author to manually set renderOrder
for any other objects that may overlap in front of or behind the UI panes.
Let's try to find a better way to handle background/border layering that allows z-sorting to still work like normal.
Currently if you have 2 tracked controllers, we naively choose one of them to be the "isPointing" controller that is given a pointer ray and cursor.
We should allow either controller to become the pointer, e.g. by switching isPointing to that controller that last had a button press.
Support for WOFF2 font files was initially omitted, due to the requirement of a JS-executable Brotli decompressor. If we were to add one, it should otherwise work.
The big issue with Brotli implementations is their relatively large file size. This appears to be due to the fact that the Brotli algorithm specifies a built-in dictionary of common terms which itself is most of the file size -- 9K+ items.
In some scenarios the extra size may be outweighed by the decreased size of the font files, especially if using several different fonts or if the surrounding page is already using WOFF2 fonts in its CSS. But I don't think I'd want to include it by default, so this might be an option users could set that would point to a file holding the Brotli code.
For reference, a webpacked build of decompress.js at https://github.com/foliojs/brotli.js weighs in at about 92K / 60K gzipped. This is the smallest impl I've seen so far due to its approach of brotli-compressing the dictionary itself.
We use the GLTFLoader from Three's packaged jsm examples for some of the VR controller models. The GLTFLoader module imports ../../../build/three.module.js
which works fine if the application's bundler also resolves three
to that file, however some bundlers (e.g. parcel) will choose to load the three.js
UMD module file instead, which results in two copies of Three being loaded and the GLTFLoader using different classes than the rest of the app, and causes rendering glitches in the models (perhaps due to instanceof checks or id collisions, not sure exactly.)
What we ideally want is for GLTFLoader to import from the 'three' alias so it will be resolved the same way as all the other imports, whether that's the jsm or umd file. The https://github.com/johh/three-gltf-loader package comes close but uses require('three')
instead of an es6 import or umd.
The XRInputSourceFacade
design is set up to allow overrides to configuration of its grip, targetRay, cursor, etc., but there's not currently an exposed way for authors to define those overrides.
There seems to be an issue loading fonts?
https://codesandbox.io/s/threejs-bare-example-w00pp?file=/index.js
I was thinking maybe it was codesandbox but the react-three-fiber example works fine. I wonder what is happening differently 🤔
Followup from #11 -- The initial WebXR implementation does not do any polyfilling on its own, requiring authors to load and initialize the webxr-polyfill. We need to decide if that's acceptable or if we want to try injecting it automatically when applicable. My hope is that the polyfill will become obsolete fairly soon anyway as true WebXR implementations roll out to greenfield browsers, but in the short term it's still a necessary tool.
Also should look into a custom webxr-polyfill build that excludes the Cardboard device emulation.
demo: https://codesandbox.io/s/r3f-troika-text-l40jo?file=/src/index.js
it seems to behave very strange when i anchor it left/op, then move it via position to minus half the viewports width/height so that it should be exactly at the upper left border.
it makes no sense to me, but this setting makes the text disappear completely:
<Text position={[-viewport.width / 2, 0, 0]}
while adding a tiny digit shows it again:
<Text position={[-viewport.width / 2.1, 0, 0]}
same happens at the top, the offsets that are 100% correct but a clean width / 2 makes the text go away.
it looks to me like something in the shader is clipping it incorrectly.
We currently map buttons to mouse-ish events, and the stick axis to wheel events. That's decent for simple cases but authors will want to be able to handle specific buttons/axes in custom ways. We need to design an interface for doing that.
The builtin ThreeJS shaders have a set of fragment shader chunks that perform what could be considered post-processing tasks such as tone mapping, encoding, dithering, etc. Currently the fragmentColorTransform
is injected after these chunks, but it would be more appropriate to inject it before those chunks, but after any other gl_FragColor manipulation.
I took an initial swing at it here: 85c71d6 and it works ok in nominal cases but fails when double-deriving due to #include
expansion.
Build some out-of-the-box facades/utilities for common needs in XR scenes. Some ideas:
We can break these out to separate issues as needed.
Use of new Function in troika/packages/troika-worker-utils/src/WorkerModules.js (v0.20.0) causes CSP failure:
"Uncaught EvalError: Refused to evaluate a string as JavaScript because
'unsafe-eval' is not an allowed source of script in the following
Content Security Policy directive"
It requires content security directive script-src 'unsafe-eval'
.
Would there be a safer alternative for new Function so that there would be no need to allow this unsafe functionality in policy?
As of version 0.21.0, using Instanceable3DFacade with material.instanceUniforms = ['opacity'] and castShadow:true results in the following console warning:
three.module.js:18347 THREE.WebGLProgram: gl.getProgramInfoLog() WARNING: Output of vertex shader 'troika_vary_opacity' not read by fragment shader
This is because the DepthMaterial fragment shader declares the opacity uniform, so InstancingManager creates a varying for it in both the vertex and fragment shaders; however that uniform and its usages are within #if
conditional directives that are compiled out of the fragment shader, leaving it in only the vertex shader and producing this warning.
This is a low impact edge case but it would be nice to find a way to eliminate the warning.
See https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/assets and https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/motion-controllers
We should use these tools to resolve generic tracked controller grip models.
I would like to configure the number of segments of the surface plane, similar to
new PlaneBufferGeometry(1, 1, 32, 32) // 32 x 32 segments/vertices
so that we can warp the surface like so: https://codesandbox.io/s/r3f-drei-meshwobblematerial-g5373
currently if i pass that wobbly material to troika it behaves very rigid: https://codesandbox.io/s/r3f-drei-meshwobblematerial-rwmrx i guess that's because the surface behaves like a plane with 1x1 segments.
can this be done somehow?
See lojjic/aframe-troika-text#20
The font referenced there (https://fonts.google.com/download?family=Noto%20Sans%20SC) appears to have a CFF
table and no loca
table. Typr appears to support both schemes - see Typr.U.glyphToPath
as an example for the forking logic. However we aren't following that same logic in the FontParser_Typr adapter, we just call Typr.glyf._parseGlyf
, which fails when there's no loca
table present.
For TextMesh and Text3DFacade:
The current anchor
property isn't very expressive, and having it be an array can sometimes be hard to work with and generally goes against Troika's convention of facades being simple flat structures.
Here's my initial proposal:
anchorX
- can be:
anchorY
- can be:
[1] These baseline values could be useful e.g. for the MOZ_text glTF export from Blender.
Something like CSS calc()
could also be useful for added expressiveness and control, but that's a bigger lift that could be done in the future.
Currently, the sdfGlyphSize
can only be configured once globally. It would be useful to allow configuring this on a per-object basis. For example some fonts with very fine details need a larger SDF resolution than others, and some text objects that will be displayed very large could use sharper corners than those that will be displayed small.
example: https://codesandbox.io/s/r3f-drei-meshwobblematerial-tjmu2?file=/src/App.js
all playfair variants have this problem, even the non-italic ones. https://fonts.google.com/specimen/Playfair+Display?category=Serif&thickness=6
Look into offloading the BoundingSphereOctree into a web worker. This could help with frame rate by removing the raycasting operations from the main thread. It could also pose complications with events and their relation to native events due to being async.
With an average gl.MAX_TEXTURE_SIZE
of 4096 (see https://webglstats.com/webgl/parameter/MAX_TEXTURE_SIZE), the current approach of a single-column SDF texture only allows up to 64 glyphs. Exceeding that count results in gl errors and broken rendering.
The single-column approach was nice because it made inserting new glyphs super simple, but that obviously doesn't work. Let's move to a texture with default width of 2048 and a single row, and grow its height by powers of 2 as necessary from there. That will allow for 2048 glyphs at default SDF size in essentially all cases. Inserting and reading will be slightly more complex but not very much so.
See corresponding CSS feature: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range
The font
property should accept an array of unicode-range-to-font-file mappings.
Is troika-3d-text available via a content delivery network such as jsdelivr.net?
I build very simple plain-vanilla JavaScript cookbook examples - such as this one:
https://www.ladybug.tools/spider-covid-19-viz-3d/cookbook/globe-population-cities/
I am very interested in building examples that include troika-3d-text. Is there some way this could be possible?
tested this with the aframe component and direct troika build and example on
Two blocks adjacent to each other currently have a small visual gap in between them due to the fragment shader antialiasing into the blocks by half a fragment.
We need to be smarter and:
This is a necessary feature for eventually enabling text selection/highlighting/editing.
We need the ability to raycast a position in a rendered text block, and for that position determine the closest character boundary to it, returning an index in the original text string.
It's easy enough to resolve the glyph index, by searching through the glyph rects array, but there isn't a clean way to resolve the glyph index back to string char index. These aren't always 1-to-1 due to ligature substitution etc. This may require modifying Typr.js to persist char indexes with the glyphs.
Hi there,
Great module! Have you considered allowing to use troika-3d-text standalone with react-native? I've tried to use your module via react-three-fiber
and https://github.com/react-spring/drei` but I run into the following bundler error: pmndrs/drei#19
It works great with react-native-web, but I think the downloading and building code might be the culprit. Is it possible to generate the sdf assets offline and then pass the resulting asset to troika-3d-text or does this defeat the purpose of the module and I'm better off with three-bmfont-text
?
Thanks,
Jun
Text on the web should be selectable by default. Let's design in text selection behavior and copy/cut out of the box.
Depends on cursor/caret positioning capability - see #25
How can I apply custom shader and apply text texture? https://codesandbox.io/s/msdf-bitmap-28hy0?file=/src/app.js
Other folks are wanting to do flexbox layout using Troika's text implementation, but they run into the same problems I did for troika-3d-ui with the async nature of the text layout and Yoga's need for measureText to be synchronous.
It occured to me that FlexLayoutProcessor.js is very close to being standalone, and could be exposed on its own to let people just call requestFlexLayout()
with their own style tree. It would run in the worker alongside the text processor, have access to text measurement, and users could apply the result to their main thread objects.
I'm thinking this has a dependency on #47, and we'd create a new package troika-flexbox-layout
or similar that just has the flexbox processing code and no other troika framework deps.
Text empty and doesn't drawed after clone TextMesh.
See https://github.com/vislyhq/stretch
This appears to match features with Yoga, with some potential advantages:
The main downside is using wasm
, which changes the browser compat story a bit. There may be ways to get an asm
build out of it, or we could take the plunge.
Font download and SDF generation is currently lazy, waiting until a TextMesh is first created and sync()
-ed. This can cause a noticeable period of blankness when a scene is first rendered.
We should add a function that users can call to preload a font and optionally generate SDF for a set of initial glyphs. It would take a callback that is invoked when the font file is loaded, parsed, and the SDFs are ready. It would then be ready for TextMeshes to use without any noticeable delay.
Proposal:
import {preloadFont} from 'troika-3d-text'
showLoadingScreen()
preloadFont('path/to/font.woff', 'abcdefghijklmnopqrstuvwxyz', () => {
showScene()
})
When I build
with create-react-app
I get the error ReferenceError: s is not defined
with the FontProcessor
file. I suspect something is breaking during minification?
EDIT: Looks like textmesh-standalone.esm.js
gets this error, however, textmesh-standalone.umd.js
works fine. Quite possibly the same issue with codesandbox?
Text3DFacade's underlying implementation should be extracted to a subclass of THREE.Mesh (without a dependency on troika-3d if possible). This would allow it to be used by itself in other projects and frameworks (AFrame, react-three-fiber, etc.) that could benefit from its advantages over other text implementations.
Hi!
We already used troika-3d-text
in our latest demos (https://blog.mozvr.com) and it's amazing. Great job!
I'm currently working on a glTF extension to include text without exporting the mesh but only the metadata needed for recreating it in realtime. My specific goal is to create text in Blender, export the scene to glTF, and recreate the text in realtime in threejs with the same look as in Blender, using troika-3d-text.
But I have a problem: a text in Blender with zero rotation is laid down on the floor, whereas a text in troika-3d-text with zero rotation is standing up, facing Z.
I tried different solutions for this, but none works completely. The best option would be to ask troika-3d-text to create the text "laid down on the floor", in the XZ plane. Do you think it could be possible to add a parameter in the constructor, or a property of the text, to specify the desired plane where the text is created? something like text.axis
or text.normal
, with the possible string values +x
-x
+y
-y
+z
-z
, specifying where the text is facing on creation time.
I don't know if that would break things. I this case, maybe you could give me some hints about where to hack the library to achieve the desired result. I've been trying but honestly I'm a bit lost on how it could be the best way to do it.
This would be incredibly useful to match Blender and troika-3d-text. Thanks!
Now that the standalone TextMesh is being used by several third party ThreeJS frameworks and projects, the fact that those users have to explicitly import from a secondary file in the dist directory rather than just the package name feels ... wrong.
I'm proposing to add a new package that will hold all the code currently used by the standalone build, and the existing troika-3d-text will reference that and just add the extra stuff related to usage in the Troika framework. This will be a breaking change for projects using it, but that will be the case at some point regardless so sooner is better IMO.
Possible names for the new package:
I'm open to renaming any exports as well ... TextMesh -> Text perhaps?
Add an ergonomic API for defining and controlling positional audio. See https://threejs.org/docs/#api/en/audio/PositionalAudio
Currently the Object3DFacade tree is mirrored directly in a ThreeJS Object3D tree of the same structure. This isn't a necessity, however; it's possible that using a simpler flattened ThreeJS scene could bring some advantages, such as:
Potential gotchas:
it seems to rely on document
, which does not exist in node.
i believe in order to make troika pseudo-isomorphic all it would have to do is:
const linkEl = typeof document !== 'undefined' && document.createElement('a')
this would allow ssr to function normally.
Hi,
it looks like in aframe text its possible to get this data
what i try is to port aframe-material input to troika-text
https://github.com/etiennepinchon/aframe-material/blob/master/src/input/index.js#L180
We should convert all the existing WebVR code in the troika-xr
module to use the WebXR API, now that it has reached a stable vr-complete milestone. This will help smooth out many of the rough edges in the current impl and give us a much better base on which to build.
In the short term we'll probably want to polyfill it, which will depend on the webxr-polyfill finishing its update to the milestone API. Watch immersive-web/webxr-polyfill#51 for that status.
When overflowing the maxWidth and wrapping is disabled, we should support truncation of the text with or without ellipsis. Ideally we'd support everything in the CSS text-overflow property. We may also want to expose ellipsis in the middle, though there's no CSS precedent to match for that.
If an Instanceable3DFacade is a descendant of an object which is set to visible=false
, the instance is still rendered. We need to handle inherited visibility on instanceables just like normal meshes do.
When using the 3d-text module I get this error. It seems that something is wrong with DerivedShader:
THREE.WebGLShader: gl.getShaderInfoLog() vertex
ERROR: 0:390: 'uTroikaSDFTextureSize' : redefinition
ERROR: 0:391: 'uTroikaSDFGlyphSize' : redefinition
ERROR: 0:392: 'uTroikaTotalBounds' : redefinition
ERROR: 0:393: 'uTroikaClipRect' : redefinition
ERROR: 0:394: 'uTroikaOrient' : redefinition
ERROR: 0:395: 'uTroikaUseGlyphColors' : redefinition
ERROR: 0:396: 'aTroikaGlyphBounds' : redefinition
ERROR: 0:397: 'aTroikaGlyphIndex' : redefinition
ERROR: 0:398: 'aTroikaGlyphColor' : redefinition
ERROR: 0:399: 'vTroikaSDFTextureUV' : redefinition
ERROR: 0:400: 'vTroikaGlyphUV' : redefinition
ERROR: 0:401: 'vTroikaGlyphColor' : redefinition
�1: precision highp float;
2: precision highp int;
3: #define HIGH_PRECISION
4: #define SHADER_NAME MeshBasicMaterial
5: #define TROIKA_DERIVED_MATERIAL 3
6: #define VERTEX_TEXTURES
7: #define GAMMA_FACTOR 2
8: #define MAX_BONES 0
9: #define BONE_TEXTURE
10: #define DOUBLE_SIDED
11: #define USE_LOGDEPTHBUF
12: #define USE_LOGDEPTHBUF_EXT
13: uniform mat4 modelMatrix;
14: uniform mat4 modelViewMatrix;
15: uniform mat4 projectionMatrix;
16: uniform mat4 viewMatrix;
17: uniform mat3 normalMatrix;
18: uniform vec3 cameraPosition;
19: uniform bool isOrthographic;
20: #ifdef USE_INSTANCING
21: attribute mat4 instanceMatrix;
22: #endif
23: attribute vec3 position;
24: attribute vec3 normal;
25: attribute vec2 uv;
26: #ifdef USE_TANGENT
27: attribute vec4 tangent;
28: #endif
29: #ifdef USE_COLOR
30: attribute vec3 color;
31: #endif
32: #ifdef USE_MORPHTARGETS
33: attribute vec3 morphTarget0;
34: attribute vec3 morphTarget1;
35: attribute vec3 morphTarget2;
36: attribute vec3 morphTarget3;
37: #ifdef USE_MORPHNORMALS
38: attribute vec3 morphNormal0;
39: attribute vec3 morphNormal1;
40: attribute vec3 morphNormal2;
41: attribute vec3 morphNormal3;
42: #else
43: attribute vec3 morphTarget4;
44: attribute vec3 morphTarget5;
45: attribute vec3 morphTarget6;
46: attribute vec3 morphTarget7;
47: #endif
48: #endif
49: #ifdef USE_SKINNING
50: attribute vec4 skinIndex;
51: attribute vec4 skinWeight;
52: #endif
53:
54: #define PI 3.14159265359
55: #define PI2 6.28318530718
56: #define PI_HALF 1.5707963267949
57: #define RECIPROCAL_PI 0.31830988618
58: #define RECIPROCAL_PI2 0.15915494
59: #define LOG2 1.442695
60: #define EPSILON 1e-6
61: #ifndef saturate
62: #define saturate(a) clamp( a, 0.0, 1.0 )
63: #endif
64: #define whiteComplement(a) ( 1.0 - saturate( a ) )
65: float pow2( const in float x ) { return x*x; }
66: float pow3( const in float x ) { return x*x*x; }
67: float pow4( const in float x ) { float x2 = x*x; return x2*x2; }
68: float average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }
69: highp float rand( const in vec2 troika_uv_1 ) {
70: const highp float a = 12.9898, b = 78.233, c = 43758.5453;
71: highp float dt = dot( troika_uv_1.xy, vec2( a,b ) ), sn = mod( dt, PI );
72: return fract(sin(sn) * c);
73: }
74: #ifdef HIGH_PRECISION
75: float precisionSafeLength( vec3 v ) { return length( v ); }
76: #else
77: float max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }
78: float precisionSafeLength( vec3 v ) {
79: float maxComponent = max3( abs( v ) );
80: return length( v / maxComponent ) * maxComponent;
81: }
82: #endif
83: struct IncidentLight {
84: vec3 color;
85: vec3 direction;
86: bool visible;
87: };
88: struct ReflectedLight {
89: vec3 directDiffuse;
90: vec3 directSpecular;
91: vec3 indirectDiffuse;
92: vec3 indirectSpecular;
93: };
94: struct GeometricContext {
95: vec3 troika_position_1;
96: vec3 troika_normal_1;
97: vec3 viewDir;
98: #ifdef CLEARCOAT
99: vec3 clearcoatNormal;
100: #endif
101: };
102: vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
103: return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
104: }
105: vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {
106: return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );
107: }
108: vec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
109: float distance = dot( planeNormal, point - pointOnPlane );
110: return - distance * planeNormal + point;
111: }
112: float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
113: return sign( dot( point - pointOnPlane, planeNormal ) );
114: }
115: vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {
116: return lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;
117: }
118: mat3 transposeMat3( const in mat3 m ) {
119: mat3 tmp;
120: tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );
121: tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );
122: tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );
123: return tmp;
124: }
125: float linearToRelativeLuminance( const in vec3 color ) {
126: vec3 weights = vec3( 0.2126, 0.7152, 0.0722 );
127: return dot( weights, color.rgb );
128: }
129: bool isPerspectiveMatrix( mat4 m ) {
130: return m[ 2 ][ 3 ] == - 1.0;
131: }
132: #ifdef USE_UV
133: #ifdef UVS_VERTEX_ONLY
134: vec2 vUv;
135: #else
136: varying vec2 vUv;
137: #endif
138: uniform mat3 uvTransform;
139: #endif
140: #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )
141: attribute vec2 uv2;
142: varying vec2 vUv2;
143: uniform mat3 uv2Transform;
144: #endif
145: #ifdef USE_ENVMAP
146: #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )
147: #define ENV_WORLDPOS
148: #endif
149: #ifdef ENV_WORLDPOS
150:
151: varying vec3 vWorldPosition;
152: #else
153: varying vec3 vReflect;
154: uniform float refractionRatio;
155: #endif
156: #endif
157: #ifdef USE_COLOR
158: varying vec3 vColor;
159: #endif
160: #ifdef USE_FOG
161: varying float fogDepth;
162: #endif
163: #ifdef USE_MORPHTARGETS
164: uniform float morphTargetBaseInfluence;
165: #ifndef USE_MORPHNORMALS
166: uniform float morphTargetInfluences[ 8 ];
167: #else
168: uniform float morphTargetInfluences[ 4 ];
169: #endif
170: #endif
171: #ifdef USE_SKINNING
172: uniform mat4 bindMatrix;
173: uniform mat4 bindMatrixInverse;
174: #ifdef BONE_TEXTURE
175: uniform highp sampler2D boneTexture;
176: uniform int boneTextureSize;
177: mat4 getBoneMatrix( const in float i ) {
178: float j = i * 4.0;
179: float x = mod( j, float( boneTextureSize ) );
180: float y = floor( j / float( boneTextureSize ) );
181: float dx = 1.0 / float( boneTextureSize );
182: float dy = 1.0 / float( boneTextureSize );
183: y = dy * ( y + 0.5 );
184: vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );
185: vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );
186: vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );
187: vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );
188: mat4 bone = mat4( v1, v2, v3, v4 );
189: return bone;
190: }
191: #else
192: uniform mat4 boneMatrices[ MAX_BONES ];
193: mat4 getBoneMatrix( const in float i ) {
194: mat4 bone = boneMatrices[ int(i) ];
195: return bone;
196: }
197: #endif
198: #endif
199: #ifdef USE_LOGDEPTHBUF
200: #ifdef USE_LOGDEPTHBUF_EXT
201: varying float vFragDepth;
202: varying float vIsPerspective;
203: #else
204: uniform float logDepthBufFC;
205: #endif
206: #endif
207: #if 0 > 0
208: varying vec3 vClipPosition;
209: #endif
210: uniform vec3 diffuse;
211:
212:
213: uniform vec2 uTroikaSDFTextureSize;
214: uniform float uTroikaSDFGlyphSize;
215: uniform vec4 uTroikaTotalBounds;
216: uniform vec4 uTroikaClipRect;
217: uniform mat3 uTroikaOrient;
218: uniform bool uTroikaUseGlyphColors;
219: attribute vec4 aTroikaGlyphBounds;
220: attribute float aTroikaGlyphIndex;
221: attribute vec3 aTroikaGlyphColor;
222: varying vec2 vTroikaSDFTextureUV;
223: varying vec2 vTroikaGlyphUV;
224: varying vec3 vTroikaGlyphColor;
225:
226: vec3 troika_position_1;
227: vec3 troika_normal_1;
228: vec2 troika_uv_1;
229: void troikaVertexTransform1(inout vec3 troika_position_3, inout vec3 troika_normal_3, inout vec2 troika_uv_3) {
230:
231: vec4 bounds = aTroikaGlyphBounds;
232: vec4 clippedBounds = vec4(
233: clamp(bounds.xy, uTroikaClipRect.xy, uTroikaClipRect.zw),
234: clamp(bounds.zw, uTroikaClipRect.xy, uTroikaClipRect.zw)
235: );
236: vec2 clippedXY = (mix(clippedBounds.xy, clippedBounds.zw, troika_position_3.xy) - bounds.xy) / (bounds.zw - bounds.xy);
237: vTroikaGlyphUV = clippedXY.xy;
238:
239: float cols = uTroikaSDFTextureSize.x / uTroikaSDFGlyphSize;
240: vTroikaSDFTextureUV = vec2(
241: mod(aTroikaGlyphIndex, cols) + clippedXY.x,
242: floor(aTroikaGlyphIndex / cols) + clippedXY.y
243: ) * uTroikaSDFGlyphSize / uTroikaSDFTextureSize;
244:
245: troika_position_3.xy = mix(bounds.xy, bounds.zw, clippedXY);
246:
247: troika_uv_3 = vec2(
248: (troika_position_3.x - uTroikaTotalBounds.x) / (uTroikaTotalBounds.z - uTroikaTotalBounds.x),
249: (troika_position_3.y - uTroikaTotalBounds.y) / (uTroikaTotalBounds.w - uTroikaTotalBounds.y)
250: );
251:
252: troika_position_3 = uTroikaOrient * troika_position_3;
253: troika_normal_3 = uTroikaOrient * troika_normal_3;
254:
255: }
256:
257: void troikaOrigMain1() {
258: vTroikaGlyphColor = uTroikaUseGlyphColors ? aTroikaGlyphColor / 255.0 : diffuse;
259:
260: #ifdef USE_UV
261: vUv = ( uvTransform * vec3( troika_uv_1, 1 ) ).xy;
262: #endif
263: #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )
264: vUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;
265: #endif
266: #ifdef USE_COLOR
267: vColor.xyz = color.xyz;
268: #endif
269: #ifdef USE_SKINNING
270: mat4 boneMatX = getBoneMatrix( skinIndex.x );
271: mat4 boneMatY = getBoneMatrix( skinIndex.y );
272: mat4 boneMatZ = getBoneMatrix( skinIndex.z );
273: mat4 boneMatW = getBoneMatrix( skinIndex.w );
274: #endif
275: #ifdef USE_ENVMAP
276: vec3 objectNormal = vec3( troika_normal_1 );
277: #ifdef USE_TANGENT
278: vec3 objectTangent = vec3( tangent.xyz );
279: #endif
280: #ifdef USE_MORPHNORMALS
281: objectNormal *= morphTargetBaseInfluence;
282: objectNormal += morphNormal0 * morphTargetInfluences[ 0 ];
283: objectNormal += morphNormal1 * morphTargetInfluences[ 1 ];
284: objectNormal += morphNormal2 * morphTargetInfluences[ 2 ];
285: objectNormal += morphNormal3 * morphTargetInfluences[ 3 ];
286: #endif
287: #ifdef USE_SKINNING
288: mat4 skinMatrix = mat4( 0.0 );
289: skinMatrix += skinWeight.x * boneMatX;
290: skinMatrix += skinWeight.y * boneMatY;
291: skinMatrix += skinWeight.z * boneMatZ;
292: skinMatrix += skinWeight.w * boneMatW;
293: skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;
294: objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;
295: #ifdef USE_TANGENT
296: objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;
297: #endif
298: #endif
299: vec3 transformedNormal = objectNormal;
300: #ifdef USE_INSTANCING
301: mat3 m = mat3( instanceMatrix );
302: transformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );
303: transformedNormal = m * transformedNormal;
304: #endif
305: transformedNormal = normalMatrix * transformedNormal;
306: #ifdef FLIP_SIDED
307: transformedNormal = - transformedNormal;
308: #endif
309: #ifdef USE_TANGENT
310: vec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;
311: #ifdef FLIP_SIDED
312: transformedTangent = - transformedTangent;
313: #endif
314: #endif
315: #endif
316: vec3 transformed = vec3( troika_position_1 );
317: #ifdef USE_MORPHTARGETS
318: transformed *= morphTargetBaseInfluence;
319: transformed += morphTarget0 * morphTargetInfluences[ 0 ];
320: transformed += morphTarget1 * morphTargetInfluences[ 1 ];
321: transformed += morphTarget2 * morphTargetInfluences[ 2 ];
322: transformed += morphTarget3 * morphTargetInfluences[ 3 ];
323: #ifndef USE_MORPHNORMALS
324: transformed += morphTarget4 * morphTargetInfluences[ 4 ];
325: transformed += morphTarget5 * morphTargetInfluences[ 5 ];
326: transformed += morphTarget6 * morphTargetInfluences[ 6 ];
327: transformed += morphTarget7 * morphTargetInfluences[ 7 ];
328: #endif
329: #endif
330: #ifdef USE_SKINNING
331: vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );
332: vec4 skinned = vec4( 0.0 );
333: skinned += boneMatX * skinVertex * skinWeight.x;
334: skinned += boneMatY * skinVertex * skinWeight.y;
335: skinned += boneMatZ * skinVertex * skinWeight.z;
336: skinned += boneMatW * skinVertex * skinWeight.w;
337: transformed = ( bindMatrixInverse * skinned ).xyz;
338: #endif
339: vec4 mvPosition = vec4( transformed, 1.0 );
340: #ifdef USE_INSTANCING
341: mvPosition = instanceMatrix * mvPosition;
342: #endif
343: mvPosition = modelViewMatrix * mvPosition;
344: gl_Position = projectionMatrix * mvPosition;
345: #ifdef USE_LOGDEPTHBUF
346: #ifdef USE_LOGDEPTHBUF_EXT
347: vFragDepth = 1.0 + gl_Position.w;
348: vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );
349: #else
350: if ( isPerspectiveMatrix( projectionMatrix ) ) {
351: gl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;
352: gl_Position.z *= gl_Position.w;
353: }
354: #endif
355: #endif
356: #if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )
357: vec4 worldPosition = vec4( transformed, 1.0 );
358: #ifdef USE_INSTANCING
359: worldPosition = instanceMatrix * worldPosition;
360: #endif
361: worldPosition = modelMatrix * worldPosition;
362: #endif
363: #if 0 > 0
364: vClipPosition = - mvPosition.xyz;
365: #endif
366: #ifdef USE_ENVMAP
367: #ifdef ENV_WORLDPOS
368: vWorldPosition = worldPosition.xyz;
369: #else
370: vec3 cameraToVertex;
371: if ( isOrthographic ) {
372: cameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );
373: } else {
374: cameraToVertex = normalize( worldPosition.xyz - cameraPosition );
375: }
376: vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
377: #ifdef ENVMAP_MODE_REFLECTION
378: vReflect = reflect( cameraToVertex, worldNormal );
379: #else
380: vReflect = refract( cameraToVertex, worldNormal, refractionRatio );
381: #endif
382: #endif
383: #endif
384: #ifdef USE_FOG
385: fogDepth = -mvPosition.z;
386: #endif
387: }
388:
389:
390: uniform vec2 uTroikaSDFTextureSize;
391: uniform float uTroikaSDFGlyphSize;
392: uniform vec4 uTroikaTotalBounds;
393: uniform vec4 uTroikaClipRect;
394: uniform mat3 uTroikaOrient;
395: uniform bool uTroikaUseGlyphColors;
396: attribute vec4 aTroikaGlyphBounds;
397: attribute float aTroikaGlyphIndex;
398: attribute vec3 aTroikaGlyphColor;
399: varying vec2 vTroikaSDFTextureUV;
400: varying vec2 vTroikaGlyphUV;
401: varying vec3 vTroikaGlyphColor;
402:
403: vec3 troika_position_3;
404: vec3 troika_normal_3;
405: vec2 troika_uv_3;
406: void troikaVertexTransform3(inout vec3 position, inout vec3 normal, inout vec2 uv) {
407:
408: vec4 bounds = aTroikaGlyphBounds;
409: vec4 clippedBounds = vec4(
410: clamp(bounds.xy, uTroikaClipRect.xy, uTroikaClipRect.zw),
411: clamp(bounds.zw, uTroikaClipRect.xy, uTroikaClipRect.zw)
412: );
413: vec2 clippedXY = (mix(clippedBounds.xy, clippedBounds.zw, position.xy) - bounds.xy) / (bounds.zw - bounds.xy);
414: vTroikaGlyphUV = clippedXY.xy;
415:
416: float cols = uTroikaSDFTextureSize.x / uTroikaSDFGlyphSize;
417: vTroikaSDFTextureUV = vec2(
418: mod(aTroikaGlyphIndex, cols) + clippedXY.x,
419: floor(aTroikaGlyphIndex / cols) + clippedXY.y
420: ) * uTroikaSDFGlyphSize / uTroikaSDFTextureSize;
421:
422: position.xy = mix(bounds.xy, bounds.zw, clippedXY);
423:
424: uv = vec2(
425: (position.x - uTroikaTotalBounds.x) / (uTroikaTotalBounds.z - uTroikaTotalBounds.x),
426: (position.y - uTroikaTotalBounds.y) / (uTroikaTotalBounds.w - uTroikaTotalBounds.y)
427: );
428:
429: position = uTroikaOrient * position;
430: normal = uTroikaOrient * normal;
431:
432: }
433:
434: void troikaOrigMain3() {
435:
436: troika_position_1 = vec3(troika_position_3);
437: troika_normal_1 = vec3(troika_normal_3);
438: troika_uv_1 = vec2(troika_uv_3);
439: troikaVertexTransform1(troika_position_1, troika_normal_1, troika_uv_1);
440:
441:
442: troikaOrigMain1();
443:
444: }
445: void main() {
446:
447: troika_position_3 = vec3(position);
448: troika_normal_3 = vec3(normal);
449: troika_uv_3 = vec2(uv);
450: troikaVertexTransform3(troika_position_3, troika_normal_3, troika_uv_3);
451:
452:
453: troikaOrigMain3();
454:
455: }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.