Skip to content

Commit

Permalink
Load data for KHR_materials_anisotropy
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeshurun Hembd committed May 11, 2024
1 parent e2e9226 commit c48cad5
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 16 deletions.
15 changes: 15 additions & 0 deletions Specs/Data/Models/glTF-2.0/AnisotropyRotationTest/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# LICENSE file for the model: Anisotropy Rotation Test

All files in this directory tree are licensed as indicated below.

- All files directly associated with the model including all text, image and binary files:

- [CC BY 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"]

- This file and all other metadocumentation files including "metadata.json":

- [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"]

Full license text of these licenses are available at the links above

#### Generated by modelmetadata
57 changes: 57 additions & 0 deletions Specs/Data/Models/glTF-2.0/AnisotropyRotationTest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Anisotropy Rotation Test

## Tags

[extension](../../Models-extension.md), [testing](../../Models-testing.md)

## Extensions Used

- KHR_materials_anisotropy

## Summary

This model tests rotational offsets for KHR_materials_anisotropy.

## Operations

- [Display](https://github.khronos.org/glTF-Sample-Viewer-Release/?model=https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/AnisotropyRotationTest/glTF-Binary/AnisotropyRotationTest.glb) in SampleViewer
- [Download GLB](https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/AnisotropyRotationTest/glTF-Binary/AnisotropyRotationTest.glb)
- [Model Directory](./)

## Screenshot

![screenshot](screenshot/screenshot-large.png)

## Description

This model tests rotational offsets for [`KHR_materials_anisotropy`](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy). It has the following features:

- Six of the meshes (2 on the bottom row, 2 in the middle, and 2 on the top row) are all "simple" anisotropy with material roughness extended horizontally along the mesh's `TANGENT` vectors.

- One mesh in the lower-left marked "Tangents + Rotation" has a 30-degree clockwise tilt to the `TANGENT` vectors, and un-does this rotation using the `anisotropyRotation` parameter in radians equivalent to 30 degrees counter-clockwise. When the rotation is applied correctly, the anisotropy here should look the same as the neighboring meshes.

- One mesh in the upper-left marked "Tangents + Texture" has the same 30-degree clockwise tilt to the `TANGENT` vectors, and un-does this rotation using the `anisotropyTexture` parameter with a 30-degree counter-clockwise tilt encoded in the texture. As before, when the rotation is applied correctly, the anisotropy here should look the same as the neighboring meshes.

- One mesh in the lower-right marked "Tangents + Texture + Rotation" has again the same 30-degree clockwise tilt to the `TANGENT` vectors as the others. However this mesh uses a combination of 10 degrees from `anisotropyTexture` and 20 degrees (in radians) from `anisotropyRotation`, combining to create the 30-degree counter-clockwise tilt needed to make the anisotropy horizontal like the other meshes.

- Finally, one mesh in the upper-right marked "Normal map of grooves" has no anisotropy applied at all. It has a (somewhat grainy) normal texture applied with a series of vertical grooves, intended to approximate the look of very coarse horizontal anisotropy. It will not look exactly the same as its neighbors, but a bright light source in the environment should still spread out horizontally like its neighbors.

## IBL Example

![IBL screenshot](screenshot/ibl-example.png)

With a full IBL reflection environment, the model should show horizontal stretching. It may appear similar to the screenshot above.

## Incorrect Rotation Example

![rotation failure screenshot](screenshot/fail-example.png)

In the above image, the six "Basic Anisotropy" meshes are correct. But on the left side, both the texture-based rotation and JSON-based rotation are incorrect, and in the lower-right, the combination of both is also incorrect. These test meshes use a 30-degree clockwise slant in the tangent vectors that is intended to be undone by a 30-degree counter-clockwise rotation in the material. However in this image, a 60-degree clockwise rotation is visible on all three of these meshes, indicating that the material rotated the opposite way.

## Legal

© 2023, Analytical Graphics, Inc.. [CC BY 4.0 International](https://creativecommons.org/licenses/by/4.0/legalcode)

- Ed Mackey for Everything

### Assembled by modelmetadata
Binary file not shown.
25 changes: 25 additions & 0 deletions Specs/Data/Models/glTF-2.0/AnisotropyRotationTest/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": 2,
"legal": [
{
"year": "2023",
"owner": "Analytical Graphics, Inc.",
"license": "CC-BY International 4.0",
"artist": "Ed Mackey",
"what": "Everything",
"licenseUrl": "https://creativecommons.org/licenses/by/4.0/legalcode",
"text": "CC BY 4.0 International",
"spdx": "CC-BY-4.0",
"icon": "https://licensebuttons.net/l/by/3.0/88x31.png"
}
],
"tags": [
"extension",
"testing"
],
"screenshot": "screenshot/screenshot.png",
"name": "Anisotropy Rotation Test",
"path": "./Models/AnisotropyRotationTest",
"summary": "This model tests rotational offsets for KHR_materials_anisotropy.",
"createReadme": true
}
30 changes: 30 additions & 0 deletions packages/engine/Source/Scene/GltfLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const {
MetallicRoughness,
SpecularGlossiness,
Specular,
Anisotropy,
Material,
} = ModelComponents;

Expand Down Expand Up @@ -1559,12 +1560,34 @@ function loadSpecular(loader, specularInfo, frameState) {
frameState
);
}
// TODO: if not defined, should we leave the default values?
specular.specularFactor = specularFactor;
specular.specularColorFactor = fromArray(Cartesian3, specularColorFactor);

return specular;
}

function loadAnisotropy(loader, anisotropyInfo, frameState) {
const {
anisotropyStrength = Anisotropy.DEFAULT_ANISOTROPY_STRENGTH,
anisotropyRotation = Anisotropy.DEFAULT_ANISOTROPY_ROTATION,
anisotropyTexture,
} = anisotropyInfo;

const anisotropy = new Anisotropy();
if (defined(anisotropyTexture)) {
anisotropy.anisotropyTexture = loadTexture(
loader,
anisotropyTexture,
frameState
);
}
anisotropy.anisotropyStrength = anisotropyStrength;
anisotropy.anisotropyRotation = anisotropyRotation;

return anisotropy;
}

/**
* Load textures and parse factors and flags for a glTF material
*
Expand All @@ -1583,6 +1606,7 @@ function loadMaterial(loader, gltfMaterial, frameState) {
);
const pbrSpecularGlossiness = extensions.KHR_materials_pbrSpecularGlossiness;
const pbrSpecular = extensions.KHR_materials_specular;
const pbrAnisotropy = extensions.KHR_materials_anisotropy;
const pbrMetallicRoughness = gltfMaterial.pbrMetallicRoughness;

material.unlit = defined(extensions.KHR_materials_unlit);
Expand All @@ -1594,6 +1618,7 @@ function loadMaterial(loader, gltfMaterial, frameState) {
frameState
);
} else {
// TODO: should this branch exclude materials.unlit?
if (defined(pbrMetallicRoughness)) {
material.metallicRoughness = loadMetallicRoughness(
loader,
Expand All @@ -1602,8 +1627,13 @@ function loadMaterial(loader, gltfMaterial, frameState) {
);
}
if (defined(pbrSpecular)) {
// TODO: not compatible with materials.unlit
material.specular = loadSpecular(loader, pbrSpecular, frameState);
}
if (defined(pbrAnisotropy)) {
// TODO: not compatible with materials.unlit
material.anisotropy = loadAnisotropy(loader, pbrAnisotropy, frameState);
}
}

// Top level textures
Expand Down
126 changes: 110 additions & 16 deletions packages/engine/Source/Scene/Model/MaterialPipelineStage.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,19 @@ MaterialPipelineStage.process = function (
// gltf-pipeline automatically creates a default material so this will always
// be defined.
const material = primitive.material;
const model = renderResources.model;
const { model, uniformMap, shaderBuilder } = renderResources;

// Classification models only use position and feature ID attributes,
// so textures should be disabled to avoid compile errors.
const hasClassification = defined(model.classificationType);
const disableTextures = hasClassification;

const uniformMap = renderResources.uniformMap;
const shaderBuilder = renderResources.shaderBuilder;

// When textures are loaded incrementally, fall back to a default 1x1 texture
const defaultTexture = frameState.context.defaultTexture;
const defaultNormalTexture = frameState.context.defaultNormalTexture;
const defaultEmissiveTexture = frameState.context.defaultEmissiveTexture;
const {
defaultTexture,
defaultNormalTexture,
defaultEmissiveTexture,
} = frameState.context;

processMaterialUniforms(
material,
Expand All @@ -90,7 +89,7 @@ MaterialPipelineStage.process = function (

if (defined(material.specularGlossiness)) {
processSpecularGlossinessUniforms(
material,
material.specularGlossiness,
uniformMap,
shaderBuilder,
defaultTexture,
Expand All @@ -102,15 +101,27 @@ MaterialPipelineStage.process = function (
ModelUtility.supportedExtensions.KHR_materials_specular === true
) {
processSpecularUniforms(
material,
material.specular,
uniformMap,
shaderBuilder,
defaultTexture,
disableTextures
);
}
if (
defined(material.anisotropy) &&
ModelUtility.supportedExtensions.KHR_materials_anisotropy === true
) {
processAnisotropyUniforms(
material.anisotropy,
uniformMap,
shaderBuilder,
defaultTexture,
disableTextures
);
}
processMetallicRoughnessUniforms(
material,
material.metallicRoughness,
uniformMap,
shaderBuilder,
defaultTexture,
Expand Down Expand Up @@ -321,14 +332,23 @@ function processMaterialUniforms(
}
}

/**
* Add uniforms and defines for the KHR_materials_pbrSpecularGlossiness extension
*
* @param {ModelComponents.SpecularGlossiness} specularGlossiness
* @param {Object<string, Function>} uniformMap The uniform map to modify.
* @param {ShaderBuilder} shaderBuilder
* @param {Texture} defaultTexture
* @param {boolean} disableTextures
* @private
*/
function processSpecularGlossinessUniforms(
material,
specularGlossiness,
uniformMap,
shaderBuilder,
defaultTexture,
disableTextures
) {
const { specularGlossiness } = material;
const {
diffuseTexture,
diffuseFactor,
Expand Down Expand Up @@ -426,14 +446,23 @@ function processSpecularGlossinessUniforms(
}
}

/**
* Add uniforms and defines for the KHR_materials_specular extension
*
* @param {ModelComponents.Specular} specular
* @param {Object<string, Function>} uniformMap The uniform map to modify.
* @param {ShaderBuilder} shaderBuilder
* @param {Texture} defaultTexture
* @param {boolean} disableTextures
* @private
*/
function processSpecularUniforms(
material,
specular,
uniformMap,
shaderBuilder,
defaultTexture,
disableTextures
) {
const { specular } = material;
const {
specularTexture,
specularFactor,
Expand Down Expand Up @@ -511,14 +540,79 @@ function processSpecularUniforms(
}
}

const scratchAnisotropy = new Cartesian3();

/**
* Add uniforms and defines for the KHR_materials_anisotropy extension
*
* @param {ModelComponents.Anisotropy} anisotropy
* @param {Object<string, Function>} uniformMap The uniform map to modify.
* @param {ShaderBuilder} shaderBuilder
* @param {Texture} defaultTexture
* @param {boolean} disableTextures
* @private
*/
function processAnisotropyUniforms(
anisotropy,
uniformMap,
shaderBuilder,
defaultTexture,
disableTextures
) {
const {
anisotropyStrength,
anisotropyRotation,
anisotropyTexture,
} = anisotropy;

shaderBuilder.addDefine(
"USE_ANISOTROPY",
undefined,
ShaderDestination.FRAGMENT
);

if (defined(anisotropyTexture) && !disableTextures) {
processTexture(
shaderBuilder,
uniformMap,
anisotropyTexture,
"u_anisotropyTexture",
"ANISOTROPY",
defaultTexture
);
}

// Pre-compute cos and sin of rotation, since they are the same for all fragments.
// Combine with strength as one vec3 uniform.
const anisotropyValues = Cartesian3.fromElements(
Math.cos(anisotropyRotation),
Math.sin(anisotropyRotation),
anisotropyStrength,
scratchAnisotropy
);
shaderBuilder.addUniform("vec3", "u_anisotropy", ShaderDestination.FRAGMENT);
uniformMap.u_anisotropy = function () {
return anisotropyValues;
};
}

/**
* Add uniforms and defines for the PBR metallic roughness model
*
* @param {ModelComponents.MetallicRoughness} metallicRoughness
* @param {Object<string, Function>} uniformMap The uniform map to modify.
* @param {ShaderBuilder} shaderBuilder
* @param {Texture} defaultTexture
* @param {boolean} disableTextures
* @private
*/
function processMetallicRoughnessUniforms(
material,
metallicRoughness,
uniformMap,
shaderBuilder,
defaultTexture,
disableTextures
) {
const metallicRoughness = material.metallicRoughness;
shaderBuilder.addDefine(
"USE_METALLIC_ROUGHNESS",
undefined,
Expand Down

0 comments on commit c48cad5

Please sign in to comment.