Cardboard VR

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
User avatar
Ats
Posts: 224
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Cardboard VR

Post by Ats » Sun Apr 14, 2019 10:37 am

Hi, I'm back to ZGE and this time I'm trying to make something out of the Google cardboard VR that takes dust on my shelter...
So I made a quick example, using an old example to set viewport, and the red globule from about.zge

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Cardboard VR" ClearScreenMode="1" RenderPasses="2" ClearColor="0.24 0.24 0.24 1" ScreenMode="0" CameraPosition="0.1 0 6" FileVersion="2" AndroidPackageName="com.mydomain.ZGEVR" AndroidPortrait="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <BeforeInitExp>
<![CDATA[if(ANDROID) {
  this.ModuleName = "libGLESv1_CM.so";
}]]>
      </BeforeInitExp>
      <Source>
<![CDATA[//

void glViewport(int X, int Y, int Width, int Height){}]]>
      </Source>
    </ZExternalLibrary>
    <ZExpression>
      <Expression>
<![CDATA[App.RenderPasses = 2;

View[0,0] = 0;
View[0,1] = 0;
View[0,2] = App.ViewportWidth / 2;
View[0,3] = App.ViewportHeight;

View[1,0] = App.ViewportWidth / 2;
View[1,1] = 0;
View[1,2] = App.ViewportWidth / 2;
View[1,3] = App.ViewportHeight;]]>
      </Expression>
    </ZExpression>
    <SpawnModel Model="System" SpawnStyle="1"/>
  </OnLoaded>
  <OnUpdate>
    <Timer Interval="0.31">
      <OnTimer>
        <SpawnModel Model="SpinnerModel"/>
      </OnTimer>
    </Timer>
  </OnUpdate>
  <OnBeginRenderPass>
    <ZExpression>
      <Expression>
<![CDATA[// Only clear the screen on first pass

if(App.CurrentRenderPass) App.ClearScreenMode = 1;
else App.ClearScreenMode = 0;

// Calculate & set the viewport ratio

int P = App.CurrentRenderPass;

float W = View[P,2];
float H = View[P,3];

//App.CustomViewportRatio = W/H;

if(App.CurrentRenderPass == 0)
{
  App.CameraPosition.Z = 6;
  App.CameraPosition.X = -0.1;
  App.CameraPosition.Y = 0;
  App.CameraRotation.Y = 0;
}

if(App.CurrentRenderPass == 1)
{
  App.CameraPosition.Z = 6;
  App.CameraPosition.X = 0.1;
  App.CameraPosition.Y = 0;
  App.CameraRotation.Y = 0;
}]]>
      </Expression>
    </ZExpression>
  </OnBeginRenderPass>
  <Content>
    <Group Name="SpinnerGroup">
      <Children>
        <Model Name="SpinnerModel" Scale="2 2 1" RotationVelocity="0 0.5 0">
          <Definitions>
            <Variable Name="SpinnerTime"/>
          </Definitions>
          <OnUpdate>
            <Condition Expression="return CurrentModel.Position.Y&gt;5.5;">
              <OnTrue>
                <RemoveModel/>
              </OnTrue>
            </Condition>
            <ZExpression>
              <Expression>
<![CDATA[SpinnerTime+=App.DeltaTime*0.75;

float Temp1;
Temp1=-4 + SpinnerTime;
Temp1+=noise2(CurrentModel.Personality,SpinnerTime*0.5) * 1.0;
Temp1+=noise2((SpinnerTime+App.Time)*0.25,0)*3;
CurrentModel.Position.Y=Temp1;

Temp1=sin(SpinnerTime*2)*2;
Temp1+=noise2((SpinnerTime+App.Time)*0.2,0)*8;
CurrentModel.Position.X=Temp1;

Temp1=cos(SpinnerTime*2)*3;
CurrentModel.Position.Z=Temp1;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="SpinnerMaterial"/>
            <RenderMesh Mesh="SpinnerMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="SpinnerMesh">
          <Producers>
            <MeshSphere Scale="0.25 0.25 0.25" ZSamples="8" RadialSamples="8"/>
          </Producers>
        </Mesh>
        <Material Name="SpinnerMaterial" Shading="1" Color="0.5 0 0 1"/>
      </Children>
    </Group> <!-- SpinnerGroup -->

    <Camera Name="CameraLeftEye"/>
    <Camera Name="CameraRightEye"/>
    <Array Name="View" Type="1" Dimensions="1" SizeDim1="2" SizeDim2="4" Persistent="255">
      <Values>
<![CDATA[78DA6360800055260686F7501A990F001DD20254]]>
      </Values>
    </Array>
    <Model Name="System">
      <Comment>
<![CDATA[This is the easiest way to make sure glViewport is called before anything else.
Calling it in OnBeginRenderPass doesn't work since ZGE sets the viewport natively at the beginning of OnRender.]]>
      </Comment>
      <OnRender>
        <ZExpression>
          <Expression>
<![CDATA[//

int P = App.CurrentRenderPass;

int X = View[P,0];
int Y = View[P,1];
int W = View[P,2];
int H = View[P,3];

//

glViewport(X,Y,W,H);]]>
          </Expression>
        </ZExpression>
      </OnRender>
    </Model>
  </Content>
</ZApplication>
But on android, it renders a very tiny viewport at the bottom left of the screen. Something like 10x5 pixels...
Am I supposed to use renderpass like that or should I use the Camera component?

I'm going to search if there is a place on the internet where I can find the camera parameters for setting the distance between the eyes correctly between the two viewports.

Edit:
I managed to "adapt" the screen to the phone by setting directly 1920 and 1080 instead of App.ScreenWidth (or Viewport) and... It's working real good :o
Can't wait to add that to Omeganaut.

User avatar
Kjell
Posts: 1699
Joined: Sat Feb 23, 2008 11:15 pm

Re: Cardboard VR

Post by Kjell » Sun Apr 14, 2019 12:46 pm

Hi Ats,

Keep in mind that you ( generally ) want to correct for lens distortion when targeting VR. Without lens distortion correction, you'll end up with a so-called "pincushion" effect.

Image

You can find a article discussing the most common techniques here.

K

User avatar
Ats
Posts: 224
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Cardboard VR

Post by Ats » Mon Apr 15, 2019 10:16 am

I read the article and I think I'll try to go with the second method (mesh based solution), since I'm doing that for Omeganaut, which has low poly. Direct vertex displacement seems to need a lot of vertex, and since I'm doing that for the low poly Omeganaut...

But before starting with that, I'd like to understand why App.ScreenWidth isn't working on Android when we start playing with the RenderPasses.
Also, I'm using 3 passes to render a single separative line over the two screen. Is that how I should do that?

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Cardboard VR" ClearScreenMode="1" RenderPasses="3" ClearColor="0.24 0.24 0.24 1" ScreenMode="0" CameraPosition="0 1000 0" ClipFar="200" FileVersion="2" AndroidPackageName="com.mydomain.ZGEVR" AndroidPortrait="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <BeforeInitExp>
<![CDATA[if(ANDROID) {
  this.ModuleName = "libGLESv1_CM.so";
}]]>
      </BeforeInitExp>
      <Source>
<![CDATA[//

void glViewport(int X, int Y, int Width, int Height){}]]>
      </Source>
    </ZExternalLibrary>
    <ZLibrary HasInitializer="1">
      <Source>
<![CDATA[int screenW = 2560;
int screenH = 1440;

void setVR(int i)
{
  switch(i)
  {
    case 0:
    App.RenderPasses = 1;

    View[0,0] = 0;
    View[0,1] = 0;
    View[0,2] = screenW;
    View[0,3] = screenH;
    break;

    case 1:
    App.RenderPasses = 3;

    View[0,0] = 0;
    View[0,1] = 0;
    View[0,2] = screenW / 2;
    View[0,3] = screenH;

    View[1,0] = screenW / 2;
    View[1,1] = 0;
    View[1,2] = screenW / 2;
    View[1,3] = screenH;

    View[2,0] = 0;
    View[2,1] = 0;
    View[2,2] = screenW;
    View[2,3] = screenH;
    break;
  }
}]]>
      </Source>
    </ZLibrary>
    <SpawnModel Model="System" SpawnStyle="1"/>
  </OnLoaded>
  <OnUpdate>
    <Timer Interval="0.31">
      <OnTimer>
        <SpawnModel Model="SpinnerModel"/>
      </OnTimer>
    </Timer>
    <KeyPress Comment="spacebar" Keys="{" CharCode="3" RepeatDelay="0.2">
      <OnPressed>
        <ZExpression Expression="setVR(App.RenderPasses == 1 ? 1 : 0);"/>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <OnBeginRenderPass>
    <ZExpression>
      <Expression>
<![CDATA[// Calculate & set the viewport ratio

int P = App.CurrentRenderPass;

// Only clear the screen on first pass

if (P) App.ClearScreenMode = 1;
else   App.ClearScreenMode = 0;

App.CameraPosition.X = -0.1;
App.CameraPosition.Y = 0;
App.CameraPosition.Z = 12;

if (App.RenderPasses > 1)
{
  if (App.CurrentRenderPass == 0) App.CameraPosition.X -= 0.1;
  if (App.CurrentRenderPass == 1) App.CameraPosition.X += 0.1;

  if (App.CurrentRenderPass == 2)
  {
    App.CameraPosition.X = 0;
    App.CameraPosition.Y = 1000;
    App.CameraPosition.Z = 0;
  }
}]]>
      </Expression>
    </ZExpression>
  </OnBeginRenderPass>
  <OnRender>
    <RenderTransformGroup Comment="Sky" Scale="150 100 150">
      <Children>
        <UseMaterial Material="SkyMaterial"/>
        <RenderMesh Mesh="SphereMesh"/>
      </Children>
    </RenderTransformGroup>
    <RenderTransformGroup Comment="Ground" Scale="100 100 1" Translate="0 -6 -50" Rotate="-0.25 0 0">
      <Children>
        <UseMaterial Material="GroundMaterial"/>
        <RenderSprite/>
      </Children>
    </RenderTransformGroup>
    <Condition Comment="UI over double screen" Expression="return(App.RenderPasses &gt; 1 &amp;&amp; App.CurrentRenderPass == 2);">
      <OnTrue>
        <RenderTransformGroup Scale="0.01 10 1" Translate="0 1000 -10">
          <Children>
            <UseMaterial Material="BlackMaterial"/>
            <RenderSprite/>
          </Children>
        </RenderTransformGroup>
      </OnTrue>
      <OnFalse>
        <UseMaterial Material="TextMaterial"/>
        <RenderText Text="FPS " X="0.55" Y="-0.92" Scale="0.4" Align="1">
          <TextExpression>
<![CDATA[//"Hello " + "World " + IntToStr(App.FpsCounter)
IntToStr(App.ScreenWidth) + " "+ IntToStr(App.ScreenHeight);]]>
          </TextExpression>
        </RenderText>
      </OnFalse>
    </Condition>
  </OnRender>
  <Content>
    <Group Name="SpinnerGroup">
      <Children>
        <Model Name="SpinnerModel" Scale="2 2 1.5" RotationVelocity="0 0.5 0">
          <Definitions>
            <Variable Name="SpinnerTime"/>
          </Definitions>
          <OnUpdate>
            <Condition Expression="return CurrentModel.Position.Y&gt;5.5;">
              <OnTrue>
                <RemoveModel/>
              </OnTrue>
            </Condition>
            <ZExpression>
              <Expression>
<![CDATA[SpinnerTime+=App.DeltaTime*0.75;

float Temp1;
Temp1=-4 + SpinnerTime;
Temp1+=noise2(CurrentModel.Personality,SpinnerTime*0.5) * 1.0;
Temp1+=noise2((SpinnerTime+App.Time)*0.25,0)*3;
CurrentModel.Position.Y=Temp1;

Temp1=sin(SpinnerTime*2)*4;
Temp1+=noise2((SpinnerTime+App.Time)*0.2,0)*8;
CurrentModel.Position.X=Temp1;

Temp1=cos(SpinnerTime*2)*4;
CurrentModel.Position.Z=Temp1;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="SpinnerMaterial"/>
            <RenderMesh Mesh="SpinnerMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="SpinnerMesh">
          <Producers>
            <MeshSphere Scale="0.25 0.25 0.25" ZSamples="8" RadialSamples="8"/>
          </Producers>
        </Mesh>
        <Material Name="SpinnerMaterial" Shading="1" Color="0.5 0 0 1"/>
      </Children>
    </Group> <!-- SpinnerGroup -->

    <Array Name="View" Type="1" Dimensions="1" SizeDim1="3" SizeDim2="4" Persistent="255">
      <Values>
<![CDATA[78DA6360800055260686F7501A990F03DE2C103E0049420392]]>
      </Values>
    </Array>
    <Model Name="System">
      <Comment>
<![CDATA[This is the easiest way to make sure glViewport is called before anything else.
Calling it in OnBeginRenderPass doesn't work since ZGE sets the viewport natively at the beginning of OnRender.]]>
      </Comment>
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[screenW= App.ScreenWidth;
screenH = App.ScreenHeight;

setVR(1);]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnRender>
        <ZExpression>
          <Expression>
<![CDATA[//

int P = App.CurrentRenderPass;

int X = View[P,0];
int Y = View[P,1];
int W = View[P,2];
int H = View[P,3];

//

glViewport(X,Y,W,H);]]>
          </Expression>
        </ZExpression>
      </OnRender>
    </Model>
    <Group Comment="meshes + materials">
      <Children>
        <Mesh Name="SphereMesh">
          <Producers>
            <MeshBox Scale="1 0.5 1" XCount="18" YCount="12" Grid2DOnly="255"/>
            <MeshExpression AutoNormals="0">
              <Expression>
<![CDATA[//

        float E, A, K, X, Y, Z;

        // Convert range to radians

        E = v.Y*PI; // Elevation
        A = v.X*PI; // Azimuth

        // Convert spherical coordinates into cartesian

        K = cos(E);

        X = sin(A)*K;
        Y = sin(E);
        Z = cos(A)*K;

        // Assign coordinates

        v.X = X;
        v.Y = Y;
        v.Z = Z;

        n.X = X;
        n.Y = Y;
        n.Z = Z;]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Bitmap Name="GroundBitmap" Width="16" Height="16">
          <Producers>
            <BitmapExpression UseBlankSource="1" Expression="pixel = x &gt; 0.98 || y &gt; 0.98 ? 1 : 0;"/>
          </Producers>
        </Bitmap>
        <Material Name="GroundMaterial" Shading="1" Color="0 1 0 0.5" Blend="2">
          <Textures>
            <MaterialTexture Texture="GroundBitmap" TextureScale="10 10 1" TextureWrapMode="1" TexCoords="1"/>
          </Textures>
        </Material>
        <Bitmap Name="SkyBitmap" Width="16" Height="128" Filter="2">
          <Producers>
            <BitmapFromFile Comment="Imported from sky.png" DataWidth="16" DataHeight="128">
              <BitmapFile>
<![CDATA[78DAB5D8F946C4511806E0F67D99F67ED7111189212211318C88884444242212119188881111912122464444222212119168DFF7BDAEE1F9239E0B98E59CEFBCDF1B54FD06A4DA54D6FC985A535187C2DFA6DE94377C994653D6849A3F4D8B298D7C98A82969456DEFA6DD1477BC994E53D485BA5F4D8F09F5BE983E53D88F069ECDA029187A32C3267F048D3E9A319337FE60264CEE249ABA37D326277667664CF62C9ABB35F3266BE1C6C44DE6225ABA36CB26237165564CFA2A5ABB34EB266DE3C26C9AD42DB47D6E764CCAEE99D933C9FBE8E0D41C9AA4A31373FCCFF0F3E8F7E5DF13FF2F3D0F7ADEF43CF37DC1FBA8F75DE789CE2B9E87386F759EEB7BA1EF11BF77F89EEA7BAD7940F306E719CC4B9AC734EF699EE4BC8A7958F3B6E679DD17781FC17D47F729DDD7741FE47D13F759DD97751FD77D9FFB04EC2BB40FD1BE45FB1CEE8BB08FD2BE4BFB34EDEBB80FC4BE51FB4CED4BB58FE5BE17FB64EDABB50FD7BE3DC03EFF0FB9DE52F5]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="SkyMaterial" WireframeWidth="0" Light="0" SpecularColor="0 0 0 1" EmissionColor="0 0 0 1" DrawBackFace="255">
          <Textures>
            <MaterialTexture Texture="SkyBitmap" TextureScale="1 1 0" TextureY="0.05" TexCoords="1" Origin="0 0 0"/>
          </Textures>
        </Material>
        <Material Name="BlackMaterial" Shading="1" Color="0 0 0 1" Light="0" ZBuffer="0"/>
      </Children>
    </Group>
    <Group Name="Font3Group">
      <Children>
        <Bitmap Name="FontBitmap3" Width="256" Height="32">
          <Producers>
            <BitmapFromFile Transparency="1" DataWidth="256" DataHeight="32">
              <BitmapFile>
<![CDATA[78DAED9BC19284300844E7FF7F7AF7B45596A3041A8831FBDE51CB4CC49634C4F97C0000000000000000000076E6E78FCB83478815A07F80EDF56F1C07D84FFCBC020000FFD3F99C523DFE1FD03FFA070000003879A726AF7579A1FF2AC3BCD95ECE73D5F0E78C012FA3710AE670F2978FC038E59F463E1A43CF3C3C6E8731A42859ABEBD41A7DA73C8F3BA97FCF2D0BD118EABF291A2565A3B0D99ACC724DD5AB9CFF3369CD8864F4B1CA031626A8687BE138DA5DA0AAD27526C93B63924C9B210FD09DD2F3FA37EE42D6BF16B1AAB4369C6DD4937C2BFC38A0712AB3F226FD6AF4A5084DC3693EE7B89A92E5A37CC05737A593B624B3FCE54F9578636D356CCDFF99D94E36F91D5583B6D4CEAC50A205F5CAE1D58ADC6EFFAFBD5C8227E9EBFF8466D2A77FFB54B48720F77FB4E655F27975EB7F3F6F0000008B94B1EBCCDC5885E7377B93CB6EA67915328A8600E4268FBF7E8956D9E8DF1FCFF2F25F1827F3D6084ACE6C06556DDE7D223BBCD1DD61D6A9E86B3BB3035CF55B9E2A2FB4E5A4B5A1B4E2DDAFE1D686EA7EF95FFB7BDA7BF53FECE408B76C6F2F66BC56288D8716AFA7FC8FF32304F4BF4D5E9A1CA8EF9D5C63264FE9BFF50BA2FC039AE9FF9F2A6AEEEC4A55D57037EC225B630FE699772D01ADFD9F05EBFA4CD72854FF6A1B85D16FD21E11FF2F2CB9AB28]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Font Name="Font3" Bitmap="FontBitmap3" FirstChar="33" CharPixelWidth="8" CharPixelHeight="8" BorderPixels="1"/>
        <Material Name="TextMaterial" Color="0.42 0.07 0.07 1" Light="0" Blend="1" ZBuffer="0" Font="Font3"/>
      </Children>
    </Group> <!-- Font3Group -->

  </Content>
</ZApplication>
Here's what's going on my phone:
Image

I'd like to avoid setting the screen manually as I don't know what hardware the game will run the game.

User avatar
VilleK
Site Admin
Posts: 1981
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Cardboard VR

Post by VilleK » Tue Apr 23, 2019 10:08 am

Hi, I've been away on vacation. Did you find a workaround or do you still have problems with ScreenWidth issue?

User avatar
Ats
Posts: 224
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Cardboard VR

Post by Ats » Wed Apr 24, 2019 9:28 am

Hi Ville :)

Kjell managed to help me by calling that on onUpdate:

Code: Select all

glGetIntegerv(0x0BA2, Viewport);
screenW = Viewport[2];
screenH = Viewport[3];
Here's my current Cardboard VR test:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Cardboard VR" ClearScreenMode="1" RenderPasses="3" ClearColor="0.24 0.24 0.24 1" ScreenMode="0" CameraPosition="0 1000 0" ClipFar="200" FileVersion="2" AndroidPackageName="com.mydomain.ZGEVR" AndroidPortrait="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <BeforeInitExp>
<![CDATA[if(ANDROID) {
  this.ModuleName = "libGLESv1_CM.so";
}]]>
      </BeforeInitExp>
      <Source>
<![CDATA[//

void glViewport(int X, int Y, int Width, int Height){}

void glGetIntegerv(int pname, xptr params){}]]>
      </Source>
    </ZExternalLibrary>
    <ZLibrary HasInitializer="1">
      <Source>
<![CDATA[int screenW = App.screenWidth;//2560;
int screenH = App.screenHeight;//1440;

float eyeSpace = 0.6;

void setScreen()
{
  glGetIntegerv(0x0BA2, Viewport);
  screenW = Viewport[2];
  screenH = Viewport[3];
}

void setVR(int i)
{
  switch(i)
  {
    case 0:
    App.RenderPasses = 1;

    View[0,0] = 0;
    View[0,1] = 0;
    View[0,2] = screenW;
    View[0,3] = screenH;
    break;

    case 1:
    App.RenderPasses = 3;

    View[0,0] = 0;
    View[0,1] = 0;
    View[0,2] = screenW / 2;
    View[0,3] = screenH;

    View[1,0] = screenW / 2;
    View[1,1] = 0;
    View[1,2] = screenW / 2;
    View[1,3] = screenH;

    View[2,0] = 0;
    View[2,1] = 0;
    View[2,2] = screenW;
    View[2,3] = screenH;
    break;
  }
}]]>
      </Source>
    </ZLibrary>
    <SpawnModel Model="System" SpawnStyle="1"/>
  </OnLoaded>
  <OnUpdate>
    <Timer Interval="0.31">
      <OnTimer>
        <SpawnModel Model="SpinnerModel"/>
      </OnTimer>
    </Timer>
    <KeyPress Comment="left click" Keys="{" RepeatDelay="0.2">
      <OnPressed>
        <ZExpression Expression="setVR(App.RenderPasses == 1 ? 1 : 0);"/>
      </OnPressed>
    </KeyPress>
    <KeyPress Comment="spacebar" CharCode="32" RepeatDelay="0.2">
      <OnPressed>
        <ZExpression Expression="setVR(App.RenderPasses == 1 ? 1 : 0);"/>
      </OnPressed>
    </KeyPress>
    <KeyPress Comment="left" Keys="&lt;Z" RepeatDelay="0.2">
      <OnPressed>
        <ZExpression Expression="eyeSpace -= 0.01;"/>
      </OnPressed>
    </KeyPress>
    <KeyPress Comment="right" Keys="&gt;X" RepeatDelay="0.2">
      <OnPressed>
        <ZExpression Expression="eyeSpace += 0.01;"/>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <OnBeginRenderPass>
    <ZExpression>
      <Expression>
<![CDATA[// Calculate & set the viewport ratio

int Pass = App.CurrentRenderPass;

// Only clear the screen on first pass

if (Pass) App.ClearScreenMode = 1;
else      App.ClearScreenMode = 0;

App.CameraPosition.X = 0;
App.CameraPosition.Y = 0;
App.CameraPosition.Z = 12;

if (App.RenderPasses > 1)
{
  switch (Pass)
  {
    case 0:
    App.CameraPosition.X -= eyeSpace;
    break;

    case 1:
    App.CameraPosition.X += eyeSpace;
    break;

    case 2:
    App.CameraPosition.X = 0;
    App.CameraPosition.Y = 1000;
    App.CameraPosition.Z = 0;
    break;
  }
}]]>
      </Expression>
    </ZExpression>
  </OnBeginRenderPass>
  <OnRender>
    <RenderTransformGroup Comment="Sky" Scale="150 100 150">
      <Children>
        <UseMaterial Material="SkyMaterial"/>
        <RenderMesh Mesh="SphereMesh"/>
      </Children>
    </RenderTransformGroup>
    <RenderTransformGroup Comment="Ground" Scale="100 100 1" Translate="0 -6 -50" Rotate="-0.25 0 0">
      <Children>
        <UseMaterial Material="GroundMaterial"/>
        <RenderSprite/>
      </Children>
    </RenderTransformGroup>
    <Condition Comment="UI over double screen" Expression="return(App.RenderPasses &gt; 1 &amp;&amp; App.CurrentRenderPass == 2);">
      <OnTrue>
        <RenderTransformGroup Scale="0.01 10 1" Translate="0 1000 -10">
          <Children>
            <UseMaterial Material="BlackMaterial"/>
            <RenderSprite/>
          </Children>
        </RenderTransformGroup>
      </OnTrue>
      <OnFalse>
        <UseMaterial Material="TextMaterial"/>
        <RenderText Y="-0.9" Scale="0.5" TextExpression="IntToStr(App.ScreenWidth) + &quot; &quot;+ IntToStr(App.ScreenHeight) + &quot; &quot; + IntToStr(eyeSpace*100);"/>
      </OnFalse>
    </Condition>
  </OnRender>
  <Content>
    <Group Name="SpinnerGroup">
      <Children>
        <Model Name="SpinnerModel" Scale="2 2 1.5" RotationVelocity="0 0.5 0">
          <Definitions>
            <Variable Name="SpinnerTime"/>
          </Definitions>
          <OnUpdate>
            <Condition Expression="return CurrentModel.Position.Y&gt;5.5;">
              <OnTrue>
                <RemoveModel/>
              </OnTrue>
            </Condition>
            <ZExpression>
              <Expression>
<![CDATA[SpinnerTime+=App.DeltaTime*0.75;

float Temp1;
Temp1=-4 + SpinnerTime;
Temp1+=noise2(CurrentModel.Personality,SpinnerTime*0.5) * 1.0;
Temp1+=noise2((SpinnerTime+App.Time)*0.25,0)*3;
CurrentModel.Position.Y=Temp1;

Temp1=sin(SpinnerTime*2)*4;
Temp1+=noise2((SpinnerTime+App.Time)*0.2,0)*8;
CurrentModel.Position.X=Temp1;

Temp1=cos(SpinnerTime*2)*4;
CurrentModel.Position.Z=Temp1;]]>
              </Expression>
            </ZExpression>
          </OnUpdate>
          <OnRender>
            <UseMaterial Material="SpinnerMaterial"/>
            <RenderMesh Mesh="SpinnerMesh"/>
          </OnRender>
        </Model>
        <Mesh Name="SpinnerMesh">
          <Producers>
            <MeshSphere Scale="0.25 0.25 0.25" ZSamples="8" RadialSamples="8"/>
          </Producers>
        </Mesh>
        <Material Name="SpinnerMaterial" Shading="1" Color="0.5 0 0 1"/>
      </Children>
    </Group> <!-- SpinnerGroup -->

    <Array Name="View" Type="1" Dimensions="1" SizeDim1="3" SizeDim2="4" Persistent="255">
      <Values>
<![CDATA[78DA6360800055260686F7501A990F03DE2C103E0049420392]]>
      </Values>
    </Array>
    <Model Name="System">
      <Comment>
<![CDATA[This is the easiest way to make sure glViewport is called before anything else.
Calling it in OnBeginRenderPass doesn't work since ZGE sets the viewport natively at the beginning of OnRender.]]>
      </Comment>
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[setScreen();
setVR(1);]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnRender>
        <ZExpression>
          <Expression>
<![CDATA[//
setScreen();

int P = App.CurrentRenderPass;

int X = View[P,0];
int Y = View[P,1];
int W = View[P,2];
int H = View[P,3];

//

glViewport(X,Y,W,H);]]>
          </Expression>
        </ZExpression>
      </OnRender>
    </Model>
    <Group Comment="meshes + materials">
      <Children>
        <Mesh Name="SphereMesh">
          <Producers>
            <MeshBox Scale="1 0.5 1" XCount="18" YCount="12" Grid2DOnly="255"/>
            <MeshExpression AutoNormals="0">
              <Expression>
<![CDATA[//

        float E, A, K, X, Y, Z;

        // Convert range to radians

        E = v.Y*PI; // Elevation
        A = v.X*PI; // Azimuth

        // Convert spherical coordinates into cartesian

        K = cos(E);

        X = sin(A)*K;
        Y = sin(E);
        Z = cos(A)*K;

        // Assign coordinates

        v.X = X;
        v.Y = Y;
        v.Z = Z;

        n.X = X;
        n.Y = Y;
        n.Z = Z;]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Bitmap Name="GroundBitmap" Width="16" Height="16">
          <Producers>
            <BitmapExpression UseBlankSource="1" Expression="pixel = x &gt; 0.98 || y &gt; 0.98 ? 1 : 0;"/>
          </Producers>
        </Bitmap>
        <Material Name="GroundMaterial" Shading="1" Color="0 1 0 0.5" Blend="2">
          <Textures>
            <MaterialTexture Texture="GroundBitmap" TextureScale="10 10 1" TextureWrapMode="1" TexCoords="1"/>
          </Textures>
        </Material>
        <Bitmap Name="SkyBitmap" Width="16" Height="128" Filter="2">
          <Producers>
            <BitmapFromFile Comment="Imported from sky.png" DataWidth="16" DataHeight="128">
              <BitmapFile>
<![CDATA[78DAB5D8F946C4511806E0F67D99F67ED7111189212211318C88884444242212119188881111912122464444222212119168DFF7BDAEE1F9239E0B98E59CEFBCDF1B54FD06A4DA54D6FC985A535187C2DFA6DE94377C994653D6849A3F4D8B298D7C98A82969456DEFA6DD1477BC994E53D485BA5F4D8F09F5BE983E53D88F069ECDA029187A32C3267F048D3E9A319337FE60264CEE249ABA37D326277667664CF62C9ABB35F3266BE1C6C44DE6225ABA36CB26237165564CFA2A5ABB34EB266DE3C26C9AD42DB47D6E764CCAEE99D933C9FBE8E0D41C9AA4A31373FCCFF0F3E8F7E5DF13FF2F3D0F7ADEF43CF37DC1FBA8F75DE789CE2B9E87386F759EEB7BA1EF11BF77F89EEA7BAD7940F306E719CC4B9AC734EF699EE4BC8A7958F3B6E679DD17781FC17D47F729DDD7741FE47D13F759DD97751FD77D9FFB04EC2BB40FD1BE45FB1CEE8BB08FD2BE4BFB34EDEBB80FC4BE51FB4CED4BB58FE5BE17FB64EDABB50FD7BE3DC03EFF0FB9DE52F5]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="SkyMaterial" WireframeWidth="0" Light="0" SpecularColor="0 0 0 1" EmissionColor="0 0 0 1" DrawBackFace="255">
          <Textures>
            <MaterialTexture Texture="SkyBitmap" TextureScale="1 1 0" TextureY="0.05" TexCoords="1" Origin="0 0 0"/>
          </Textures>
        </Material>
        <Material Name="BlackMaterial" Shading="1" Color="0 0 0 1" Light="0" ZBuffer="0"/>
      </Children>
    </Group>
    <Group Name="Font3Group">
      <Children>
        <Bitmap Name="FontBitmap3" Width="256" Height="32">
          <Producers>
            <BitmapFromFile Transparency="1" DataWidth="256" DataHeight="32">
              <BitmapFile>
<![CDATA[78DAED9BC19284300844E7FF7F7AF7B45596A3041A8831FBDE51CB4CC49634C4F97C0000000000000000000076E6E78FCB83478815A07F80EDF56F1C07D84FFCBC020000FFD3F99C523DFE1FD03FFA070000003879A726AF7579A1FF2AC3BCD95ECE73D5F0E78C012FA3710AE670F2978FC038E59F463E1A43CF3C3C6E8731A42859ABEBD41A7DA73C8F3BA97FCF2D0BD118EABF291A2565A3B0D99ACC724DD5AB9CFF3369CD8864F4B1CA031626A8687BE138DA5DA0AAD27526C93B63924C9B210FD09DD2F3FA37EE42D6BF16B1AAB4369C6DD4937C2BFC38A0712AB3F226FD6AF4A5084DC3693EE7B89A92E5A37CC05737A593B624B3FCE54F9578636D356CCDFF99D94E36F91D5583B6D4CEAC50A205F5CAE1D58ADC6EFFAFBD5C8227E9EBFF8466D2A77FFB54B48720F77FB4E655F27975EB7F3F6F0000008B94B1EBCCDC5885E7377B93CB6EA67915328A8600E4268FBF7E8956D9E8DF1FCFF2F25F1827F3D6084ACE6C06556DDE7D223BBCD1DD61D6A9E86B3BB3035CF55B9E2A2FB4E5A4B5A1B4E2DDAFE1D686EA7EF95FFB7BDA7BF53FECE408B76C6F2F66BC56288D8716AFA7FC8FF32304F4BF4D5E9A1CA8EF9D5C63264FE9BFF50BA2FC039AE9FF9F2A6AEEEC4A55D57037EC225B630FE699772D01ADFD9F05EBFA4CD72854FF6A1B85D16FD21E11FF2F2CB9AB28]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Font Name="Font3" Bitmap="FontBitmap3" FirstChar="33" CharPixelWidth="8" CharPixelHeight="8" BorderPixels="1"/>
        <Material Name="TextMaterial" Color="0.42 0.07 0.07 1" Light="0" Blend="1" ZBuffer="0" Font="Font3"/>
      </Children>
    </Group> <!-- Font3Group -->

    <Array Name="Viewport" Type="1" SizeDim1="4"/>
  </Content>
</ZApplication>

We can see the cushion deformation at the very bottom of the ground lines, but since the camera is not following the headset orientation, it does not bother me. I'm going to push that to Omeganaut today and see if I puke :D

Edit: I just discovered that my demo is only working for Android and preview mode in ZGE. Fullscreen mode on PC is broken...
Last edited by Ats on Thu Apr 25, 2019 1:28 am, edited 1 time in total.

User avatar
Ats
Posts: 224
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Cardboard VR

Post by Ats » Wed Apr 24, 2019 7:25 pm

I managed to make it work in Omeganaut :P

On Android, I'm displaying a first AppState without touching a thing, in my case, the disclaimer. This initiates the Android viewport. Then I can simply call:

Code: Select all

screenW = App.screenWidth;
screenH = App.screenHeight;
instead of

Code: Select all

glGetIntegerv(0x0BA2, Viewport);
screenW = Viewport[2];
screenH = Viewport[3];
Now I have a little problem: when I divide the screen into two parts, it shrinks the width of the screen per two. So the image looks slim on the X axis. How can I manage that? Does that have to do with the App.CustomViewportRatio ?

User avatar
Kjell
Posts: 1699
Joined: Sat Feb 23, 2008 11:15 pm

Re: Cardboard VR

Post by Kjell » Thu Apr 25, 2019 11:32 am

Hi Ats,
Ats wrote:
Wed Apr 24, 2019 7:25 pm
Now I have a little problem: when I divide the screen into two parts, it shrinks the width of the screen per two. So the image looks slim on the X axis. How can I manage that? Does that have to do with the App.CustomViewportRatio?
Correct, you need to use a custom viewport ratio set to the ratio of the viewports you're using for each eye. Here's a simple example ..

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ClearScreenMode="1" RenderPasses="2" ViewportRatio="1" RenderOrder="1" FileVersion="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <Source>
<![CDATA[//

void glClear(int mask){}
void glViewport(int x, int y, int width, int height){}]]>
      </Source>
    </ZExternalLibrary>
    <SpawnModel Model="Box"/>
    <ZExpression>
      <Expression>
<![CDATA[//

App.CustomViewportRatio = App.ScreenWidth * 0.5 / App.ScreenHeight;]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnRender>
    <ZExpression>
      <Expression>
<![CDATA[//

int w = App.ScreenWidth >> 1;

//

if(App.CurrentRenderPass)
{
  glViewport(w, 0, w, App.ScreenHeight);
}
else
{
  glClear(0x4100);
  glViewport(0, 0, w, App.ScreenHeight);
}]]>
      </Expression>
    </ZExpression>
  </OnRender>
  <Content>
    <Model Name="Box" RotationVelocity="0.2 0.3 0">
      <OnRender>
        <UseMaterial Material="BoxMaterial"/>
        <RenderMesh Mesh="BoxMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox/>
      </Producers>
    </Mesh>
    <Material Name="BoxMaterial" Shading="1"/>
  </Content>
</ZApplication>
K

Post Reply