Showing posts with label cuda. Show all posts
Showing posts with label cuda. Show all posts

2012/04/23

New results

We submitted a paper to EGSR (Eurographics Symposium on Rendering), and still waiting to see if the paper is accepted or not.


In the mean time, here's a little result. We used a Perlin sum, to sum up the first four images, to create the last one. The output is very interesting.


Here's the octaves:





Here's the output (also used as the new backgroud for this blog):


Note that each octave is different, which is different to Perlin noises. But if we wanted, we could have used the exact approach described by Perlin.


In future post, I'll give more detail about the method used to create these textures. All images are tileable. Eventually, a GPU version of this framework should be implemented. Either as a fragment shader or on CUDA/OpenCL.

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/25

first pattern

So, yesterday I mentioned two steps that we need to work on to finish the hierarchy project. And one of them is to work on patterns or structures to show what is possible to do with that product.

Today, I managed to to a first structure, a flower. Very simple to do. Just needed some adjustment first, but I got that result in few minutes. So here it is:
Naturally, I just showed the final product. I had other images created before I managed to do the right effect that I wanted. I think that this is a nice preview of what that product can do.

Let me know what you think about that output!

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/08

merging voronoi

Here we are playing again with the Voronoi diagram (VD). We wanted to see what happen when sites are merged together (MVD, merged VD).

VD partitions the plane in cells where each of these cell represents the closest part of the plane to a particular site. So, if you have sites on a map of various fast food restaurants, the Voronoi diagram tells you which one is physically the closest to your location.

But imagine that we want to consider all restaurant from a particular chain as one entity. We want to know the influence or the domination of a particular chain.

The following images are in pair. The first one is the influence of a chain of restaurant and the second is the actual VD that everyone knows. Cells with the same color represents a chain of restaurant.





In the images, you can see some brighter points (particularly in the first two images), this is the actual location of the site (or restaurant for in our example).

And just like the VD is well known for its role in texture synthesis, we hope to find a way to use the MVD to create some interesting results.

As for the diagram itself, we don't really know what to do with it or how to interpret it. VD has a dual graph called the Delaunay Triangulation. But what would be the dual graph of MVD ? Where do we put the edges ? That's an open question.

2011/07/04

More texture synthesis

In this post, I present some new result that we really like. Again, it's a variation of the Voronoi diagram. You can observe the Voronoi cells interacting with each other. The colors help to see clearly the cells. And because of the few number of color, some cells might share the same color but are not related at all.

Here's some of the results:








This method, if it produces the result we're expecting, can be used to create texture by simply specifying some parameters or an artist can use a program with that method implemented to place some control points and control other parameters.

Again, all these images can be computed with CUDA because each pixel is unique.

2011/06/27

mosaic

Yesterday I mentioned using images as a source for the points and orientations. And I managed to do something.

First, the original image (a South Park version of myself, before I lose some weight):



And here's the various mosaic:







I used various effects to control the orientation in the cell. Plus I tried a random point selection, except for the first output.

Which one do you prefer ?

Naturally, to produce the output, I'm still using CUDA. I didn't used any data structure to optimize, so it can be computed a bit faster.

More textures

In my research, I'm still working on my textures. Here's some results I produced today that I really like.








Those effects might be implemented in a next version of my live-wallpaper. I haven't decided yet. For the first two images, I put the orientation of the points right on the plane. Plus I tried a new function to compute the distance. This one allows some distance pixels to actually have a distance of zero when it's perfectly aligned with another points.

Next, I will try to use images as a source of points and orientations. To see if with this method it's possible to create mosaic from an image. Creating mosaic with the normal Voronoi diagram is something well known in the literature. But with this method of oriented points that creates cells that are not convex polygons might allow us to do something very unique.

Let me know what you think of these images.

2011/06/21

Yin Yang Texture

Here's a post on texture.

Previously, we were using a method to control images with points and normals. Alone, a point and a normal split the plane in two, a positive and negative part. But combined with other points and normals, we can actually control curve shapes. To visualize it, we assign white to the positive part and black for the other.

The textures proposed here are made by first splitting the plane in two parts. The two parts must be symmetrical just like the Yin Yang symbol.

We then distribute points and normals inside one of the part. We then reflect the point into the second part, but not the normal.

The method create a contrast and a perfect symmetry. Here's some results:




I won't describe the method to render those images because it's very complex. Also, the process is very slow. Unlike the live-wallpaper I'm working on, or the previous images I showed, we cannot compute those in real-time.

Unfortunately, we haven't implement this with CUDA. With CUDA, it wouldn't be in real-time, but it would be much faster. Specially the per-pixel rendering part. Let me know what you think about these Yin-Yang images.