Pages

Tuesday, November 26, 2013

Underwhelming Screenshot 4: Yet Another Cube

While this happens to be the very same cube as the last one, from exactly the same angle IIRC, this one is of note for being output from GLSL, and more importantly this should run on AMD GPU's... but I haven't tested it. In the "Display" menu there is an option to switch between GLSL and OpenCL for rendering on the fly. I took the time to make sure they are pixel for pixel the same, correcting the GLSL fragment coords to achieve this.

Of particular interest is the horizontal line through the middle of the cube. It only appears at certain angles, and I believe it to be the result of GLSL not handling infinity quite as nicely as OpenCL does, as the AABB-Slab method I used exploits floating points ability to store both positive and negative infinity. Alas I'm not sure if this is a bug or intended behaviour. Back in good news land, there as yet appears to be no difference in performance between the two implementations on my GTX 680. Here's the relevant commit.

Wednesday, November 13, 2013

Underwhelming Screenshot 3, but it's Perspective Correct!



Take a hard look at this one folks, it's something I can almost guarantee you've never seen in real-time graphics. It's a perspective correct cube. Check out those subtle curves on the edges, yeah triangles don't do that. Here's the GitHub link for the revision.

Monday, November 4, 2013

Shadertoy like OpenCL Kernel Tester


EDIT 2017-11-10: The build environment instructions I've given here are quite out of date, a current one can be found here. Regarding DLL's, MinGW can link directly against them, so there should no longer ever be a need to use dlltool or gendef in anger. END-EDIT

Well I say it's like Shadertoy, but it's nowhere near as good. Either way, it's OpenGL using a texture that's generated in OpenCL, and the CPU isn't getting involved. I've also rewiggled the build system, so now it should theoretically build Windows binaries from Linux, although my Debian Wheezy tests have so far not yielded success. I'm hoping there were bugs in the gcc-4.6 version of mingw64, but there's probably a flag somewhere I'm missing, as my Windows test with the same build config on native Windows version of mingw64 with gcc 4.8 worked a treat.

So GNU/Linux users, to build this type "make". You'll need the OpenCL dev files, and some X11 stuff. It should all be in your repository. It doesn't matter if you install the Nvidia OpenCL headers, or the AMD ones, or the Intel ones. They all work the same, and all speak to each other. Your distro's package manager should have everything on hand, shouldn't be more than a couple of megabytes.

Windows users, to build this type "make". Setting it up to be that easy is a bit of a task. First go download and install the mingw-get-setup.exe, run that and it will do some downloading and some thinking, and then present you with a list of things to install. Down the bottom is MSYS, we need that. We also need the minimal MinGW option at the top for a DLL tool it has, and while we're at it combine it with g++. Once that has finished its thing, (~100Mb later), go download MinGW-w64, and extract it to your C:\ drive. Yes in the root directory, it's a compiler, they're special beasts. Now right click on My computer, or whatever it is these days, and work your way to Advanced Settings and finally to edit your environment variables. Edit your Path, and at the start of it put the text... "c:\mingw64\bin;c:\MinGW\msys\1.0\bin;c:\MinGW\bin;". Now you've got a little bit of unix for your very ownsome. You can open a command prompt and type ls, rm, grep, even bash. Ahem, the last step is installing the OpenCL headers and libraries. I might get in trouble for distributing these files, but it's in good faith so err lets find out. The header files come from Khronos (via Nvidia), the def files were generated against Nvidia's OpenCL.dll and OpenCL64.dll. I'm pretty sure I modified the headers to not complain about using older style OpenCL commands, because that's all my implementation supported. So the files are not official, download this file OpenCL-MinGW.7z, put the contents of the include directory into your c:\mingw64\x86_64-w64-mingw32\include\ directory, and plonk the def files down for a tick, and run this command...
dlltool -l libOpenCL.a -d OpenCL.def -k -A
dlltool -l libOpenCL64.a -d OpenCL64.def -k -A
That will give you the lib.a files you need, stick them in c:\mingw64\x86_64-x64-mingw32\lib\ When the time comes that you want to use more modern OpenCL, you'll have to download the OpenCL SDK from your hardware manufacturer, find their DLL's, and run these commands on them...
gendef OpenCL.dll
gendef OpenCL64.dll
That will give you the .def files you need to give to dlltool. If you're cross compiling from GNU/Linux, dlltool is named "x86_64-w64-mingw32-dlltool". It can be coerced into producing the lib file straight from the DLL, but there's no way I'm going to distribute their DLL's.

Well, here's the link to the code. It builds on Debian Wheezy, and 64bit windows. You can build it in 32bit mode, but I've got datasets too big to fit in 4Gb of RAM. I don't support 32bit for this project. The upper case sigma, "Σ", reloads the OpenCL kernel from disk.

A note about OpenCL. If you've got current video card drivers from Nvidia or AMD then you already have all the OpenCL you need. I expect my OpenCL kernel will disagree with AMDs OpenCL compiler... feel free to fix it AMD owners :-)

Friday, September 13, 2013

Most Underwhelming Screenshot Attempt 2


Another in a soon to be oh so very long line of underwhelming screenshots. This one demonstrates OpenCL borrowing a texture from OpenGL, filling it with gradients, and returning it.

Just like the last underwhelming screenshot and if anything moreso, this is a portent of things to come.

Sunday, June 2, 2013

GUI progress

So there's the progress on the GUI so far. As I plan on making it the usual, here is the branch on GitHub. There's nothing particularly fancy to report, it's yet another GUI framework for OpenGL, but this has the almost unique distinction of being written in C99. It's all WIP, so if you use it, don't be surprised when the next version breaks everything.

Thursday, November 22, 2012

One Shiny Dragon + Source

This is viewing a hollow shell of the XYZ RGB Asian Dragon at 1024^3, using what I've written so far of my attempt to implement Cyril Crassin's GigaVoxel method. At the moment it would be optimistic to say I have partly implemented a quarter of it, but it's capable of drawing shiny dragons, and I'd like to share them :-) The original dragon has a tad more detail than 2048^3 can store, which I intend to address in the next phase of the method, mip-mapping. In the mean time, I for one always get sad when I read a blog post about something really cool, and I can't play with it myself.

GitHub - Win32 Binaries - zlib licensed.
This should build with minimal fiddling on your favourite linux distro. I use Debian, but it only depends on X and zlib, so should be easy to build. It also loves clang. It's written in pure C99, at least that's what I tell the compiler.



Going Deeper...


To all yee who explore the source code, fair warning, it's a hatchet job. With that in mind I hope it should make a kind of sense. The first thing you'll want to look at is the Makefile. convert and convertoct convert simple Wavefront OBJ files, as output by Blender, into a format suitable for throwing at a video card. Worth grabbing the win32 binaries for the included data file, it's not in the git repo.

convert and polyview


convert turns the OBJ file into the format that polyview expects for a VBO. polyview loads the file into memory, tells OpenGL where it is in memory and how it's formatted, and runs a simple display loop. It's not terribly clever, but it does push all of the load onto the video card, leaving the CPU idle in my tests.

convertoct and octview


convertoct produces a Sparse Voxel Octtree by discarding the polygons of a mesh file produced by convert, and throwing the points (and their normals) into a buffer. Hatchet Job. So this will only work with models that have a uniform vertex density, mostly 3D scanned objects (like the dragon, and the bunny).

The Data


A 1024^3 cube is big. That's out of the box we're talking about a Gigabyte of data if we're only using a single byte per voxel, but I'm using 4 floats. This means we don't have enough video memory. Well, it's sparse, which brings it down to 900Mb. The texture data is zipped up with zlib, which brings the data file down to a much more reasonable 17Mb. It's still extracting to 900Mb of RAM though. Due to ?!?!?, the current Nvidia drivers don't like me allocating 900Mb of texture memory on Windows 7, so the drivers convert it to 16bit floats, bringing it down to 450Mb, which it's quite happy with. This doesn't seem to affect performance in this instance, as I'm already abusing the video card in plenty of other ways. 64bit executables solve this problem, I've updated the binary and now it does allocate the full 900Mb.

The Build System & Porting


The idea is win32.c and x11.c are "shivs", all platform dependant things are in there, they obey their respective OS's rules, and they toggle fullscreen when pressing F11. They call main_* functions in polyview.c or octview.c depending which one is linked. polyview.c has almost no intelligence at all, it's just a test mesh displayer. octview.c is marginally better, providing simple FPS controls, and handballing off to voxel.c. Making a osx.c shiv should be pretty easy, and I'm fairly sure I already have one laying around from an older project.

voxel.c


This is where we find the initialisation, the texture block is decompressed with zlib, and loaded into a vanilla old OpenGL 3D floating point texture. The Node Pool is loaded into the format that Nvidia requires when you're planning on breaking the legs of the GLSL standard, like I am doing here. The main brains of the program is located in the fragment shader, which this file dutifully loads and compiles it ready for the GPU to use. The final text in this file is a few lines that update variables for the shader, such as the camera position, and then render a single flat polygon covering the whole screen. As all of the work is done in the fragment shader, it will be called once per pixel on the screen (unless you're using antialiasing, then this will run horribly slow, and at no visual benefit at all, this rendering method is aliasing free to begin with). OpenGL experts will marvel at how primitively I'm drawing the quad, and possibly be driven to self harm. Pressing the R key will reload the shader from disk, useful for debugging.

render.frag


To understand this code you'll really have to read Cyril Crassin's PhD, which can be found here. The quick version is that for each pixel it traces a path through the Sparse Voxel Octtree that was built by convertoct. There's nothing more complicated than that going on, so there's currently no point comparing it to Gigavoxels. Also it does it in GLSL, as opposed to a real GPU compute language, so mine is an amusing abuse of GPU power, at best. For now...

Tuesday, November 20, 2012

Voxel Rendering Update


Here's the current progress with simple diffuse lighting. Viewing on the higher resolutions will reveal that I've still got some edge cases to go, quite literally. I think I've got some divide by zero's hiding in the block stepping code, which is why you can see the edges of the voxel blocks. While the video is recorded at 30fps, while I was capturing the video it was running at never less than 40fps, most of the time holding the constant 60fps my old LCD permits. At 1920x1200, 8 bits per colour channel. This is on a GTX680, and I'm feeling rather chuffed that not only this runs smoothly, but that it runs smoothly while recording HD video too :-)