The texture module provides classes for managing texture data and sampling.
import io.materia.texture.*
Base class for all textures.
class Texture(
image: Image? = null,
mapping: TextureMapping = TextureMapping.UV,
wrapS: TextureWrapping = TextureWrapping.CLAMP_TO_EDGE,
wrapT: TextureWrapping = TextureWrapping.CLAMP_TO_EDGE,
magFilter: TextureFilter = TextureFilter.LINEAR,
minFilter: TextureFilter = TextureFilter.LINEAR_MIPMAP_LINEAR,
format: TextureFormat = TextureFormat.RGBA,
type: TextureDataType = TextureDataType.UNSIGNED_BYTE,
anisotropy: Int = 1
)
| Property | Type | Default | Description |
|---|---|---|---|
id |
Int |
auto | Unique identifier |
uuid |
String |
auto | UUID string |
name |
String |
"" |
Optional name |
image |
Image? |
null |
Source image |
mipmaps |
List<Image> |
[] |
Mipmap levels |
mapping |
TextureMapping |
UV |
Mapping mode |
wrapS |
TextureWrapping |
CLAMP |
Horizontal wrap |
wrapT |
TextureWrapping |
CLAMP |
Vertical wrap |
magFilter |
TextureFilter |
LINEAR |
Magnification filter |
minFilter |
TextureFilter |
LINEAR_MIPMAP_LINEAR |
Minification filter |
anisotropy |
Int |
1 |
Anisotropic filtering |
format |
TextureFormat |
RGBA |
Pixel format |
internalFormat |
String? |
null |
Internal GPU format |
type |
TextureDataType |
UNSIGNED_BYTE |
Data type |
offset |
Vector2 |
(0,0) |
UV offset |
repeat |
Vector2 |
(1,1) |
UV repeat |
center |
Vector2 |
(0,0) |
Rotation center |
rotation |
Float |
0 |
Rotation (radians) |
generateMipmaps |
Boolean |
true |
Auto-generate mipmaps |
premultiplyAlpha |
Boolean |
false |
Premultiply alpha |
flipY |
Boolean |
true |
Flip Y on upload |
unpackAlignment |
Int |
4 |
Byte alignment |
colorSpace |
ColorSpace |
SRGB |
Color space |
needsUpdate |
Boolean |
false |
Needs GPU upload |
userData |
Map<String, Any> |
{} |
Custom data |
enum class TextureMapping {
UV, // Standard UV mapping
CUBE_REFLECTION, // Cube map reflection
CUBE_REFRACTION, // Cube map refraction
EQUIRECTANGULAR_REFLECTION, // Equirectangular reflection
EQUIRECTANGULAR_REFRACTION // Equirectangular refraction
}
enum class TextureWrapping {
REPEAT, // Tile texture
CLAMP_TO_EDGE, // Clamp to edge
MIRRORED_REPEAT // Mirror and tile
}
enum class TextureFilter {
NEAREST, // Nearest neighbor
NEAREST_MIPMAP_NEAREST, // Nearest with nearest mipmap
NEAREST_MIPMAP_LINEAR, // Nearest with linear mipmap
LINEAR, // Bilinear
LINEAR_MIPMAP_NEAREST, // Bilinear with nearest mipmap
LINEAR_MIPMAP_LINEAR // Trilinear
}
enum class TextureFormat {
ALPHA,
RED,
RED_INTEGER,
RG,
RG_INTEGER,
RGB,
RGB_INTEGER,
RGBA,
RGBA_INTEGER,
LUMINANCE,
LUMINANCE_ALPHA,
DEPTH,
DEPTH_STENCIL
}
enum class TextureDataType {
UNSIGNED_BYTE,
BYTE,
SHORT,
UNSIGNED_SHORT,
INT,
UNSIGNED_INT,
FLOAT,
HALF_FLOAT,
UNSIGNED_INT_24_8,
UNSIGNED_SHORT_4_4_4_4,
UNSIGNED_SHORT_5_5_5_1,
UNSIGNED_SHORT_5_6_5
}
// Update transform matrix from offset, repeat, rotation, center
fun updateMatrix()
// Clone texture
fun clone(): Texture
// Copy from another texture
fun copy(source: Texture): Texture
// Convert to JSON
fun toJSON(meta: Any? = null): JsonObject
// Dispose GPU resources
fun dispose()
// Transform UV
fun transformUv(uv: Vector2): Vector2
// Load and configure texture
val texture = textureLoader.load("textures/brick.jpg")
texture.wrapS = TextureWrapping.REPEAT
texture.wrapT = TextureWrapping.REPEAT
texture.repeat.set(4f, 4f)
texture.anisotropy = renderer.capabilities.maxAnisotropy
// Offset and rotate
texture.offset.set(0.5f, 0f)
texture.center.set(0.5f, 0.5f)
texture.rotation = PI / 4
// Apply to material
material.map = texture
Texture from raw pixel data.
class DataTexture(
data: ByteArray,
width: Int,
height: Int,
format: TextureFormat = TextureFormat.RGBA,
type: TextureDataType = TextureDataType.UNSIGNED_BYTE
)
// Create checkerboard texture
val size = 64
val data = ByteArray(size * size * 4)
for (y in 0 until size) {
for (x in 0 until size) {
val i = (y * size + x) * 4
val isWhite = (x / 8 + y / 8) % 2 == 0
val value = if (isWhite) 255.toByte() else 0.toByte()
data[i] = value // R
data[i + 1] = value // G
data[i + 2] = value // B
data[i + 3] = 255.toByte() // A
}
}
val texture = DataTexture(data, size, size)
texture.needsUpdate = true
3D texture (volume).
class Data3DTexture(
data: ByteArray,
width: Int,
height: Int,
depth: Int
)
| Property | Type | Description |
|---|---|---|
wrapR |
TextureWrapping |
Depth wrap mode |
// Create 3D noise texture
val size = 32
val data = ByteArray(size * size * size)
for (z in 0 until size) {
for (y in 0 until size) {
for (x in 0 until size) {
val i = z * size * size + y * size + x
data[i] = (noise3D(x, y, z) * 255).toByte()
}
}
}
val texture = Data3DTexture(data, size, size, size)
texture.format = TextureFormat.RED
Array of 2D textures.
class DataArrayTexture(
data: ByteArray,
width: Int,
height: Int,
depth: Int // Number of layers
)
GPU-compressed texture.
class CompressedTexture(
mipmaps: List<CompressedMipmap>,
width: Int,
height: Int,
format: CompressedTextureFormat,
type: TextureDataType = TextureDataType.UNSIGNED_BYTE
)
enum class CompressedTextureFormat {
// S3TC (Desktop)
RGB_S3TC_DXT1,
RGBA_S3TC_DXT1,
RGBA_S3TC_DXT3,
RGBA_S3TC_DXT5,
// PVRTC (iOS)
RGB_PVRTC_4BPPV1,
RGB_PVRTC_2BPPV1,
RGBA_PVRTC_4BPPV1,
RGBA_PVRTC_2BPPV1,
// ETC
RGB_ETC1,
RGB_ETC2,
RGBA_ETC2_EAC,
// ASTC
RGBA_ASTC_4x4,
RGBA_ASTC_5x4,
RGBA_ASTC_5x5,
RGBA_ASTC_6x5,
RGBA_ASTC_6x6,
RGBA_ASTC_8x5,
RGBA_ASTC_8x6,
RGBA_ASTC_8x8,
RGBA_ASTC_10x5,
RGBA_ASTC_10x6,
RGBA_ASTC_10x8,
RGBA_ASTC_10x10,
RGBA_ASTC_12x10,
RGBA_ASTC_12x12,
// BPTC
RGBA_BPTC,
RGB_BPTC_SIGNED,
RGB_BPTC_UNSIGNED
}
Cube map texture for skyboxes and environment maps.
class CubeTexture(
images: Array<Image> = Array(6) { null },
mapping: TextureMapping = TextureMapping.CUBE_REFLECTION
)
// images[0] = positive X (right)
// images[1] = negative X (left)
// images[2] = positive Y (top)
// images[3] = negative Y (bottom)
// images[4] = positive Z (front)
// images[5] = negative Z (back)
val cubeTexture = cubeTextureLoader.load(arrayOf(
"px.jpg", "nx.jpg",
"py.jpg", "ny.jpg",
"pz.jpg", "nz.jpg"
))
// As skybox
scene.background = cubeTexture
// As environment map
scene.environment = cubeTexture
// On material
material.envMap = cubeTexture
material.envMapIntensity = 1.0f
Texture from HTML Canvas.
class CanvasTexture(
canvas: HTMLCanvasElement,
mapping: TextureMapping = TextureMapping.UV
)
// Create canvas
val canvas = document.createElement("canvas") as HTMLCanvasElement
canvas.width = 256
canvas.height = 256
val ctx = canvas.getContext("2d") as CanvasRenderingContext2D
ctx.fillStyle = "red"
ctx.fillRect(0, 0, 256, 256)
ctx.fillStyle = "white"
ctx.font = "48px sans-serif"
ctx.fillText("Hello!", 50, 128)
// Create texture
val texture = CanvasTexture(canvas)
// Update after drawing
ctx.fillStyle = "blue"
ctx.fillRect(100, 100, 50, 50)
texture.needsUpdate = true
Texture from HTML Video.
class VideoTexture(
video: HTMLVideoElement,
mapping: TextureMapping = TextureMapping.UV
)
// Create video element
val video = document.createElement("video") as HTMLVideoElement
video.src = "video/movie.mp4"
video.loop = true
video.muted = true
video.play()
// Create texture
val texture = VideoTexture(video)
texture.colorSpace = ColorSpace.SRGB
// Apply to material
material.map = texture
// Texture auto-updates each frame
Texture for storing depth information.
class DepthTexture(
width: Int,
height: Int,
type: TextureDataType = TextureDataType.UNSIGNED_INT,
mapping: TextureMapping = TextureMapping.UV
)
// Create render target with depth texture
val depthTexture = DepthTexture(1024, 1024)
val renderTarget = RenderTarget(1024, 1024, RenderTargetOptions(
depthTexture = depthTexture
))
// Render to target
renderer.setRenderTarget(renderTarget)
renderer.render(scene, camera)
// Use depth texture
depthMaterial.map = renderTarget.depthTexture
Texture backed by framebuffer for copyTexImage.
class FramebufferTexture(
width: Int,
height: Int
)
Generates prefiltered environment maps for IBL.
class PMREMGenerator(renderer: Renderer) {
// From equirectangular texture
fun fromEquirectangular(texture: Texture): RenderTarget
// From cube texture
fun fromCubemap(cubeTexture: CubeTexture): RenderTarget
// From scene (capture environment)
fun fromScene(scene: Scene, sigma: Float = 0f, near: Float = 0.1f, far: Float = 100f): RenderTarget
// Compile shaders
fun compileEquirectangularShader()
fun compileCubemapShader()
// Dispose
fun dispose()
}
val pmremGenerator = PMREMGenerator(renderer)
// From HDR environment
rgbeLoader.load("environment.hdr") { texture ->
val envMap = pmremGenerator.fromEquirectangular(texture).texture
scene.environment = envMap
texture.dispose()
}
pmremGenerator.dispose()
Explicit sampler state.
class Sampler(
addressModeU: AddressMode = AddressMode.CLAMP_TO_EDGE,
addressModeV: AddressMode = AddressMode.CLAMP_TO_EDGE,
addressModeW: AddressMode = AddressMode.CLAMP_TO_EDGE,
magFilter: FilterMode = FilterMode.LINEAR,
minFilter: FilterMode = FilterMode.LINEAR,
mipmapFilter: MipmapFilterMode = MipmapFilterMode.LINEAR,
lodMinClamp: Float = 0f,
lodMaxClamp: Float = 32f,
compare: CompareFunction? = null,
maxAnisotropy: Int = 1
)
enum class AddressMode {
CLAMP_TO_EDGE,
REPEAT,
MIRROR_REPEAT
}
enum class FilterMode {
NEAREST,
LINEAR
}
enum class MipmapFilterMode {
NEAREST,
LINEAR
}
val texture = textureLoader.load("textures/tile.jpg")
texture.wrapS = TextureWrapping.REPEAT
texture.wrapT = TextureWrapping.REPEAT
texture.repeat.set(10f, 10f) // Tile 10x10
fun animate(time: Float) {
texture.offset.x = time * 0.1f // Scroll horizontally
// No needsUpdate needed for offset/repeat
}
val texture = textureLoader.load("textures/spritesheet.png")
texture.magFilter = TextureFilter.NEAREST // Pixel art
// 4x4 sprite sheet, show sprite at (col, row)
fun setSprite(col: Int, row: Int) {
texture.offset.set(col / 4f, 1 - (row + 1) / 4f)
texture.repeat.set(0.25f, 0.25f)
}
val renderTarget = RenderTarget(512, 512)
fun renderToTexture() {
renderer.setRenderTarget(renderTarget)
renderer.clear()
renderer.render(offscreenScene, offscreenCamera)
renderer.setRenderTarget(null)
}
// Use as texture
screenMaterial.map = renderTarget.texture
