Tuesday, June 14, 2016

Cheap IBL + reflections test

Quick post showing a quick WIP of a cheap all realtime IBL + reflections solution for my VR engine.  Nothing really fancy to show here except that the project is still going.  It's kind of annoying having to manually index and project for a linear cubemap format too.  I may do a pass to convert to lat + long to reduce maps and sampling a la GTA later too.  Right now the next step is to do importance sampling reference in realtime before going too far into screen space ray tracing and compute maddness.  I also added support for 'metalness' materials back for this scene.  It might be worth looking into a metalness only pipeline or even deferred texturing for VR just for GBuffer reduction to help aging GPUs.  The annoying part is this scene is all one FBX, so I ended up fixing some FBX compiler issues with per polygon materials not cooking properly.  I think it ends up being quite a bit of submeshes without instancing.

Looking into GI and related features next most likely if not SDFs for fluids and shadows or finishing up the OIT system for more than fluids.

Indirect Lighting ON
Direct Lighting ON
Reflections ON
Direct Lighting ON
Indirect Lighting ON
Reflections OFF
Indirect Lighting ON
Direct Lighting OFF
Reflections OFF

Monday, May 16, 2016

SteamVR (beta) under Linux

Update 20160523
Forgot to update this at the end of the week.  Busy with work.  :)

Turns out I needed to kick the compositor right after submitting both texture refs ( I output a single target, but it updates in one pass instead of two ).  After that I don't have Dutch orange as a background anymore.  I should also clarify that my demo doesn't need any user setup to run with Vive at all once the driver config steps are done once.  Unlike ye olde DK2 setup where you need to HUP the ovr daemon, or older SteamVr vrserver --keepalive.

Sadly as noted before the UV support for single target appears to not work under Linux SteamVR in the sense it applies the values incorrectly by splitting the single target twice.  The same test in Windows SteamVR outputs as expected.  Also the SteamVR compositor tends to have a window title as well.  I could likely hack around the title issue using a WM hint mutation program like DevilsPie2 for GNOME if needed.

It almost works, rendering and compositing anyway...
For the curious this is as far as I got SteamVR ( beta ) and hellovr running under Linux at present.  This is using my fork of OpenVR.

Right now my game is just drawing orange to the compositor, so stay tuned.  I might hack it up this week if I get enough time.  Before this was all extended mode hacks under Linux.  :3

Poorly written up dump of what I had to do to get beta running
Shared in the hopes it helps someone.  I'm not sure why I had to manually create json files and add paths, so beware only tested on my box.  Also I may have forgot some change I did locally.  :3

If you're using my OpenVR fork remember hellovr searches for the PNG in the '..' path.  Also note if you copy your lighthousedb.json files from a Windows machine they should auto downgrade to the older SteamVR version.  I didn't do an strace to see if some files such as chaperone_info.vrchap are even read, but be aware they exist on Windows SteamVR.

Lib path

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/thendrix/Steam/SteamApps/common/SteamVR/bin/linux64:/home/thendrix/Steam/SteamApps/common/SteamVR/drivers/lighthouse/bin/linux64

USB permissions

sudo chmod a+rw /dev/hidraw*

Steam/config/streamvr.vrsettings - ( May need to comment out bodys if this fails )
   "jsonid" : "vrsettings",
   "steamvr" : {
     // "automaticDirectModeEnabled" : true,
     // "requestDirectModeDisabled" : false,
     // "requestDirectModeEnabled" : false,
  "ipd": 0.0635,
  "forcedDriver": "lighthouse",
  "forcedHmd": "",
  "requireHmd": true,
  "displayDebug": false,
  "enableDistortion": true,
  "displayDebugX": 0,
  "displayDebugY": 0, 
  "sendSystemButtonToAllApps": false,
  "loglevel": 3
  "background": "backgrounds/image_%d.png"
   "driver_lighthouse": {
   "disableimu": false,
   "usedisambiguation": "tdm",
   "disambiguationdebug": 0,
   "primarybasestation": 0,
   "lighthousename": "",
   "maxincidenceangledegrees": 60.0,
   "uselighthousedirect": true,
   "dbhistory": false,
   "originoffsetx": 0.0,
   "originoffsety": 1.0,
   "originoffsetz": 0.0,
   "headingoffset": 0.0,
   "driver_null" : {
  // drivers are searched in alphabetical order, so you may need steamvr.forcedDriver="null" as well
  "enable": true,
  "id": "Null Driver",
  "serialNumber": "Null 4711",
  "modelNumber": "Null Model Number",
  "windowX": 100,
  "windowY": 100,
  "windowWidth": 1920,
  "windowHeight": 1080,
  "renderWidth": 1344,
  "renderHeight": 1512,
  "secondsFromVsyncToPhotons": 0.1,
  "displayFrequency": 90
   "version" : "1"

Path registry setup
thendrix@xenophon ~/Steam/SteamApps/common/SteamVR/bin/linux64 $ ./vrpathreg --help
  show - Display the current paths
  setruntime <path> - Sets the runtime path
  setthis - Sets the runtime path to the runtime that vrpathreg lives in
  setconfig  - Sets the config path
  setlog  - Sets the log path
  adddriver  - Adds an external driver
  removedriver  - Removes an external driver


thendrix@xenophon ~/Steam/SteamApps/common/SteamVR/bin/linux64 $ ./vrpathreg
Runtime path = /home/thendrix/Steam/SteamApps/common/SteamVR/
Config path = /home/thendrix/Steam/config/
Log path = /home/thendrix/Steam/logs

Linux OpenVR hacks

After trolling the steam forums a few days ago with this:

I notice this today:

Hopefully have an update at the end of the week.  :)

First time I tested on an HMD in a while, and I notice the new deferred water isn't setup correctly.  Pretty handy to have a dynamic RT browser.

Bonus for those wondering there is a branchless way to do screen-space pass UVs for single target + serialized | two target parallel.  Blogger makes it painful to post source... sorry if it screws it up after I hit update.  :)

out vec2 v_Texcoord;

void main()
    // Fullscreen clipped triangle.
    int x = ( gl_VertexID << 1 ) & 2;
    int y =  gl_VertexID & 2;
    v_Texcoord = vec2( x, y );
    gl_Position = vec4( v_Texcoord * vec2( 2.0, 2.0 ) + vec2( -1.0, -1.0 ), 0.0, 1.0 );

    // Monoscopic : 2.0, RightEye : 1.0, LeftEye : 0.0
    // { scale = 1, offset = 0 }; { scale = 0.5, offset = 0.5 }; { scale = 0.5, offset = 0.0 }
    int i = int(floor( _Eye )) >> 1; 
    float stereo = 1.0 - i;
    float scale = 1.0 - 0.5 * stereo;
    float offset = 0.5 * _Eye * stereo;
    v_Texcoord.x = v_Texcoord.x * scale + offset;

Sunday, May 15, 2016

Hhmm... oh yeah

I switched over to IMGUI a while back for a debug UI.  Currently I have an accordion-style property editor w/ inline material editing et al.  Not as fully featured as the HTML interface, but easier for blokes with just laptops.  :3

Saturday, January 30, 2016


Update: Screenshots with realistic sized trees on same terrain, and fixed some links.  :3

Tree scale now in 10-20m range.

I noticed r/proceduralgeneration has a lot activity lately, so I thought I would do quick post on how I'm generating my current test islands with only 4 functions.  This is what they typically look like:

Terrain generated by simple density function.

Terrian Geometry
I basically use both 2d and 3d simplex noise to add and subtract a global density function, which is described per terrain cube.  You can stack cubes like octrees, or more typically just a simple XZ grid.  This density function is used to produce voxels, which are then in turn converted to meshes for physics and rendering.  I don't use GPU rendering of the voxels as I need that GPU time for VR.  :3

All of this is done in realtime via the clever use of worker threads with the option to serialize them out as models.  Each cube is typically 256 meters.  Yes, this means if you want really tall mountains you need to stack another layer of cubes on top of your XZ grid.

This listing shows how I build the density function to pass into a now obsolete KaMeshComponent, which will then in turn start deferred creation of the meshes for physics and rendering.  The above island is solely defined as as the global density function:

local density = KaDensity.Create()
KaDensity.Seed( density, 2312.0, 0.0, 561.972 )
KaDensity.AddFractalNoise2d( density, 6, 32.0, 8.0, 0.0, 32.0 )
KaDensity.AddFractalNoise2d( density, 10, 8.0, 8.0, 0.0, 8.0 )
KaDensity.SubFractalNoise2d( density, 10, 64.0, 8.0, 0.0, 6.0 )
KaDensity.AddFractalNoise3d( density, 3, 32.0, 4.5 )

listing 1

Notice there is little use of 3d, as that is more for making hills, caves, rivers, and arches.  Also you could introduce local density for features, but I don't typically do any manual level editing at this point in project.  This is one of my small islands used for testing materials.

Terrian Material
The terrain is composed from a simple triplanar shader.  World height, world slope, and a per pixel Fractal Brownian Motion ( FBM ) to break up the monotony of ground foliage.  There are typically beach sand, dirt, grass ( eg green to brown / height ), and stone generated from this step.  Since you can modify shaders at runtime in kagura this can be fun to improve when you have a few extra minutes in the day.

Terrian Foliage
Once terrain geometry is instanced it will be filled with large vegetation and deco such as bushes and trees to rocks and statues.  For every XY terrain sector I generate a SpawnTracer.  The spawner will 'ping' for the worker threads to be done by ray casting for terrain to appear in its given sector.  Once this is done it issues the given spawn callback.  In this case the callback is a per sector foliage trace driven again by a grid pattern filtered by a tillable FBM ( see old blog post ), slope, height, max per tile count of an object type, and a few other attributes.  This pass handles the case where a house is placed on terrain for example, so it would not put trees and grass on top of it.  It is important to note these happen out of order, and the tiling pattern provided by the FBM is the trick making smooth transitions between tiles possible.

Closer look at the same scene

That's basically how the system works, and it's a little more complex than that but not much.  I'd be happy to answer any questions or take comments.  Here's a script function that creates the entire island above:

function VoxelTerrainComponent.OnCreate( self )
        local sz = self.width
        local hsz = self.height
        local scale = 256.0

        local density = KaDensity.Create()
        KaDensity.Seed( density, 2312.0, 0.0, 561.972 )
        KaDensity.AddFractalNoise2d( density, 6, 32.0, 8.0, 0.0, 32.0 )
        KaDensity.AddFractalNoise2d( density, 10, 8.0, 8.0, 0.0, 8.0 )
        KaDensity.SubFractalNoise2d( density, 10, 64.0, 8.0, 0.0, 6.0 )
        KaDensity.AddFractalNoise3d( density, 3, 32.0, 4.5 )

        for x = -sz, sz do
                for y = 0, hsz do
                        for z = -sz, sz do
                                local name = "VoxelMesh_" .. x .. "_" .. y .. "_" .. z
                                local dump = 'Cache/' .. name .. '.asset'
                                local sector = KaGameObject.New( x * scale, y * scale, z * scale )
                                KaGameObject.SetName( sector, name )
                                KaMeshComponent.CreateFromVoxels( sector, density, dump, self.material, x, y, z )
                                KaGameObject.Finalize( sector )
                                KaGameObject.Hide( sector )
                                KaGameObject.AddChild( self._GameObject, sector )

                                if self.foliage and y == 0.0 then
                                        -- Place spawners and mappers in the middle of the voxel sector.
                                        local offset = scale * 0.5
                                        SpawnByTracePrefabChild( "FoliageSpawner", self._GameObject,
                                                x * scale + offset,
                                                y * scale + scale * 0.75,
                                                z * scale + offset,
                                                -- VoxelSectorFoliageCb )
                                                VoxelSectorFoliageFbmCb )

listing 2

And here's what you can do with unfiltered 3d noise:

Wednesday, January 27, 2016

Always check visualizations...

You generally don't want collisions much less generate contact points between static objects.   :3

Tuesday, January 26, 2016

Got HMD working again...

Dug my DK2 back out, and got it hooked back up in my engine.  I somehow had emitter simulations run per eye per frame instead of per frame.  Also need to enforce soft particles in VR maybe.  What a productive lunch break.

Mismatched per eye.

Much better.  :3

Double-checked shadows and reflection probe are once per frame. ;3

Update a walk in the woods...

Very Large Area Test.

Same Area in with HMD off vsync'ed  60Hz.