three.js: GLTF Orthographic camera size seems to be handled incorrectly.
Describe the bug
Per spec, camera.orthographic.xmag and .ymag should be half the view window size, I think:
==== Orthographic projection
Let
- `r` be half the orthographic width, set by `camera.orthographic.xmag`;
- `t` be half the orthographic height, set by `camera.orthographic.ymag`;
- `f` be the distance to the far clipping plane, set by `camera.orthographic.zfar`;
- `n` be the distance to the near clipping plane, set by `camera.orthographic.znear`.
The loader code looks right:
But the results don’t:
Screenshots


Each square is one unit.
To Reproduce
Steps to reproduce the behavior:
- Save and open the GLTF file below.
Note: The Khronos Group reference implementation looks like Three.JS, while Blender looks like Babylon.js (Okay. That’s actually not implemented for Blender, and the default just happened to be what I was expecting by hilarious coincidence.). So… Not 100% sure I’m interpreting the spec correctly, but either way something isn’t lining up here.
OrthoScale.gltf
{
"asset" : {
"generator" : "Khronos glTF Blender I/O v3.3.32",
"version" : "2.0"
},
"scene" : 0,
"scenes" : [
{
"name" : "Scene",
"nodes" : [
0,
36
]
}
],
"nodes" : [
{
"camera" : 0,
"name" : "Camera",
"rotation" : [
-0.7071068286895752,
0,
0,
0.7071068286895752
],
"scale" : [
2,
1.9999998807907104,
1
],
"translation" : [
6,
2,
-4
]
},
{
"mesh" : 0,
"name" : "Plane"
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
2,
0,
0
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
4,
0,
0
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
6,
0,
0
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
8,
0,
0
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
10,
0,
0
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
12,
0,
0
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
0,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
2,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
4,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
6,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
8,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
10,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
12,
0,
-2
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
0,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
2,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
4,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
6,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
8,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
10,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
12,
0,
-4
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
0,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
2,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
4,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
6,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
8,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
10,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
12,
0,
-6
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
0,
0,
-8
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
2,
0,
-8
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
4,
0,
-8
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
6,
0,
-8
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
8,
0,
-8
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
10,
0,
-8
]
},
{
"mesh" : 0,
"name" : "Plane",
"translation" : [
12,
0,
-8
]
},
{
"children" : [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35
],
"name" : "Plane.001"
}
],
"cameras" : [
{
"name" : "Camera",
"orthographic" : {
"xmag" : 3,
"ymag" : 4,
"zfar" : 100,
"znear" : 0.10000000149011612
},
"type" : "orthographic"
}
],
"materials" : [
{
"doubleSided" : true,
"name" : "White",
"pbrMetallicRoughness" : {
"baseColorFactor" : [
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor" : 0,
"roughnessFactor" : 0.5
}
},
{
"doubleSided" : true,
"name" : "Black",
"pbrMetallicRoughness" : {
"baseColorFactor" : [
0.05000000074505806,
0.05000000074505806,
0.05000000074505806,
1
],
"metallicFactor" : 0,
"roughnessFactor" : 0.5
}
}
],
"meshes" : [
{
"name" : "Plane",
"primitives" : [
{
"attributes" : {
"POSITION" : 0,
"NORMAL" : 1,
"TEXCOORD_0" : 2
},
"indices" : 3,
"material" : 0
},
{
"attributes" : {
"POSITION" : 4,
"NORMAL" : 5,
"TEXCOORD_0" : 6
},
"indices" : 7,
"material" : 1
}
]
}
],
"accessors" : [
{
"bufferView" : 0,
"componentType" : 5126,
"count" : 7,
"max" : [
1.5,
0,
0.5
],
"min" : [
-0.5,
0,
-1.5
],
"type" : "VEC3"
},
{
"bufferView" : 1,
"componentType" : 5126,
"count" : 7,
"type" : "VEC3"
},
{
"bufferView" : 2,
"componentType" : 5126,
"count" : 7,
"type" : "VEC2"
},
{
"bufferView" : 3,
"componentType" : 5123,
"count" : 12,
"type" : "SCALAR"
},
{
"bufferView" : 4,
"componentType" : 5126,
"count" : 7,
"max" : [
1.5,
0,
0.5
],
"min" : [
-0.5,
0,
-1.5
],
"type" : "VEC3"
},
{
"bufferView" : 5,
"componentType" : 5126,
"count" : 7,
"type" : "VEC3"
},
{
"bufferView" : 6,
"componentType" : 5126,
"count" : 7,
"type" : "VEC2"
},
{
"bufferView" : 7,
"componentType" : 5123,
"count" : 12,
"type" : "SCALAR"
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 84,
"byteOffset" : 0,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 84,
"byteOffset" : 84,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 56,
"byteOffset" : 168,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 24,
"byteOffset" : 224,
"target" : 34963
},
{
"buffer" : 0,
"byteLength" : 84,
"byteOffset" : 248,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 84,
"byteOffset" : 332,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 56,
"byteOffset" : 416,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 24,
"byteOffset" : 472,
"target" : 34963
}
],
"buffers" : [
{
"byteLength" : 496,
"uri" : "data:application/octet-stream;base64,AAAAPwAAAAAAAAA/AAAAvwAAAAAAAAC/AAAAPwAAAAAAAAC/AADAPwAAAAAAAAA/AADAPwAAAAAAAAC/AAAAvwAAAAAAAMC/AAAAPwAAAAAAAMC/AAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAAAACAAAAAwACAAMABAABAAIABgABAAYABQAAAAC/AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAMA/AAAAAAAAAL8AAAA/AAAAAAAAwL8AAMA/AAAAAAAAwL8AAAAAAACAPwAAAIAAAAAAAACAPwAAAIAAAAAAAACAPwAAAIAAAAAAAACAPwAAAIAAAAAAAACAPwAAAIAAAAAAAACAPwAAAIAAAAAAAACAPwAAAIAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAAQADAAAAAwACAAMABAAGAAMABgAFAA=="
}
]
}
Code
Relevant excerpt from file:
"cameras" : [
{
"name" : "Camera",
"orthographic" : {
"xmag" : 3,
"ymag" : 4,
"zfar" : 100,
"znear" : 0.10000000149011612
},
"type" : "orthographic"
}
],
See also
https://github.com/KhronosGroup/glTF/issues/1663
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 16 (2 by maintainers)
I would not make it a priority unless there is demand for doing so. Cameras can have children, and ignoring part of the camera’s world transform raises questions about how to handle the children.
Cameras in three.js should not have a scale applied.
Yes, as in your example.
three.js does not ignore the scaling in a camera transform.
three.js assumes the rotation component of the view matrix is orthonormal.
(There are side-effects if it is not. See, for example, #9002, and the discussion in #7028.)
See https://github.com/KhronosGroup/glTF/pull/2053#issuecomment-933017285.