Controlling Camera Entity in Scene

Am I missing something or maybe it’s just my long summer vacation, but I’m not able to control the camera entity in Scene.

<Scene Camera="Camera1" ux:ClassName="MyScene" ClearColor="0, 0, 0, 1">

    <Entity ux:Name="Camera1">
        <Frustum FovDegrees="120" ZNear="10" ZFar="4500" ux:Name="Camera1Frustum" />
        <Transform3D Position="0, 0, 0" RotationDegrees="0, 0, 0" Scaling="1, 1, 1" ux:Name="Camera1Transform" />
    </Entity>

</Scene>

And in Scene class I do :

protected override void OnDraw(Fuse.DrawContext dc)
{
    var time = (float)Uno.Application.Current.FrameTime;

    Camera.Transform.Position = float3(200 * Math.Sin(time),0,-500);

    Camera.Transform.LookAt(float3(0,0,0), float3(0,1,0));


    dc.Clear(float4(0,0,0,0), 1);

    draw dc, DefaultShading, Fuse.Drawing.Primitives.Cube;

}

This doesn’t seems to have any effect on what happens on the screen. All I see is a little grey rectangle at the left up corner of the screen.

Help, please.

Hey,

Is this <Scene> inside an <App> ? How does your complete UX look?

Yep, Scene is just inside App

<App Theme="Basic" ux:ClassName="MainView" ClearColor="#000000FF">
    <MyScene />
</App>

Are you sure it is actually redrawing each frame?

Yes. Added debug_log "time "+time;

inside OnDraw() at Scene and it prints out the time every frame.

Hm, you are doing some manual draw here. Probably applying dc doesn’t do what it once did. You might have to set up your draw statement a bit more elaborately.

OH wait,

You are overriding Scene.OnDraw() ? Then the camera is never pushed. You need to let the Scene do it’s thing, and implement your drawing in a RenderNode or Component, inside the scene.

yep

Oh yes that’s it.

So here’s how you can render 3D stuff with Fuse/Uno and control the camera:

<App ClearColor="#000000FF">

  <Scene Camera="CameraEntity" ClearColor="0,0,0,1">

      <Entity ux:Name="CameraEntity">
          <Frustum FovDegrees="120" ZNear="10" ZFar="4500" />
          <Transform3D Position="0, 0, 0" RotationDegrees="0, 0, 0" Scaling="1, 1, 1" />
      </Entity>

      <MyRenderNode Camera="CameraEntity" />

  </Scene>

  </App>

And you have a MyRenderNode.ux:

<RenderNode ux:Class="MyRenderNode" />

And it’s class:

using Uno;
using Fuse;
using Fuse.Entities;

public partial class MyRenderNode
{
    public Entity Camera {get;set;}

    protected override void OnDraw(Fuse.DrawContext dc)
    {
        var time = (float)Uno.Application.Current.FrameTime;

        Camera.Transform.Position = float3(200 * Math.Sin(time),0,-500);

        Camera.Transform.LookAt(float3(0,0,0), float3(0,1,0));

        Camera.Frustum.FovRadians = Math.PIf/3.0f;

        dc.Clear(float4(0,0,0,0), 1);
        draw dc, DefaultShading, Fuse.Drawing.Primitives.Cube
        {
            Scaling:float3(100);
        };

    }

}

Great :slight_smile:

Some simplifications you can do:

  • The RenderNode doesn’t have to be in it’s own UX file, it is perfectly fine to have nested classes.

  • The Camera is pushed on the DrawContext when you use it on the scene, so you can get that from there instead of setting it explicitly on the RenderNode

  • You don’t need to repeat the ClearColor on both the app and the scene

The code can then look like this:

<App ClearColor="#000">

    <Scene Camera="CameraEntity">

        <Entity ux:Name="CameraEntity">
            <Frustum FovDegrees="120" ZNear="10" ZFar="4500" />
            <Transform3D Position="0, 0, 0" RotationDegrees="0, 0, 0" Scaling="1, 1, 1" />
        </Entity>

        <RenderNode ux:Class="MyRenderNode" />

    </Scene>

</App>

And to get the camera in Uno:

var camera = (Entity)dc.Camera;

Cool.

How should the MyRenderNode class look like in that case?

I now only have a MyRenderNode.uno class and it looks like:

using Uno;
using Fuse;
using Fuse.Entities;

public partial class MyRenderNode : RenderNode
{
    protected override void OnDraw(Fuse.DrawContext dc)
    {
        debug_log "foo";

        var _camera = (Entity)dc.Camera;

        var time = (float)Uno.Application.Current.FrameTime;

        _camera.Transform.Position = float3(200 * Math.Sin(time),0,-500);

        _camera.Transform.LookAt(float3(0,0,0), float3(0,1,0));

        _camera.Frustum.FovRadians = Math.PIf/3.0f;

        dc.Clear(float4(0,0,0,0), 1);
        draw dc, DefaultShading, Fuse.Drawing.Primitives.Cube
        {
            Scaling:float3(100);
        };

    }

}

But that draw is not called. Compiler doesn’t whine about anything.

If it’s the same as before:

    using Uno;
    using Fuse;
    using Fuse.Entities;

    public partial class MyRenderNode
    {
        protected override void OnDraw(Fuse.DrawContext dc)
        {
            debug_log "foo";

            var _camera = (Entity)dc.Camera;

            var time = (float)Uno.Application.Current.FrameTime;

            _camera.Transform.Position = float3(200 * Math.Sin(time),0,-500);

            _camera.Transform.LookAt(float3(0,0,0), float3(0,1,0));

            _camera.Frustum.FovRadians = Math.PIf/3.0f;

            dc.Clear(float4(0,0,0,0), 1);
            draw dc, DefaultShading, Fuse.Drawing.Primitives.Cube
            {
                Scaling:float3(100);
            };

        }

    }

I get .cache\GeneratedCode\MainView.g.uno(3,12): E3002: ‘MyRenderNode’ already has a static constructor

Looks like you now have both a stand alone MyRenderNode and the inline one, resulting in double code generation for that class.

Not sure why it doesn’t render, need more info to debug.