From d6f5c1def3522abca32ddd62e5de725aa4f9500f Mon Sep 17 00:00:00 2001 From: Alexey Knyazev Date: Wed, 1 Mar 2017 03:02:32 +0400 Subject: [PATCH 1/4] Remove image specifications from texture object , make sampler optional, rename source to image --- specification/2.0/schema/texture.schema.json | 31 ++------------------ 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/specification/2.0/schema/texture.schema.json b/specification/2.0/schema/texture.schema.json index 4194c7bfde..8938fb7c75 100644 --- a/specification/2.0/schema/texture.schema.json +++ b/specification/2.0/schema/texture.schema.json @@ -5,29 +5,11 @@ "description" : "A texture and its sampler.", "allOf" : [ { "$ref" : "glTFChildOfRootProperty.schema.json" } ], "properties" : { - "format": { - "type" : "integer", - "description" : "The texture's format.", - "enum" : [6406, 6407, 6408, 6409, 6410], - "gltf_enumNames" : ["ALPHA", "RGB", "RGBA", "LUMINANCE", "LUMINANCE_ALPHA"], - "default" : 6408, - "gltf_detailedDescription" : "The texture's format. Valid values correspond to WebGL enums: `6406` (ALPHA), `6407` (RGB), `6408` (RGBA), `6409` (LUMINANCE), and `6410` (LUMINANCE_ALPHA).", - "gltf_webgl" : "`texImage2D()` format parameter" - }, - "internalFormat": { - "type" : "integer", - "description" : "The texture's internal format.", - "enum" : [6406, 6407, 6408, 6409, 6410], - "gltf_enumNames" : ["ALPHA", "RGB", "RGBA", "LUMINANCE", "LUMINANCE_ALPHA"], - "default" : 6408, - "gltf_detailedDescription" : "The texture's internal format. Valid values correspond to WebGL enums: `6406` (ALPHA), `6407` (RGB), `6408` (RGBA), `6409` (LUMINANCE), and `6410` (LUMINANCE_ALPHA). Defaults to same value as format.", - "gltf_webgl" : "`texImage2D()` internalFormat parameter" - }, "sampler" : { "allOf" : [ { "$ref" : "glTFid.schema.json" } ], "description" : "The index of the sampler used by this texture." }, - "source" : { + "image" : { "allOf" : [ { "$ref" : "glTFid.schema.json" } ], "description" : "The index of the image used by this texture." }, @@ -40,20 +22,11 @@ "gltf_detailedDescription" : "The target that the WebGL texture should be bound to. Valid values correspond to WebGL enums: `3553` (TEXTURE_2D).", "gltf_webgl" : "`bindTexture()`" }, - "type": { - "type" : "integer", - "description" : "Texel datatype.", - "enum" : [5121, 33635, 32819, 32820], - "gltf_enumNames" : ["UNSIGNED_BYTE", "UNSIGNED_SHORT_5_6_5", "UNSIGNED_SHORT_4_4_4_4", "UNSIGNED_SHORT_5_5_5_1"], - "default" : 5121, - "gltf_detailedDescription" : "Texel datatype. Valid values correspond to WebGL enums: `5121` (UNSIGNED_BYTE), `33635` (UNSIGNED_SHORT_5_6_5), `32819` (UNSIGNED_SHORT_4_4_4_4), and `32820` (UNSIGNED_SHORT_5_5_5_1).", - "gltf_webgl" : "`texImage2D()` type parameter" - }, "name" : {}, "extensions" : {}, "extras" : {} }, "additionalProperties" : false, "gltf_webgl" : "`createTexture()`, `deleteTexture()`, `bindTexture()`, `texImage2D()`, and `texParameterf()`", - "required": ["sampler", "source"] + "required": ["image"] } From adbf2dc4d52f7695fbb20c5e2716cec68d8aa3c4 Mon Sep 17 00:00:00 2001 From: Alexey Knyazev Date: Wed, 1 Mar 2017 03:03:32 +0400 Subject: [PATCH 2/4] Move image sources into sub-array --- specification/2.0/schema/image.schema.json | 30 +++++++--------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/specification/2.0/schema/image.schema.json b/specification/2.0/schema/image.schema.json index aa382e8cc8..456068c0be 100644 --- a/specification/2.0/schema/image.schema.json +++ b/specification/2.0/schema/image.schema.json @@ -2,32 +2,20 @@ "$schema" : "http://json-schema.org/draft-04/schema", "title" : "image", "type" : "object", - "description" : "Image data used to create a texture. Image can be referenced by URI or `bufferView` index. `mimeType` is required in the latter case.", + "description" : "Image data used to create a texture. Image can have different representations, defined in `sources` array.", "allOf" : [ { "$ref" : "glTFChildOfRootProperty.schema.json" } ], "properties" : { - "uri" : { - "type" : "string", - "description" : "The uri of the image.", - "format" : "uriref", - "gltf_detailedDescription" : "The uri of the image. Relative paths are relative to the .gltf file. Instead of referencing an external file, the uri can also be a data-uri. The image format must be jpg, png, bmp, or gif.", - "gltf_uriType" : "image" - }, - "mimeType" : { - "type" : "string", - "description" : "The image's MIME type.", - "minLength" : 1 - }, - "bufferView" : { - "allOf" : [ { "$ref" : "glTFid.schema.json" } ], - "description" : "The index of the bufferView that contains the image. Use this instead of the image's uri property.", - "minLength" : 1 + "sources" : { + "type" : "array", + "description" : "An array of image sources.", + "items" : { + "$ref" : "image.source.schema.json" + }, + "minItems" : 1 }, "name" : {}, "extensions" : {}, "extras" : {} }, - "additionalProperties" : false, - "dependencies" : { - "bufferView" : ["mimeType"] - } + "additionalProperties" : false } From 56c7b1bc7d66476c210b0a4492e155cbf4ec18fb Mon Sep 17 00:00:00 2001 From: Alexey Knyazev Date: Wed, 1 Mar 2017 21:54:57 +0400 Subject: [PATCH 3/4] Update image.source schema --- .../2.0/schema/image.source.schema.json | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 specification/2.0/schema/image.source.schema.json diff --git a/specification/2.0/schema/image.source.schema.json b/specification/2.0/schema/image.source.schema.json new file mode 100644 index 0000000000..10ac066b3a --- /dev/null +++ b/specification/2.0/schema/image.source.schema.json @@ -0,0 +1,48 @@ +{ + "$schema" : "http://json-schema.org/draft-04/schema", + "title" : "source", + "type" : "object", + "description" : "Image source used to create a texture. Image source can be defined by an array of URI or `bufferView`s.", + "allOf" : [ { "$ref" : "glTFProperty.schema.json" } ], + "properties" : { + "internalFormat": { + "type" : "integer", + "description" : "The texture's internal format.", + "enum" : [6406, 6409, 6410, 32849, 32854, 32855, 32856, 35905, 35907, 36194], + "gltf_enumNames" : ["GL_ALPHA", "GL_LUMINANCE", "GL_LUMINANCE_ALPHA", "GL_RGB8", "GL_RGBA4", "GL_RGB5_A1", "GL_RGBA8", "GL_SRGB8", "GL_SRGB8_ALPHA8", "GL_RGB565"], + "default" : 32856, + "gltf_detailedDescription" : "The texture's internal format. Valid values correspond to GL enums: `6406` (ALPHA), `6409` (LUMINANCE), `6410` (LUMINANCE_ALPHA), `32849` (RGB8), `32854` (RGBA4), `32855` (RGB5_A1), `32856` (RGBA8), `35905` (SRGB8), `35907` (SRGB8_ALPHA8), `36194` (RGB565)", + "gltf_webgl" : "`texImage2D()` internalFormat parameter" + }, + "mimeType" : { + "type" : "string", + "description" : "The image's MIME type.", + "enum" : ["image/jpeg", "image/png"] + }, + "uris" : { + "type" : "array", + "description" : "The array with uris of the images.", + "items" : { + "type" : "string", + "format" : "uriref" + }, + "minItems" : 1, + "maxItems" : 1, + "gltf_detailedDescription" : "The array with uris of the images. Relative paths are relative to the .gltf file. Instead of referencing an external file, the uri can also be a data-uri. The image format must match mimeType.", + "gltf_uriType" : "image" + }, + "bufferViews" : { + "type" : "array", + "description" : "The array with indices of the bufferViews that contains the images. Use this instead of the `uris` property.", + "items" : { + "allOf" : [ { "$ref" : "glTFid.schema.json" } ] + }, + "minItems" : 1, + "maxItems" : 1 + }, + "extensions" : {}, + "extras" : {} + }, + "additionalProperties" : false, + "required" : ["mimeType"] +} From 5b4214cd38c76f515927c969030ae8960e68aefa Mon Sep 17 00:00:00 2001 From: Alexey Knyazev Date: Wed, 1 Mar 2017 21:55:16 +0400 Subject: [PATCH 4/4] Update README.md on textures --- specification/2.0/README.md | 97 ++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/specification/2.0/README.md b/specification/2.0/README.md index 359c0a0d43..acd3c7b813 100644 --- a/specification/2.0/README.md +++ b/specification/2.0/README.md @@ -57,6 +57,7 @@ Copyright (C) 2013-2017 The Khronos Group Inc. All Rights Reserved. glTF is a tr * [Texture Data](#texture-data) * [Textures](#textures) * [Images](#images) + * [Image Formats](#image-formats) * [Samplers](#samplers) * [Materials](#materials) * [Metallic-Roughness Material](#metallic-roughness-material) @@ -831,57 +832,108 @@ A skin is instanced within a node using a combination of the node's `mesh` and ` ## Texture Data -**TODO: describe separation of concerns: textures / images / samplers** +glTF separates texture access into three distinct types of objects: Textures, Images, and Samplers. ### Textures -**TODO: update to latest revisions** - -All textures are stored in the asset's `textures` array. A texture is defined by an image file, denoted by the `source` property; `format` and `internalFormat` specifiers, corresponding to the GL texture format types; a `target` type for the sampler; a sampler identifier (`sampler`), and a `type` property defining the internal data format. Refer to the GL definition of `texImage2D()` for more details. +All textures are stored in the asset's `textures` array. A texture is defined by an image resource, denoted by the `image` property; a `target` type for the sampler; and a sampler index (`sampler`). +When `sampler` is omitted, a sampler with all-default properties should be used. ```json { "textures": [ { - "format": 6408, - "internalFormat": 6408, - "sampler": 0, - "source": 2, "target": 3553, - "type": 5121 + "image": 2, + "sampler": 0 } ] } ``` +> **Implementation Note** glTF 2.0 supports only 2D texture targets. Support for other targets is expected in future revisions. + ### Images -**TODO: update to latest revisions** +Images referred by textures are stored in the `images` array of the asset. + +Each `image` defines an `image.sources` set of image sources. Type and format of image source are defined by `mimeType` and `internalFormat` specifiers. + +An image source can refer to image data either by array of URIs (external or base64-encoded), or by array of Buffer Views. + +> **Implementation Note** glTF 2.0 requires these arrays to contain no more than one element. This restriction could be lifted in future to support more texture targets. + +First image pixel corresponds to the lower left corner of the image. + +> **Implementation Note**: With WebGL API, the first pixel transferred from the `TexImageSource` (i.e., HTML Image object) to the WebGL implementation corresponds to the upper left corner of the source. To achieve correct rendering, WebGL runtimes must flip Y axis by enabling `UNPACK_FLIP_Y_WEBGL` flag. This behavior was changed from glTF 1.0. -Images referred to by textures are stored in the `images` array of the asset. Each image contains a URI to an external file (or a reference to a bufferView) in one of the supported images formats. Image data may also be stored within the glTF file as base64-encoded data and referenced via data URI. For example: +Any colorspace information (such as ICC profiles, intents, etc) from PNG or JPEG containers must be ignored. + +> **Implementation Note**: This increases portability of an asset, since not all image decoding libraries fully support custom color conversions. To achieve correct rendering, WebGL runtimes must disable such conversions by setting `UNPACK_COLORSPACE_CONVERSION_WEBGL` flag to `NONE`. + +In the following example asset provides two versions of the same image: in sRGB and in linear colorspaces; so clients with hardware sRGB filtering support (or with enough fragment shader processing power) benefit from reduced banding, whilst low-power clients still get correct texel values by using linear-space image data directly. ```json { "images": [ { - "uri": "duckCM.png" - }, - { - "bufferView": 14, - "mimeType": "image/jpeg" + "sources": [ + { + "internalformat": 32856, + "mimeType": "image/png", + "uris": ["duck_diffuse_linear.png"] + }, + { + "internalformat": 35907, + "mimeType": "image/png", + "uris": ["duck_diffuse_srgb.png"] + } + ] } ] } ``` -> **Implementation Note**: With WebGL API, the first pixel transferred from the `TexImageSource` (i.e., HTML Image object) to the WebGL implementation corresponds to the upper left corner of the source. Non-WebGL runtimes may need to flip Y axis to achieve correct texture rendering. -### Samplers +#### Image Formats + +glTF 2.0 allows a limited set of possible `internalformat` values based on OpenGL ES 3.0 enums. + +Each `internalformat` value defines exactly one matching pair of `type` and `format` parameters of OpenGL ES 2.0/3.0 texture specification. See table below for details: + +| `source.internalformat` | OpenGL ES 2.0 Format & Internal Format | OpenGL ES 3.0 Format | OpenGL ES 3.0 Internal Format | OpenGL ES 2.0/3.0 Type | +|-------------------------|----------------------------------------|----------------------|-------------------------------|---------------------------| +| ALPHA (`6406`) | ALPHA | ALPHA | ALPHA | UNSIGNED_BYTE | +| LUMINANCE (`6409`) | LUMINANCE | LUMINANCE | LUMINANCE | UNSIGNED_BYTE | +| LUMINANCE_ALPHA (`6410`) | LUMINANCE_ALPHA | LUMINANCE_ALPHA | LUMINANCE_ALPHA | UNSIGNED_BYTE | +| RGB8 (`32849`) | RGB | RGB | RGB8 | UNSIGNED_BYTE | +| RGBA4 (`32854`) | RGBA | RGBA | RGBA4 | UNSIGNED_SHORT_4_4_4_4 | +| RGB5_A1 (`32855`) | RGBA | RGBA | RGB5_A1 | UNSIGNED_SHORT_5_5_5_1 | +| RGBA8 (`32856`) | RGBA | RGBA | RGBA8 | UNSIGNED_BYTE | +| SRGB8 (`35905`) | SRGB_EXT | RGB | SRGB8 | UNSIGNED_BYTE | +| SRGB8_ALPHA8 (`35907`) | SRGB_ALPHA_EXT | RGBA | SRGB8_ALPHA8 | UNSIGNED_BYTE | +| RGB565 (`36194`) | RGB | RGB | RGB565 | UNSIGNED_SHORT_5_6_5 | + +These formats are usually supported by non-OpenGL APIs as well. See the following table for matches with Vulkan, D3D11/12, and Metal: + +| `source.internalformat` | Vulkan | D3D11/12 | Metal | +|-------------------------|------------------------------------|-------------------------------------------|-----------------------------------------| +| ALPHA (`6406`) | _expand to VK_FORMAT_R8G8B8A8_UNORM_ | DXGI_FORMAT_A8_UNORM | MTLPixelFormatA8Unorm | +| LUMINANCE (`6409`) | _expand to VK_FORMAT_R8G8B8_UNORM_ | _expand to DXGI_FORMAT_R8G8B8A8_UNORM_ | _expand to MTLPixelFormatRGBA8Unorm_ | +| LUMINANCE_ALPHA (`6410`) | _expand to VK_FORMAT_R8G8B8A8_UNORM_ | _expand to DXGI_FORMAT_R8G8B8A8_UNORM_ | _expand to MTLPixelFormatRGBA8Unorm_ | +| RGB8 (`32849`) | VK_FORMAT_R8G8B8_UNORM | _expand to DXGI_FORMAT_R8G8B8A8_UNORM_ | _expand to MTLPixelFormatRGBA8Unorm_ | +| RGBA4 (`32854`) | VK_FORMAT_R4G4B4A4_UNORM_PACK16 | _repack to DXGI_FORMAT_B4G4R4A4_UNORM_ | MTLPixelFormatABGR4Unorm | +| RGB5_A1 (`32855`) | VK_FORMAT_R5G5B5A1_UNORM_PACK16 | _repack to DXGI_FORMAT_B5G5R5A1_UNORM_ | MTLPixelFormatA1BGR5Unorm | +| RGBA8 (`32856`) | VK_FORMAT_R8G8B8A8_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM | MTLPixelFormatRGBA8Unorm | +| SRGB8 (`35905`) | VK_FORMAT_R8G8B8_SRGB | _expand to DXGI_FORMAT_R8G8B8A8_UNORM_SRGB_ | _expand to MTLPixelFormatRGBA8Unorm_sRGB_ | +| SRGB8_ALPHA8 (`35907`) | VK_FORMAT_R8G8B8A8_SRGB | DXGI_FORMAT_R8G8B8A8_UNORM_SRGB | MTLPixelFormatRGBA8Unorm_sRGB | +| RGB565 (`36194`) | VK_FORMAT_R5G6B5_UNORM_PACK16 | DXGI_FORMAT_B5G6R5_UNORM | MTLPixelFormatB5G6R5Unorm | + +For formats without direct matches, engines could utilize channel swizzling instead of expanding. -**TODO: update to latest revisions** +### Samplers Samplers are stored in the `samplers` array of the asset. Each sampler specifies filter and wrapping options corresponding to the GL types. The following example defines a sampler with linear mag filtering, linear mipmap min filtering, and repeat wrapping in S and T. - ```json { "samplers": [ @@ -897,10 +949,9 @@ Samplers are stored in the `samplers` array of the asset. Each sampler specifies > **Mipmapping Implementation Note**: When a sampler's minification filter (`minFilter`) uses mipmapping (`NEAREST_MIPMAP_NEAREST`, `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`, or `LINEAR_MIPMAP_LINEAR`), any texture referencing the sampler needs to have mipmaps, e.g., by calling GL's `generateMipmap()` function. - > **Non-Power-Of-Two Texture Implementation Note**: glTF does not guarantee that a texture's dimensions are a power-of-two. At runtime, if a texture's width or height is not a power-of-two, the texture needs to be resized so its dimensions are powers-of-two if the `sampler` the texture references -> * Has a wrapping mode (either `wrapS` or `wrapT`) equal to `REPEAT` or `MIRRORED_REPEAT`, or -> * Has a minification filter (`minFilter`) that uses mipmapping (`NEAREST_MIPMAP_NEAREST`, `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`, or `LINEAR_MIPMAP_LINEAR`). +> * has a wrapping mode (either `wrapS` or `wrapT`) equal to `REPEAT` or `MIRRORED_REPEAT`, or +> * has a minification filter (`minFilter`) that uses mipmapping (`NEAREST_MIPMAP_NEAREST`, `NEAREST_MIPMAP_LINEAR`, `LINEAR_MIPMAP_NEAREST`, or `LINEAR_MIPMAP_LINEAR`). ## Materials