Would there be any interest in an ambient occlusion plugin? I coded one that looks quite reasonable, but its performance isn't so good (takes about 10 seconds for a 1024^2 heightfield at sensible settings).
The source code and the built x64 device is attached.
It takes a heightfield as input.
You can specifiy the number of rays per pixel, the minimum hit distance for a ray (this is great for edge highlighting) and the maximum distance a ray travels, along with a height scaling factor.
Made with pdk 2.3.6
Image of the AO in action:
That looks interesting. How would one add this as a device to WM?
Unzip the .dll file into plugins/devices.
Good work! I'm sure some folks will find it very useful -- AO is quite nice in improving the sky lighting quality as opposed to straight ambient.
Funny enough, a while back I had been meaning to add AO to the lightmap generator but got bogged down on a side quest to improve the raytracing performance of the generator and never got to it.
If you're interested in adding some improvements, a couple quick notes after looking at it:
With regard to scale:
You can get the vertical scale of the heightfield with hf->getVScale(). This is in "WM units" (1WM = 8km).
You can get the detail scale (defined as HF pixels per WM unit) with hf->getDScale().
The combination of these two lets you do 2 things to make the results more consistent across scales:
1) Determining the max height of a heightfield (value 1.0) measured as volumetric pixels, can be achieved by pixel_height = hf->getVScale() * hf->getDScale(). This lets you drop the height parameter from the device.
2) Adjust the maximum raymarch distance based on the detail scale. ie: max_raymarch_dist *= getDScale(). Note that this treats the original "pixel" distance as a worldspace distance in WM units. Sometimes it's useful to add an adjustment factor to make this more familiar (for example, a 256x256 8kmx8km HF will have a DScale() of 256 -- if you want that to be the baseline when interpreting some given distance, divide the DScale by 256.
Again, nice work!
You are free to use the source (its included in the archive), completely free license.
I do have one more question though, as I couldnt find a good example: how can I multithread this device?
Currently this is available in DeviceThreadHelper.h, however it is a relatively boilerplate-heavy C++03 solution.
The simplest version to use is ThreadHelperScanline, when your device is embarrassingly parallel. To do so:
1) Create a new class derived from ThreadHelperScanline
2) In your new class constructor, save all values, etc that you need.
3) Implement the doActionFunc() virtual method. This method will be called from multiple threads, and passed a ThreadScanlineWork pointer for the first parameter, which contains a single Coord containing the scanline range that this thread should calculate results for.
A vastly boilerplate-reduced c++11 version using lambdas will be available pretty soon, which should provide more or less transparent multi-threading ability (your loop body is put into a lambda, and the framework would take care of all threading issues)
I just ran my plugin on an 8192 sized map, and it only added half an hour to the run time, with settings that could be considered 'good quality'.
This is faster than using xNormal (which is an excellent program, but is designed for meshes, and jamming in obj meshes of this size is not prudent).
My next step is to use reflective scattering (similar to tone mapping) as the following:
-If a ray hits a bit of terrain, it will use the texture color in the area.
-if a ray does not hit terrain, it will look up the sky color at that point from a 'sky color map'.
The only thing missing (forgive my ignorance) is that I cant seem to find a good example of reading the RGB values of a bitmap input. No method similar to the HF() wrapper seems to exist.
I'm excited to see where you take this!
Bitmaps function almost identically to heightfields, you just need to use a different datatype : BMPacket, defined in BMPacket.h.
It actually shares a template base class (defined in GridPacket.h) with heightfield, so most of the operations defined are identical, but work on colorF values (triples of floating point color) rather than a single float.
You have a similar casting operator available to get at your input from a generic packetpointer: BMP(packet).
Full set of steps required:
1) In your object constructor set the datatype for one of your inputs to bitmap (in(1)->SetType(WMP_rgb), for example).
2) Retrieve and cast to BMPointer in your Activate function (BMPointer rgb = BMP(RetrieveInput(1, context))
3) Use! (ex: colorF c = rgb->value(Coord(0,0)); )
please forgive my ignorance, but i learn best from examples. could you link to a multithreaded working simple example, as the way input and output heightfields are passed to the multithreaded implementation is not clear to me. thanks!
sorry to annoy the pro´s here, but i would be very grateful if someone could hint me on how to get this into WM. i dropped the DLL into the mentioned folder, but its not showing anywhere in the device menu. Anyone care to point me into the right direction ?
@Beherith: Is your reflective scattering plugin in development? Also, could you specify if your AO plugin build is the latest or do you have a newer version?
nice job anyway!
I did not pursue the further development of this plugin, so this is pretty much the latest build for now. The source code is shared and Public Domain.
It seems to crash every time I build a map resolution bigger than 512...
I am using 126.96.36.199 64bit and unable to get this AO plugin to be available anywhere in the UI. Is there away to get verbose app loading to see why it will not register correctly.
Looking at the source code that was so generously provided I even tried adding AO01 to my favorites bar in the world.ini file. This had no effect either, any help would be appreciated.