Blender FOV to Threejs FOV

Hey,
I Export the FOV data of a camera in a prop into a gltf file. That works as expected.
However, it is a different FOV approach.
When I copy the exported FOV value to a the .fov prop of a threejs camera, the result is not the same as in blender… it also seems to work in a different direction so + is -

I know, I can export the cameras from blender and than it is somehow the correct value.
However, I don’t need the entire camera and some other aspects of my threejs code requires me to not export the camera but instead only that value…

So how can I convert the blender FOV Value to the correct THREEJS Value?

Are you setting y = up when exporting the gltf / glb from blender? Typically values are 1 for 1 when exporting gltf from blender and importing to three…

Yes Y is Up is checked, thats not the problem.
But it is also not about axis but the Filed of View value…

No i found a way to come close to a correct value.
Because I get the FOV Value from the Blender Camera like this:

fov = math.degrees(camera.data.angle)

Because Blender gives the data in radians not in degrees.

However, it is still not correct. there is a slight difference…

When I export the Blender Camera via exporter: 172.847d becomes 167.31902155969416
When I export the same value in a prop it 172.847d becomes 172.8470001220703 … which is correct, but which will not result in the actual correct camera setting for a threejs camera.

What is weird is that Threejs Doc says that it takes degrees, but when I put the excact degrees from blender in here, it is a different result to blenders camera.

.fov : Float
Camera frustum vertical field of view, from bottom to top of view, in degrees. Default is 50.
three.js docs

So in Three JS 71° FOV looks like this, on a resolution of 1920 x 1080

And in Blender 71° FOV looks like this on 1920 x 1080:

Eveyrthing in the Camera Frame should be vissible in three js too…

But the little yellow Sign is outside the frame in Blender…but it is vissible in Three…

So the THREEJS Fov show much more of the screen as I intent it to…

Note: This is only, when I get the excact FOV Number I use in Blender.

However, When I export a camera and use the exported camera.
I do not have the exact same values but I have a correct image:

This is now in Threejs, but uses the exported Camera and takes the FOV Value from there…
But it is not 71° anymore … it is now : 43.724018093363405

This is just a blind guess (as I am not experienced with Blender)

  • Theoretically, there are two FOVs - vertical and horizontal
  • Three.js allows the users to set only the vertical FOV; the horizontal FOV is calculated from the vertical and the aspect
  • In Blender the user-defined FOV could be either the horizontal, or the vertical, depending on the aspect (I found this here: Vertical and horizontal camera FOV angles)

So, just check whether you have a horizontal FOV from Blender and trying to use it as a vertical FOV in Three.js

2 Likes

Ok thats actually interesting,
I took a look into the code of an GLTF exporter and found that they actually do excactly that.
Taking angle_y instead of angle…

Thanks for the lead. I will check if this will work.

Unofrtunately it doesnt make a difference :frowning:

THREEJS uses vertical FOV, and blender uses horizontal FOV, iirc.

And keep in mind, the blender “viewport” is fixed in the render settings, whereas threejs viewport is changing based on the renderer dimensions which is often the window… so you will only get an exact match if you:

convert cam fov from blenders horizontal at rendersettings width / height, and use exact same aspect ratio in threejs.

So converting blender h fov to threejs vertical fov, at renderer width / height… i.e. when you set this fov, you also need to update the projectionMatrix and camera.aspect.

1 Like

I found a solution. This time I dug up the current GLTF Exporter that is included in blender and found a function that converts the FOV and finally I get the desired values.

I adjusted the function a bit, now I just give the function the camera.data prop and get the threejs valid radians. Now I can convert those to degree and Tada… I have what i want. Great!

Thanks for the leads :slight_smile:

def yvof_blender_to_gltf(cameradata):

    _render = bpy.context.scene.render
    width = _render.pixel_aspect_x * _render.resolution_x
    height = _render.pixel_aspect_y * _render.resolution_y

    aspect_ratio = width / height

    if width >= height:
        if cameradata.sensor_fit != 'VERTICAL':
            return 2.0 * math.atan(math.tan(cameradata.angle * 0.5) / aspect_ratio)
        else:
            return cameradata.angle
    else:
        if cameradata.sensor_fit != 'HORIZONTAL':
            return cameradata.angle
        else:
            return 2.0 * math.atan(math.tan(cameradata.angle * 0.5) / aspect_ratio)

custom_prop.fov = math.degrees(yvof_blender_to_gltf(camera_object.data))
#This now can be exported to three js

Here is the Link to exporter, if anyone is curious:

1 Like