Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Nicolas Rannou
Nicolas Rannou

Posted on • Edited on

     

Create textures from data in ThreeJS

I've been looking into creating a texture from data inthree.js. It is super easy, but there are some caveats, and some parts can be confusing. I fell into some traps many years ago, then fall into it again recently, so I decided to write about it!

Table of contents generated with markdown-toc

What is confusing (me)?

When creating a new texture, from data, you must set aFormat, aType, and provide you data in a specific type ofTypedArray.

consttexture=newDataTexture(data,width,height,format,type,...);

The doc says

"type" must correspond to the "format".

Ok... so how do I know whichType to set for theFormat I want to use?

Grayscale textures

In this post, I will only discuss grayscale (single channel) texture for WebGL1 since it is my current focus. Everything in the rest of this post will apply to whatever you are trying to support.

Which format

Alright, I want to create a single channel (grayscale) texture.
In the'internal format' section, you can find whichFormat is the best fit for you, depending on the number of channels and the bytes per pixel.

LUMINANCE is the natural fit for grayscale textures. The caveat is that it only supportsUnsignedByte texture type for Webgl1.

If you work with WebGL2,R* formats allow you to support a variety of different bit-depth.

To know more about what the different file format means, I found this page useful:https://www.khronos.org/opengl/wiki/Image_Format. It explains what the suffix of the file format means*F,*_SNORM means and how those type of textures are interpreted. That is important regarding the data normalization. (keep reading)

Luminance format allows three types (WebGL1)

Alright, we just learned that for WebGL1,Luminance format goes withUnsignedByte type.

Can we do better?

If your browser supports theOES_texture_float extension, a bunch of new types (Float andHalfFloat) are available for theLUMINANCE format. (official documentation)

FormatTypeByte per Pixel
RGBAFLOAT16
RGBFLOAT12
LUMINANCE_ALPHAFLOAT8
LUMINANCEFLOAT4
ALPHAFLOAT4
RGBAHALF_FLOAT_OES8
RGBHALF_FLOAT_OES6
LUMINANCE_ALPHAHALF_FLOAT_OES4
LUMINANCEHALF_FLOAT_OES2
ALPHAHALF_FLOAT_OES2

Type to TypedArray containing the data

It is pretty straight forward:

TypeByte per PixelTyped Array
UnsignedByte1Uint8Array
HalfFloat2Uint16Array
Float4Float32Array

What is important there is that the number of bits in the type array matches the byte per pixel in the table. Also, forHalfFloat the data should be prepared appropriately.

Access the data in the fragment shader

All the integer textures (includingUnsignedByteType) are normalized automatically while uploaded to the shaders, whereas the floating/integral textures (includingFloat andHalfFloat) are passed as it is.

Based on theFormat name, you can know with which type of data you are dealing with and whether that will be normalized for you or not. (ref).

In other words, in the fragment shader, when using anUnsignedByteType texture, the values you get from the texture 2D are normalized between 0 and 1 automatically. ForFloatType andHalfFloatType you get the value that was in the typed array without any normalization.

Gimme some concrete examples!

UnsignedByte Texture

consttextureSize=16constdataSize=10;constdata=newUint8Array(dataSize);for(leti=0;i<dataSize){data[i]=Math.round(Math.random()*255);// pass anything from 0 to 255}consttexture=newDataTexture(data,textureSize,textureSize,LUMINACE,UnsignedByteType);
varyingvec2vUv;uniformsampler2DuData;voidmain(){vec3color;vec4data=texture2D(uData,vUv);gl_FragColor=vec4(data.xyz,1.0);}

HalfFloat Texture

To convert a number to half float, do it thethree.js way:like this

⚠️ Watch out forprecision errors when converting numbers to half float precision!

consttextureSize=16constdataSize=10;constdata=newUint16Array(dataSize);for(leti=0;i<dataSize){constlargeNumber=Math.random()*10000;// pass anything from 0 to 10000data[i]=toHalfFloat(largeNumber);}consttexture=newDataTexture(data,textureSize,textureSize,LUMINACE,HalfFloatType);
varyingvec2vUv;uniformsampler2DuData;uniformfloatuMax;uniformfloatuMin;voidmain(){vec3color;vec4data=texture2D(uData,vUv);vec4normalizedData=(data-uMin)/(uMax-uMin);gl_FragColor=vec4(data.xyz,1.0);}

Float Texture

consttextureSize=16constdataSize=10;constdata=newFloat32Array(dataSize);for(leti=0;i<dataSize){constlargeNumber=Math.random()*10000;// pass anything from 0 to 10000data[i]=largeNumber;}consttexture=newDataTexture(data,textureSize,textureSize,LUMINACE,FloatType);
varyingvec2vUv;uniformsampler2DuData;uniformfloatuMax;uniformfloatuMin;voidmain(){vec3color;vec4data=texture2D(uData,vUv);vec4normalizedData=(data-uMin)/(uMax-uMin);gl_FragColor=vec4(data.xyz,1.0);}

Until next time!

Until next time 🙋‍♂️, happy coding!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp