Showing posts with label GPU. Show all posts
Showing posts with label GPU. Show all posts

2011/11/04

My clouds are so fluffy, you're gonna die!

Today I'm showing some cloud textures that I managed to create with a simple algorithm using a Poisson-disk sampling process to distribute some points. What is nice with this process to distribute point is that it's very portable and efficient. It can even be done in parallel on the GPU (with CUDA or OpenCL), this paper actually shows one way to do it: Efficient Maximal Poisson-disk Sampling.

The rendering process for now is done completely on the CPU because we are still in a phase where we need to be able to add, change or remove some part quite fast to adjust the renderer to our needs. It's a bit harder to do that on the GPU. But when we will be completely sure of the product that we want, we will adapt it to the GPU, probably with OpenCL for portability reasons.

So here some of these outputs:






There's still a little bit of work to do to remove some isolated points that we can see in some images. I might have some idea to solve this, just need to implement it. So, let me know what you think about those images.

2011/09/30

research news

I don't have new stuff to show right now, but I've been busy in the last week. I'm currently implementing a more dynamic version of my renderer. CUDA is very nice, but when you need to add quickly new modules or do some rapid tweaks, it's not the best solution. So, for now the plan is to render to have a slower renderer that would be easier to change and adapt. When we're sure of the features that we really want to keep and we'll know the full limitation of our system, an implementation in CUDA would be possible.

One of the reason to change the renderer is that I needed some C++ features like virtual functions, which is very useful for designing rapidly a new system. I think there's some language that allows to create virtual function in CUDA or OpenCL by simply adding some hidden piece of code.

If it doesn't exist, here's how I'd do it:

First, in CUDA, there's no function pointers. But if we take a look at how polymorphism works, it's really just a way to disguise procedural code. Actually, the whole object oriented programming scheme is just a way to disguise procedural code by hiding some information to the programmer so (s)he doesn't have to worry about it. Just like many other languages do (Java is the most popular about that one because it hides a lot of security features like buffer overflows done during the execution to avoid major problems).

So, if we have:
class A
{
private:
  int value;
public:
  A(void);
  virtual ~A(void);
  virtual void test(T param1, U param2);
};
Then this piece of code is actually converted into something that look basically like this:
// prototypes
struct class_A;
void __class_A_constructor(struct class_A *this);
void __class_A_destructor(struct class_A *this);
void __class_A_test(struct class_A *this, T param1, U param2);
struct class_A_virtual_table
{
  void (*class_A_destructor)(struct class_A *this);
  void (*class_A_test)(struct class_A *this, T param1, U param2);
};

// create a single instance of the virtual table and assign the values for the function pointersstruct class_A_virtual_table class_A_virtual_table_only_instance_needed =
{
  __class_A_destructor,
  __class_A_test
};
struct class_A
{
  class_A_virtual_table *VT;
  int value;
};
void __class_A_constructor(struct class_A *this)
{
  this->value = 0; // or some other default value
  this->VT = &class_A_virtual_table_only_instance_needed;
}
void __class_A_destructor(struct class_A *this)
{
  // stuff to destroy
}
void __class_A_test(struct class_A *this, T param1, U param2)
{
  // stuff to test
}
// virtual functions
void virtual_class_A_destructor(struct class_A *this)
{
  this->VT.class_A_destructor(this);
}
void virtual_class_A_test(struct class_A*this, T param1, U param2)
{
  this->VT.class_A_test(this, param1, param2);
}
And then, with a subclass B, we have:
class B: public A
{
private:
  double value;
public:
  B(void);
  ~B(void);
  void test(T param1, U param2);  // version of test but for class B
  void function_in_B(void);
}; 
int main(void)
{
  B b;
  A *a = &b;
  a->test(1, 2);  // let way that type T and U are integers...
  b.function_in_B();
}
Then, all of this become:
struct class_B
{
  struct class_A super;
  double value;
};
// prototypes for class B
void __class_B_constructor(struct class_B *this);
void __class_B_destructor(struct class_B *this);
void __class_B_test(struct class_B *this, T param1, U param2);
void __class_B_function_in_B(struct class_B *this);
// virtual table for B, with the virtual functions for B
struct class_A_virtual_table class_B_virtual_table_only_instance_needed =
{
  __class_B_destructor,
  __class_B_test
};
void __class_B_constructor(struct class_B *this)
{
  __class_B_constructor(&(this->super));
  this->VT = &class_B_virtual_table_only_instance_needed;  // replace the virtual table
  this->value = 0.0; // or some other default value
}
void __class_B_destructor(struct class_B *this)
{
  // stuff to destroy in B
  __class_A_destructor(&(this->super));  // then, destroy the stuff in the parent
}
void __class_B_test(struct class_B *this, T param1, U param2)
{
  // stuff to test, but for B
}
void __class_B_function_in_B(struct class_B *this)
{
  // whatever that function does!
}
int main(void)
{
  struct class_B b;
  __class_B_constructor(&b);
  struct class_A *a = &(b.super);  // the address of the parent in struct class_B
  virtual_class_A_test(a, 1, 2);
   __class_B_function_in_B(&b);
  __class_B_destructor(&b);
}
So, as you can see, polymorphism is using function pointers to create the illusion that the right function is called each time.

But, without any function pointers, we need to recreate that illusion. So, one way that can be done in CUDA/OpenCL, is to add a unique ID for each class. And each instance of that class will have that ID assigned in the constructor. So:
enum CLASS_IDS { CLASS_A_ID, CLASS_B_ID, ..., CLASS_X_ID };
struct class_A
{
  int ID;
  int value;
};
void __class_A_constructor(struct class_A *this)
{
  this->ID = CLASS_A_ID;
  this->value = 0; // or some other default value
}
struct class_B
{
  struct class_A super;
  double value;
};
void __class_B_constructor(struct class_B *this)
{
  __class_A_constructor(&(this->super));  // always call the parent constructor first!
  this->ID = CLASS_B_ID;  // overwrite the ID
  this->value = 0.0; // or some other default value
}
Finally, write the virtual functions like this:
void virtual_class_A_destructor(struct class_A *this)
{
  switch(this->ID)
  {
  case CLASS_A_ID:
    __class_A_destructor(this);
    break;
  case CLASS_B_ID:
    __class_B_destructor((class_B*)this);
    break;
  // ...
  case CLASS_X_ID:
    __class_X_destructor((class_X*)this);
    break;
  };
}
So, with a switch statement, it's possible to replace the virtual table. So, a compiler that would be able to take C++ code and convert it in CUDA/OpenCL would be able to do polymorphism with that approach. It's much more slower than a function pointer, but the result of the computation would be the same.

I think that such compilers exist already, but I never used one of them. But it's probably using a method similar to the one above to emulate the virtual tables.

And for those of you who didn't know how polymorphism worked, now you have a better idea of the process the compiler has to do to convert classes and their virtual functions in machine bytecode. So, I hoped that post helps a bit for that. Otherwise, there's a couple of resources available on the web that would clearly describe that process.

If any of you know a (free if possible) compiler that convert basic C++ code in CUDA or OpenCL, but also has integrated some of the features of those languages like the synchronization between threads of the same bloc and atomic operations, I'd really like to see that and use it eventually. It must work on Linux!

2011/08/24

Hierarchy textures

So, it's been a while. I was so busy at SIGGRAPH that I never had the time to share anything.

In this post, I'm showing you some of the last textures I've been working on. These are build as a hierarchy. We use again our variation of the Voronoi diagram to create weird shapes. But this time, instead of using simply one level, we introduce many levels.

On the first level, again, the Voronoi cells are computed and once we know in which cell we are, if that cell has a sub-level, we can then continue the visit in the structure into that sub-level. Each level has can have a small or big influence on the final color of the pixel.

So, here's some outputs:

One of the first output made. It has two cells on the first level. One is the circle-like shape in the middle and then the rest. In the "rest", there's a sub level with a simple small division of the plane in two.

Exactly as the previous one, but here, there's a sub-level in the circle-like shape. As you can see, the fact that there's a new sub-level only affects the part where that sub-level is.

The actual first output that I got with the hierarchy.

In the next images, I start playing with colors inside the cells. Naturally, all of these images where made from random point distribution.



In these images, I simply played with the hierarchy. Each cell has a random chance to get a sub-level and so on. Until a maximal depth was reached. In some of them, I played also with the feature that at each level, you can influence the final color by accumulating a value.





Finally, there's two big step to do before we consider that project finished. First, we want to investigate various patterns. So, how can we do a particular shape for a cell. For this part, we don't need the hierarchy because we know it works. When we are able to control properly the patterns, we will be able to used them at various level.

Second, we want to be more dynamic for the color. Right now, each cell use a function f:[0;1]->[0;1] to control its value that will influence all the other levels. But those functions are a bit static. I can add more, but it will never be enough. So we turn to use something like the shaders in OpenGL. Literally, each cell could have its own function (coded in CUDA-C) and that function would be used to control the contribution of that cell and its sub-level to the final color of the pixel.

2011/07/28

upgrades on Twin Pictures

So today I published a new version of Twin Pictures. I added some interesting features.

First, for the second image, you can choose instead to use the first image in negative. So, just like the default settings with the Android logo, it creates a really great effect. You can really enjoy the dueling process for the two images with the negative option.

Here's an example with the Mortal Kombat Logo:


I also added new ways to split the screen for the images:

  • Random: the original method, no real structure, it's spinning around at various speed
  • Symmetry: this method splits the screen in two. So you see equally part of image 1 and image 2 at all time.
  • Asymmetry: this method can look symmetrical on certain point of view, but not on the part shared by the images. At some point, you will not see one of the image.
  • Symmetrical Yin Yang: this one is inspired by some pictures I showed in a previous post. The screen is split in two, but there's no axis of symmetry.
  • Asymmetrical Yin Yang: just like asymmetry above, it splits the screen, but not necessary equally and without an axis of symmetry.
It's also possible to set the brightness. The minimum is 50% and by default it's at 100%.

Next upgrade:

I'm looking at options for the part of the screen where the images intersect. For now, there's a very small change between the images. But it's enough to be a rough one (but it will be an option). So, i'm planning 5-6 options just to give more choice to the users with the visual aspect.


https://market.android.com/details?id=com.blogspot.widgg_research.twin

2011/07/26

A new live-wallpaper

Recently, I showed images about grouping points together to create a different kind of Voronoi diagram (see Merging Voronoi).

The case with two groups is very interesting because it splits the plane in two parts. I was first intrigued by what it would look like animated and then I imagined that if each group is associated with an image. It's possible to show parts of the first image where its group is visible and part of the second image where the second group is.

So I came up with a very simple live-wallpaper. All you need to do is select two images and let the animation do the rest. This is much more easier to use than the Weird Voronoi (Pro) with all the functions.

Here's some outputs:

(this one is the default, when you first start the live-wallpaper)






Here's the link and the QR code:

https://market.android.com/details?id=com.blogspot.widgg_research.twin

2011/06/23

Live-Wallpaper available on the Market

I finally managed to put a first version of my live-wallpaper on the market.

You can find it right here:

https://market.android.com/details?id=com.blogspot.widgg_research&feature=search_result


Post comment on this post to tell me what you think about it. It's a first version and there's a lot of work to do to create the professional version and also to improve this one.

For major problem, I will do my best to put a new version of the application on the Market as fast as possible.

The live-wallpaper is rough on the fragment shader that I created in OpenGL ES 2.0. So it's very important to control the execution of the application base on this. Fewer points and a lower FPS (frame per seconds) will give better results.

I'm also interested to know the performance of your Droid, particularly if they run on Honeycomb. So, I'd like you to post your device, version of Android, number of points and FPS that you used in your settings.

Here's some screenshots: