8000 IR-10191 mt stg studio flips green channel on normal maps by quaiquai-ir · Pull Request #2007 · ir-engine/ir-engine · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

IR-10191 mt stg studio flips green channel on normal maps #2007

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

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 29 additions & 0 deletions packages/engine/src/gltf/GLTFLoader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -803,4 +803,33 @@ describe('GLTF Loader', async () => {
const rigidbodyEntities = getChildrenWithComponents(entity, [RigidBodyComponent])
expect(rigidbodyEntities.length).toBe(0)
})

it('properly sets normalScale when no tangents are present', async () => {
const src = base_url + '/NormalTangentTest/NormalTangentTest.gltf'

const entity = setupEntity()
setComponent(entity, UUIDComponent, { entitySourceID: 'source' as SourceID, entityID: 'test' as EntityID })

setComponent(entity, GLTFComponent, {
cameraOcclusion: true,
src: src
})

await waitForScene(entity)

expect(GLTFComponent.isSceneLoaded(entity)).toBeTruthy()

const meshEntities = getChildrenWithComponents(entity, [MeshComponent])
expect(meshEntities.length).toBeGreaterThan(0)

const materialEntities = getChildrenWithComponents(entity, [MaterialStateComponent])
expect(materialEntities[0]).toBeDefined()
const material = getComponent(materialEntities[0], MaterialStateComponent).material as MeshStandardMaterial

expect(material.normalScale?.x).toBe(1)
expect(material.normalScale?.y).toBe(-1)

const mesh = getComponent(meshEntities[0], MeshComponent)
expect(mesh.geometry.hasAttribute('tangent')).toBeFalsy()
})
})
83 changes: 55 additions & 28 deletions packages/engine/src/gltf/GLTFLoaderFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ import {
MathUtils,
Matrix4,
Mesh,
MeshPhysicalMaterial,
MeshStandardMaterial,
NumberKeyframeTrack,
Object3D,
Expand Down Expand Up @@ -155,23 +154,6 @@ export function getImageURIMimeType(uri) {
return 'image/png'
}

const assignFinalMaterial = (primitiveDef: GLTF.IMeshPrimitive, entity: Entity) => {
const material = getComponent(entity, MaterialStateComponent).material as MeshPhysicalMaterial
const useDerivativeTangents = primitiveDef.attributes.TANGENT === undefined
const useVertexColors = primitiveDef.attributes.COLOR_0 !== undefined
const useFlatShading = primitiveDef.attributes.NORMAL === undefined

if (useVertexColors) material.vertexColors = true
if (useFlatShading) material.flatShading = true

if (useDerivativeTangents) {
if (material.normalScale) material.normalScale.y *= -1
if (material.clearcoatNormalScale) material.clearcoatNormalScale.y *= -1
}

material.needsUpdate = true
}

const loadPrimitives = async (options: GLTFParserOptions, meshIndex: number): Promise<[BufferGeometry, Entity[]]> => {
const json = options.document
const mesh = json.meshes![meshIndex]
Expand All @@ -181,18 +163,42 @@ const loadPrimitives = async (options: GLTFParserOptions, meshIndex: number): Pr
)

if (primitives.length > 1) {
let needsTangentRecalculation = false
for (const [geometry] of primitives) {
if (geometry.attributes.tangent) needsTangentRecalculation = true
geometry.deleteAttribute('tangent')
const hasAnyTangents = primitives.some(([geometry]) => geometry.hasAttribute('tangent'))

if (hasAnyTangents) {
const tangentAttributeLength = 4
for (let i = 0; i < primitives.length; i++) {
let [geometry] = primitives[i]

if (!geometry.hasAttribute('tangent')) {
if (!geometry.index) {
geometry = geometry.toNonIndexed()
primitives[i][0] = geometry
}

try {
geometry.computeTangents()
} catch (e) {
console.warn(`Failed to compute tangents for primitive ${i}:`, e)
// Fallback
const count = geometry.getAttribute('position').count
const fallback = new Float32Array(count * tangentAttributeLength)
for (let j = 0; j < count; j++) {
fallback[j * 4 + 0] = 1
fallback[j * 4 + 1] = 0
fallback[j * 4 + 2] = 0
fallback[j * 4 + 3] = 1
}
geometry.setAttribute('tangent', new BufferAttribute(fallback, 4))
}
}
}
}

const newGeometry = mergeBufferGeometries(
primitives.map(([geometry]) => geometry),
true
)!
if (needsTangentRecalculation) newGeometry?.computeTangents()

return [newGeometry, primitives.map(([, material]) => material)]
} else {
return [primitives[0][0], [primitives[0][1]]]
Expand Down Expand Up @@ -228,13 +234,19 @@ const loadPrimitive = async (
)
}

const material = await materialPromise
const materialComponent = getComponent(material, MaterialStateComponent).material as MeshStandardMaterial
const useVertexColors = primitiveDef.attributes.COLOR_0 !== undefined
const useFlatShading = primitiveDef.attributes.NORMAL === undefined
if (useVertexColors) materialComponent.vertexColors = true
if (useFlatShading) materialComponent.flatShading = true

if (hasDracoCompression) {
return new Promise((resolve) => {
KHR_DRACO_MESH_COMPRESSION.decodePrimitive(options, primitiveDef).then((geom) => {
GLTFLoaderFunctions.computeBounds(json, geom, primitiveDef)
assignExtrasToUserData(geom, primitiveDef)
materialPromise.then((material) => {
assignFinalMaterial(primitiveDef, material)
resolve([geom, material])
})
})
Expand Down Expand Up @@ -278,7 +290,6 @@ const loadPrimitive = async (
GLTFLoaderFunctions.computeBounds(json, geometry, primitiveDef)
assignExtrasToUserData(geometry, primitiveDef)
const [material] = await Promise.all([materialPromise, Promise.all(promises)])
assignFinalMaterial(primitiveDef, material)
if (primitiveDef.targets) await addMorphTargets(options, geometry, primitiveDef.targets)
return [geometry, material]
}
Expand Down Expand Up @@ -744,11 +755,28 @@ const loadMaterial = async (options: GLTFParserOptions, materialIndex: number) =
)
}

let hasTangents = false
if (json.meshes) {
for (const mesh of json.meshes) {
for (const primitive of mesh.primitives) {
if (
primitive.material === materialIndex &&
primitive.attributes &&
primitive.attributes.TANGENT !== undefined
) {
hasTangents = true
break
}
}
if (hasTangents) break
}
}

if (materialDef.normalTexture?.scale) {
const scale = materialDef.normalTexture.scale
materialConstructorParameters.normalScale = new Vector2(scale, scale)
} else {
materialConstructorParameters.normalScale = new Vector2(1, 1)
materialConstructorParameters.normalScale = new Vector2(1, hasTangents ? 1 : -1)
}

if (typeof materialDef.occlusionTexture !== 'undefined') {
Expand Down Expand Up @@ -863,7 +891,6 @@ const mergeMorphTargets = async (options: GLTFParserOptions, nodeIndex: number)
const newAttributesLength = morphAttributes[name].length / morphTargets.length
for (let j = newAttributesLength; j < morphAttributes[name].length; j++) {
const mergeIntoIndex = j % newAttributesLength
// console.log(j + ' goes into ' + mergeIntoIndex)
const newArray = new Float32Array(
morphAttributes[name][j].array.length + morphAttributes[name][mergeIntoIndex].array.length
)
Expand Down
10000
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{
"asset": {
"copyright": "Copyright 2017 Analytical Graphics, Inc., CC-BY 4.0 https://creativecommons.org/licenses/by/4.0/ - Mesh and textures by Ed Mackey, see: https://emackey.github.io/testing-pbr/normal-tangent-readme.html",
"generator": "COLLADA2GLTF with hand-edits",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "NormalTangentTest_low"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 23322,
"max": [
3982
],
"min": [
1E79 0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 3983,
"max": [
0.9247629046440125,
0.9247735142707824,
1.0
],
"min": [
-0.9247629046440125,
-0.9247629046440125,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 47796,
"componentType": 5126,
"count": 3983,
"max": [
1.1100000143051148,
0.9500001072883606,
0.08049999922513962
],
"min": [
-1.1100000143051148,
-1.200000047683716,
-0.009999989531934262
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 3983,
"max": [
0.9821358323097228,
0.9877346754074096
],
"min": [
0.0106734000146389,
0.03816509246826172
],
"type": "VEC2"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
},
"occlusionTexture": {
"index": 1
},
"normalTexture": {
"index": 2
},
"doubleSided": true,
"emissiveFactor": [
0.0,
0.0,
0.0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
},
{
"sampler": 0,
"source": 2
}
],
"images": [
{
"uri": "NormalTangentTest_BaseColor.png"
},
{
"uri": "NormalTangentTest_OcclusionRoughnessMetallic.png"
},
{
"uri": "NormalTangentTest_Normal.png"
}
],
"samplers": [
{
"magFilter": 9729,
"minFilter": 9986,
"wrapS": 10497,
"wrapT": 10497
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 127456,
"byteLength": 46644,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 95592,
"byteStride": 12,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 95592,
"byteLength": 31864,
"byteStride": 8,
"target": 34962
}
],
"buffers": [
{
"byteLength": 174100,
"uri": "NormalTangentTest0.bin"
}
]
}
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
0