Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for KHR_texture_transform #7549

Merged
merged 7 commits into from
Apr 7, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Change Log

##### Additions :tada:
* `czm_materialInput.aspect` was added as an angle in radians between 0 and 2pi (east, north, west to south).
* Added support for the `KHR_texture_transform` glTF extension. [#7549](https://github.com/AnalyticalGraphicsInc/cesium/pull/7549)

##### Fixes :wrench:
* Fixed an issue where models would cause a crash on load if some primitives were Draco encoded and others were not. [#7383](https://github.com/AnalyticalGraphicsInc/cesium/issues/7383)
Expand Down
71 changes: 59 additions & 12 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ define([
* {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit/README.md|KHR_materials_unlit}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/README.md|KHR_materials_pbrSpecularGlossiness}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md|KHR_texture_transform}
* </li>
* </ul>
* </p>
Expand Down Expand Up @@ -1296,6 +1298,8 @@ define([
* {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit/README.md|KHR_materials_unlit}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/README.md|KHR_materials_pbrSpecularGlossiness}
* </li><li>
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md|KHR_texture_transform}
* </li>
* </ul>
* </p>
Expand Down Expand Up @@ -2375,24 +2379,67 @@ define([

var rendererSamplers = model._rendererResources.samplers;
var sampler = rendererSamplers[texture.sampler];
sampler = defaultValue(sampler, new Sampler({
wrapS : TextureWrap.REPEAT,
wrapT : TextureWrap.REPEAT
}));
if (!defined(sampler)) {
sampler = new Sampler({
wrapS : TextureWrap.REPEAT,
wrapT : TextureWrap.REPEAT
});
}

var usesTextureTransform = false;
var materials = model.gltf.materials;
var materialsLength = materials.length;
for (var i = 0; i < materialsLength; ++i) {
var material = materials[i];
if (defined(material.extensions) && defined(material.extensions.KHR_techniques_webgl)) {
var values = material.extensions.KHR_techniques_webgl.values;
for (var valueName in values) {
if (values.hasOwnProperty(valueName) && valueName.indexOf('Texture') !== -1) {
var value = values[valueName];
if (value.index === gltfTexture.id && defined(value.extensions) && defined(value.extensions.KHR_texture_transform)) {
usesTextureTransform = true;
break;
}
}
}
}
if (usesTextureTransform) {
break;
}
}

var wrapS = sampler.wrapS;
var wrapT = sampler.wrapT;
var minFilter = sampler.minificationFilter;

if (usesTextureTransform && minFilter !== TextureMinificationFilter.LINEAR && minFilter !== TextureMinificationFilter.NEAREST) {
if (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST || minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) {
minFilter = TextureMinificationFilter.NEAREST;
} else {
minFilter = TextureMinificationFilter.LINEAR;
}

sampler = new Sampler({
wrapS : sampler.wrapS,
wrapT : sampler.wrapT,
textureMinificationFilter : minFilter,
textureMagnificationFilter : sampler.magnificationFilter
});
}

var internalFormat = gltfTexture.internalFormat;

var mipmap =
(!(defined(internalFormat) && PixelFormat.isCompressedFormat(internalFormat))) &&
((sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
(sampler.minificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
(sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
(sampler.minificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR));
((minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST) ||
(minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR) ||
(minFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST) ||
(minFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR));
var requiresNpot = mipmap ||
(sampler.wrapS === TextureWrap.REPEAT) ||
(sampler.wrapS === TextureWrap.MIRRORED_REPEAT) ||
(sampler.wrapT === TextureWrap.REPEAT) ||
(sampler.wrapT === TextureWrap.MIRRORED_REPEAT);
(wrapS === TextureWrap.REPEAT) ||
(wrapS === TextureWrap.MIRRORED_REPEAT) ||
(wrapT === TextureWrap.REPEAT) ||
(wrapT === TextureWrap.MIRRORED_REPEAT);

var tx;
var source = gltfTexture.image;
Expand Down
1 change: 1 addition & 0 deletions Source/Scene/ModelUtility.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ define([
'KHR_techniques_webgl' : true,
'KHR_materials_unlit' : true,
'KHR_materials_pbrSpecularGlossiness' : true,
'KHR_texture_transform' : true,
'WEB3D_quantized_attributes' : true,
'EXT_texture_webp' : true
};
Expand Down
129 changes: 99 additions & 30 deletions Source/Scene/processPbrMaterials.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ define([
defined(material.extensions.KHR_materials_pbrSpecularGlossiness);
}

function addTextureCoordinates(gltf, textureName, generatedMaterialValues, defaultTexCoord, result) {
var texCoord;
if (defined(generatedMaterialValues[textureName + 'Offset'])) {
var textureIndex = generatedMaterialValues[textureName].index;
var sampler = gltf.samplers[gltf.textures[textureIndex].sampler];

var repeatS = sampler.wrapS === WebGLConstants.REPEAT ? 'true' : 'false';
var repeatT = sampler.wrapS === WebGLConstants.REPEAT ? 'true' : 'false';
bagnell marked this conversation as resolved.
Show resolved Hide resolved

texCoord = textureName + 'Coord';
result.fragmentShaderMain += ' vec2 ' + texCoord + ' = computeTexCoord(' + defaultTexCoord + ', ' + textureName + 'Offset, ' + textureName + 'Rotation, ' + textureName + 'Scale, ' + repeatS + ', ' + repeatT + ');\n';
} else {
texCoord = defaultTexCoord;
}
return texCoord;
}

var DEFAULT_TEXTURE_OFFSET = [0.0, 0.0];
var DEFAULT_TEXTURE_ROTATION = [0.0];
var DEFAULT_TEXTURE_SCALE = [1.0, 1.0];

function generateTechnique(gltf, material, materialIndex, generatedMaterialValues, primitiveByMaterial, options) {
var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false);

Expand All @@ -103,8 +124,20 @@ define([
if (defined(pbrMetallicRoughness) && !useSpecGloss) {
for (parameterName in pbrMetallicRoughness) {
if (pbrMetallicRoughness.hasOwnProperty(parameterName)) {
var value = pbrMetallicRoughness[parameterName];
uniformName = 'u_' + parameterName;
generatedMaterialValues[uniformName] = pbrMetallicRoughness[parameterName];
generatedMaterialValues[uniformName] = value;

if (parameterName.indexOf('Texture') >= 0 && defined(value.extensions) && defined(value.extensions.KHR_texture_transform)) {
bagnell marked this conversation as resolved.
Show resolved Hide resolved
var extension = value.extensions.KHR_texture_transform;
generatedMaterialValues[uniformName + 'Offset'] = defaultValue(extension.offset, DEFAULT_TEXTURE_OFFSET);
generatedMaterialValues[uniformName + 'Rotation'] = defaultValue(extension.rotation, DEFAULT_TEXTURE_ROTATION);
generatedMaterialValues[uniformName + 'Scale'] = defaultValue(extension.scale, DEFAULT_TEXTURE_SCALE);

if (defined(value.texCoord) && defined(extension.texCoord)) {
generatedMaterialValues[uniformName].texCoord = extension.texCoord;
}
}
}
}
}
Expand Down Expand Up @@ -371,19 +404,42 @@ define([
fragmentShader += 'varying vec4 v_tangent;\n';
}

var fragmentShaderMain = '';

// Add texture coordinates if the material uses them
var v_texcoord;
var v_texCoord;
var normalTexCoord;
var baseColorTexCoord;
var specularGlossinessTexCoord;
var diffuseTexCoord;
var metallicRoughnessTexCoord;
var occlusionTexCoord;
var emissiveTexCoord;

if (hasTexCoords) {
techniqueAttributes.a_texcoord_0 = {
semantic : 'TEXCOORD_0'
};

v_texcoord = 'v_texcoord_0';
v_texCoord = 'v_texcoord_0';
vertexShader += 'attribute vec2 a_texcoord_0;\n';
vertexShader += 'varying vec2 ' + v_texcoord + ';\n';
vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n';
vertexShader += 'varying vec2 ' + v_texCoord + ';\n';
vertexShaderMain += ' ' + v_texCoord + ' = a_texcoord_0;\n';

fragmentShader += 'varying vec2 ' + v_texCoord + ';\n';

fragmentShader += 'varying vec2 ' + v_texcoord + ';\n';
var result = {
fragmentShaderMain : fragmentShaderMain
};
normalTexCoord = addTextureCoordinates(gltf, 'u_normalTexture', generatedMaterialValues, v_texCoord, result);
baseColorTexCoord = addTextureCoordinates(gltf, 'u_baseColorTexture', generatedMaterialValues, v_texCoord, result);
specularGlossinessTexCoord = addTextureCoordinates(gltf, 'u_specularGlossinessTexture', generatedMaterialValues, v_texCoord, result);
diffuseTexCoord = addTextureCoordinates(gltf, 'u_diffuseTexture', generatedMaterialValues, v_texCoord, result);
metallicRoughnessTexCoord = addTextureCoordinates(gltf, 'u_metallicRoughnessTexture', generatedMaterialValues, v_texCoord, result);
occlusionTexCoord = addTextureCoordinates(gltf, 'u_occlusionTexture', generatedMaterialValues, v_texCoord, result);
emissiveTexCoord = addTextureCoordinates(gltf, 'u_emmissiveTexture', generatedMaterialValues, v_texCoord, result);

fragmentShaderMain = result.fragmentShaderMain;
}

// Add skinning information if available
Expand Down Expand Up @@ -488,6 +544,22 @@ define([
'#endif \n' +
'}\n\n';

fragmentShader +=
'vec2 computeTexCoord(vec2 texCoords, vec2 offset, float rotation, vec2 scale, bool repeatS, bool repeatT) \n' +
'{\n' +
' mat3 translationMatrix = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, offset.x, offset.y, 1.0); \n' +
' rotation = -rotation; \n' +
' mat3 rotationMatrix = mat3(\n' +
' cos(rotation), sin(rotation), 0.0, \n' +
' -sin(rotation), cos(rotation), 0.0, \n' +
' 0.0, 0.0, 1.0); \n' +
' mat3 scaleMatrix = mat3(scale.x, 0.0, 0.0, 0.0, scale.y, 0.0, 0.0, 0.0, 1.0); \n' +
' vec2 transformedTexCoords = ((translationMatrix * rotationMatrix * scaleMatrix) * vec3(fract(texCoords), 1.0)).xy; \n' +
bagnell marked this conversation as resolved.
Show resolved Hide resolved
' transformedTexCoords.x = repeatS ? fract(transformedTexCoords.x) : clamp(transformedTexCoords.x, 0.0, 1.0); \n' +
' transformedTexCoords.y = repeatT ? fract(transformedTexCoords.y) : clamp(transformedTexCoords.y, 0.0, 1.0); \n' +
' return transformedTexCoords; \n' +
'}\n\n';

fragmentShader += '#ifdef USE_IBL_LIGHTING \n';
fragmentShader += 'uniform vec2 gltf_iblFactor; \n';
fragmentShader += '#endif \n';
Expand All @@ -496,6 +568,7 @@ define([
fragmentShader += '#endif \n';

fragmentShader += 'void main(void) \n{\n';
fragmentShader += fragmentShaderMain;

// Add normal mapping to fragment shader
if (hasNormals) {
Expand All @@ -506,7 +579,7 @@ define([
fragmentShader += ' vec3 t = normalize(v_tangent.xyz);\n';
fragmentShader += ' vec3 b = normalize(cross(ng, t) * v_tangent.w);\n';
fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n';
fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n';
fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + normalTexCoord + ').rgb;\n';
fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n';
} else {
// Add standard derivatives extension
Expand All @@ -518,13 +591,13 @@ define([
fragmentShader += '#ifdef GL_OES_standard_derivatives\n';
fragmentShader += ' vec3 pos_dx = dFdx(v_positionEC);\n';
fragmentShader += ' vec3 pos_dy = dFdy(v_positionEC);\n';
fragmentShader += ' vec3 tex_dx = dFdx(vec3(' + v_texcoord + ',0.0));\n';
fragmentShader += ' vec3 tex_dy = dFdy(vec3(' + v_texcoord + ',0.0));\n';
fragmentShader += ' vec3 tex_dx = dFdx(vec3(' + normalTexCoord + ',0.0));\n';
fragmentShader += ' vec3 tex_dy = dFdy(vec3(' + normalTexCoord + ',0.0));\n';
fragmentShader += ' vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n';
fragmentShader += ' t = normalize(t - ng * dot(ng, t));\n';
fragmentShader += ' vec3 b = normalize(cross(ng, t));\n';
fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n';
fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n';
fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + normalTexCoord + ').rgb;\n';
fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n';
fragmentShader += '#else\n';
fragmentShader += ' vec3 n = ng;\n';
Expand All @@ -543,7 +616,7 @@ define([

// Add base color to fragment shader
if (defined(generatedMaterialValues.u_baseColorTexture)) {
fragmentShader += ' vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, ' + v_texcoord + '));\n';
fragmentShader += ' vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, ' + baseColorTexCoord + '));\n';
if (defined(generatedMaterialValues.u_baseColorFactor)) {
fragmentShader += ' baseColorWithAlpha *= u_baseColorFactor;\n';
}
Expand All @@ -562,7 +635,7 @@ define([
if (hasNormals) {
if (useSpecGloss) {
if (defined(generatedMaterialValues.u_specularGlossinessTexture)) {
fragmentShader += ' vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, ' + v_texcoord + '));\n';
fragmentShader += ' vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, ' + specularGlossinessTexCoord + '));\n';
fragmentShader += ' vec3 specular = specularGlossiness.rgb;\n';
fragmentShader += ' float glossiness = specularGlossiness.a;\n';
if (defined(generatedMaterialValues.u_specularFactor)) {
Expand All @@ -584,7 +657,7 @@ define([
}
}
if (defined(generatedMaterialValues.u_diffuseTexture)) {
fragmentShader += ' vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, ' + v_texcoord + '));\n';
fragmentShader += ' vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, ' + diffuseTexCoord + '));\n';
if (defined(generatedMaterialValues.u_diffuseFactor)) {
fragmentShader += ' diffuse *= u_diffuseFactor;\n';
}
Expand All @@ -594,7 +667,7 @@ define([
fragmentShader += ' vec4 diffuse = vec4(1.0);\n';
}
} else if (defined(generatedMaterialValues.u_metallicRoughnessTexture)) {
fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n';
fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + metallicRoughnessTexCoord + ').rgb;\n';
fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n';
fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n';
if (defined(generatedMaterialValues.u_metallicFactor)) {
Expand Down Expand Up @@ -763,10 +836,10 @@ define([
// Ignore occlusion and emissive when unlit
if (!isUnlit) {
if (defined(generatedMaterialValues.u_occlusionTexture)) {
fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n';
fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + occlusionTexCoord + ').r;\n';
}
if (defined(generatedMaterialValues.u_emissiveTexture)) {
fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb);\n';
fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + emissiveTexCoord + ').rgb);\n';
if (defined(generatedMaterialValues.u_emissiveFactor)) {
fragmentShader += ' emissive *= u_emissiveFactor;\n';
}
Expand Down Expand Up @@ -831,23 +904,23 @@ define([
}

function getPBRValueType(paramName) {
if (paramName.indexOf('Offset') !== -1) {
return WebGLConstants.FLOAT_VEC2;
} else if (paramName.indexOf('Rotation') !== -1) {
return WebGLConstants.FLOAT;
} else if (paramName.indexOf('Scale') !== -1) {
return WebGLConstants.FLOAT_VEC2;
} else if (paramName.indexOf('Texture') !== -1) {
return WebGLConstants.SAMPLER_2D;
}

switch (paramName) {
case 'u_baseColorFactor':
return WebGLConstants.FLOAT_VEC4;
case 'u_metallicFactor':
return WebGLConstants.FLOAT;
case 'u_roughnessFactor':
return WebGLConstants.FLOAT;
case 'u_baseColorTexture':
return WebGLConstants.SAMPLER_2D;
case 'u_metallicRoughnessTexture':
return WebGLConstants.SAMPLER_2D;
case 'u_normalTexture':
return WebGLConstants.SAMPLER_2D;
case 'u_occlusionTexture':
return WebGLConstants.SAMPLER_2D;
case 'u_emissiveTexture':
return WebGLConstants.SAMPLER_2D;
case 'u_emissiveFactor':
return WebGLConstants.FLOAT_VEC3;
// Specular Glossiness Types
Expand All @@ -857,10 +930,6 @@ define([
return WebGLConstants.FLOAT_VEC3;
case 'u_glossinessFactor':
return WebGLConstants.FLOAT;
case 'u_diffuseTexture':
return WebGLConstants.SAMPLER_2D;
case 'u_specularGlossinessTexture':
return WebGLConstants.SAMPLER_2D;
}
}

Expand Down
Loading