• Create Account

# lwm

Member Since 29 Sep 2011
Offline Last Active Today, 01:33 PM

### #5071036GPU particles

Posted by on Today, 12:51 AM

A few day ago, I created a little GPU particle sample for SharpDX. The buffers start off completely empty. To spawn new particles, I copy them to a third vertex buffer. After the pass to update the particles from last frame, I just "draw" the third buffer to append the new particles to the buffer for the current frame as well.

Any properties that are "sufficiently random" like the particle's color or various flags, I put directly into the vertex. I didn't include this in the sample to avoid bloating it, but to handle properties that a lot of particles share, every particle also has a type ID that indexes into an array of particle types in the geometry shader.

Posted by on 02 June 2013 - 05:26 AM

Does that means that the project is useless and I must look for other technique such as "deferred rendering" and "light pre pass"? If yes, any deferred rendering shader out there?

It's not useless. You can use normal mapping with almost any lighting technique you want. I would advise against using the deferred techniques for now. They are a lot harder to implement and bring their own problems with them (transparent objects for example). You can't just throw a "deferred rendering shader" on there and expect it to work.

Choosing a lighting technique is an important decision and will fundamentally change the way your rendering pipeline works and performs.

- Multi-pass: Render the object multiple times and apply one light source with each pass.

- "Uber-shader": Multiple lights in one pass plus anything else you might need and enable/disable the parts you need.

- Combination of the above

- Deferred: Render scene to a G-Buffer and calculate lighting independently

What does your typical scene look like? How many lights are we talking? How large are they? How many objects do they affect?

### #5060231SlimDX Sound Problem (I am very desperate ;( )

Posted by on 08 May 2013 - 02:15 AM

I dont know why but the Volume can only be 0 or a negative value until -10000, where 0 = Volume 100 and -10000 = Volume 0,
just stupid, i know but it's so xD

That's because the volume property is really the attenuation, in hundredths of a decibel (dB).

0 -> 0 dB -> 100%

-300 -> -3 dB -> 50%

-600 -> -6 dB -> 25%

-10000 -> 100 dB -> 10^-8 %

### #5042642How to analyze run time complexity in code in a trivial way

Posted by on 13 March 2013 - 03:27 AM

There is really only one way to do it:

First, analyze your code piece by piece and write down the complexity using Big-O notation.

Most loops are easy to analyze:

for(i = 0; i < n; i++) {
var++; // O(1)
} // O(n) * O(1)

for(i = 0; i < 2 * n; i++) {
f(); // f \in O(log(x))
} // O(2*n) * O(log(x))

for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
for(k = n; k > 1; k /= 2) {
var++; // O(1)
} // O(log(n))
} // O(n) * O(log(n))
} // O(n) * O(n) * O(log(n))


But there are also trickier cases:

for(i = 1; i < n; i *= 2) {
g(i); // g in O(i)
}


Here you can't simply multiply the complexities because g depends on i.

The complexity of the loop's body doubles with every iteration: 1, 2, 4, 8, 16, ... and there are log(n) elements in the series. This is the log(n)-th partial sum of a geometric series with a common ratio of 2.

When using recursion, things get even weirder. For most divide and conquer algorithms, you can use the master theorem.

Then, simplify using the rules of the Big-O notation:

c*O(f) = O(c*f) = O(f)

O(f)*O(g) = O(f*g)

O(O(f)) = O(f)

O(f) + c = O(f+c) = O(f)

O(f) + O(f) = O(f)

O(f+g) = O(max(f,g))

So, yeah. I don't think there is a trivial way.

I have a question about this too: are we assuming log of some input to the base 10 or is the base of the log arbitrary?

The base of the logarithm doesn't matter when analyzing the asymptotic complexity, because it's just a constant factor that can be ignored.

O(log_2(n)) = O(log(n) / log(2)) = O(log(n) * 1.4426...) = O(log(n))

### #5037654simple structs initialization optimization

Posted by on 28 February 2013 - 10:22 AM

As far as I can see using MonoDevelop, the IL instantiates a new object. The question is whether the JIT optimizes this.

"newing" a struct should not instantiate a new object.

var x = new MyClass(1.5f);


will turn into

ldc.r4 1.5 // push 1.5f onto the evaluation stack
newobj instance void MyClass::.ctor(float32) // allocate object, call .ctor on it with value from stack and push reference to new object
stloc.0 // store reference in x (x is first local variable in this case)


whereas

var x = new MyStruct(1.5f);


will turn into

ldloca.s x // push reference to x
ldc.r4 1.5 // push 1.5f
call instance void MyStruct::.ctor(float32)


The struct's constructor is just a "normal" method. This call will almost certainly be inlined. Unless you start boxing the value, use it in a lambda expression or things like that, there should be no need for any heap allocations.

### #5037572simple structs initialization optimization

Posted by on 28 February 2013 - 06:25 AM

Unless your struct's constructor is very long or complex (which should never be the case for structs anyway), I would trust the JIT to inline and optimize it.

For the radian struct you could define an implicit conversion "operator" to make the assignment more straight forward.

### #5037566Grass Blocks ( anyway to make them feel more dynamic? )

Posted by on 28 February 2013 - 06:07 AM

Just to make sure I understand: You are rendering the grass completely "forward" and it doesn't appear in the GBuffer anywhere before that?

I can think of two things off the top of my head:

- Simply light the grass "forward". But, as you said, this would mean that you're coupling scene geometry with light complexity again.

- "Cheat" by using the values in the light buffer that are along the bottom edge of the grass quad. This is probably going to be very computationally cheap but will make the quads have constant lighting along the vertical axis. It will also make any grass automatically translucent.

### #4997902C#, which tools/technology to use?

Posted by on 06 November 2012 - 12:49 AM

I was in the same situation a few weeks ago and decided to go with SharpDX. I also quite like the new toolkit. It's slighty more low-level than XNA was (although there's little difference for SpriteBatch-centric use), but it doesn't restrict the amount of DX10/11 features you can use.

### #4981022C# List<T>.Find

Posted by on 17 September 2012 - 03:07 PM

I looked up how to use LINQ, and the following does work :

That method will always return default(T).

But as an aside, if you're going to look up an object by its id, why not use a dictionary for the collection of EngineObjects as well?

public T GetObject<T>(int objectId) where T : EngineObject
{
Dictionary<int, EngineObject> objects;
if (m_objectInstances.TryGetValue(typeof(T), out objects))
return (T)objects[objectId];
else
return default(T);
}
private Dictionary<Type, Dictionary<int, EngineObject>> m_objectInstances;


### #4974168[XNA] Texture2D Crop

Posted by on 28 August 2012 - 11:01 AM

Ha, I knew I shouldn't have used the Rectangle. I fixed the code in my previous post.

### #4974124[XNA] Texture2D Crop

Posted by on 28 August 2012 - 08:33 AM

You can use Texture2D.GetData to get a Color[] representation of the texture. Are you generating these images on the GPU? Because if the images are created on the CPU, you don't have to get the data in the first place.

Texture2D Crop(Color[] data, int width, int height, Color excess)
{
int x1 = width, x2 = 0, y1 = height, y2 = 0;
for (int i = 0; i < width * height; i++)
{
if (data[i] != excess)
{
int y = i / width;
int x = i % width;
x1 = Math.Min(x, x1);
x2 = Math.Max(x, x2);
y1 = Math.Min(y, y1);
y2 = Math.Max(y, y2);
}
}
Rectangle cropped = new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
Color[] newData = new Color[cropped.Width * cropped.Height];
for (int y = 0; y < cropped.Height; y++)
{
for (int x = 0; x < cropped.Width; x++)
{
int newIndex = y * cropped.Width + x;
int oldIndex = (y + cropped.Y) * width + (x + cropped.X);
newData[newIndex] = data[oldIndex];
}
}
Texture2D texture = new Texture2D(this.GraphicsDevice, cropped.Width, cropped.Height);
texture.SetData(newData);
return texture;
}


### #4974031Generic method with objects

Posted by on 28 August 2012 - 02:54 AM

The most straight-forward thing would probably be to make all classes that you want to initialize that way implement a common interface, like "IHasPosition".
Or, if you want to make the your PatternAst class even more generic, you can provide a setter action to the method.

public interface IHasPosition
{
Vector2 Position { get; set; }
}
public class Asteroid : IHasPosition
{
public Vector2 Position { get; set; }
}
public class Asteroid2
{
public Vector2 Position { get; set; }
}
public static class PatternAst
{
static void Main(string[] args)
{
// Use the fact, that Asteroid implements IHasPosition
var list1 = CreateCircle<Asteroid>(10, new Vector2(0, 0), 100);
// Asteroid2 does not implement IHasPosition, use second method with setter action
var list2 = CreateCircle<Asteroid2>(10, new Vector2(0, 0), 100, (obj, pos) => { obj.Position = pos; });
}
private static Vector2 PositionInCircle(int i, int amount, Vector2 center, float radius)
{
float a = ((float)i / (float)amount) * MathHelper.TwoPi;
float x = (float)Math.Sin(a);
float y = (float)Math.Cos(a);
return center + new Vector2(x, y) * radius;
}
public static List<T> CreateCircle<T>(int amount, Vector2 center, float radius) where T : class, IHasPosition, new()
{
var list = CreateMultipleObjects<T>(amount);
for (int i = 0; i < list.Count; i++)
{
list[i].Position = PositionInCircle(i, list.Count, center, radius);
}
return list;
}
public static List<T> CreateCircle<T>(int amount, Vector2 center, float radius, Action<T, Vector2> positionSetter) where T : class, new()
{
var list = CreateMultipleObjects<T>(amount);
for (int i = 0; i < list.Count; i++)
{
var pos = PositionInCircle(i, list.Count, center, radius);
positionSetter(list[i], pos);
}
return list;
}
public static List<T> CreateMultipleObjects<T>(int amount) where T : class, new()
{
List<T> temp = new List<T>();
for (int i = 0; i < amount; i++)
{
T obj = new T();
}
return temp;
}
}


### #4974018Generic method with objects

Posted by on 28 August 2012 - 02:12 AM

Thanks a hell of a bunch!!! Unfortunately I can only upvote once...

Well, that did the trick now I need to review all that and understand how and why it works. I have never heard of Action and delegates (still discovering C#).

Also,I was scared you led me somewhere lost as all my object were on the same spot at first but then I realized you just assign the same position in initCircle (I guess you forgot to use i).

Again thanks for that.

I used the i in initCircle to calculate a, but you probably have to scale up the vector in order to see the circle.
obj.position = new Vector2(x, y) * 100;

should produce a circle with radius 100.

### #4974004Generic method with objects

Posted by on 28 August 2012 - 01:24 AM

Just to make sure I understood correctly: You want the method to instantiate multiple objects, initialize them all differently and put them in a list?

Assuming that T is a reference type, the first method you provided receives a reference to an object of type T and adds the same reference to the list 10 times. Also, in modern C#, there is really no reason to use the non-generic versions of the built-in collections.

static void Main(string[] args)
{
Action<Asteroid, int, int> initCircle = (obj, i, amount) => {
float a = ((float)i / (float)amount) * MathHelper.TwoPi;
float x = (float)Math.Sin(a);
float y = (float)Math.Cos(a);
obj.position = new Vector2(x, y);
};
var list = CreateMultipleObjects<Asteroid>(10, initCircle);
}
public static List<T> CreateMultipleObjects<T>(int amount, Action<T, int, int> initialize) where T : class, new()
{
List<T> temp = new List<T>();
for (int i = 0; i < amount; i++)
{
T obj = new T();
initialize(obj, i, amount);
}
return temp;
}


### #4970867List Box Issues

Posted by on 18 August 2012 - 11:19 AM

The error occurs in this line in the "Form1.Designer.cs" file:
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);


I'm guessing you registered a handler for the SelectedIndexChanged event in the designer at one point but deleted the automatically-generated method in the "Form1.cs" file. The code-behind file generated by the designer still tries to use the missing method however. You can simply double-click on the error message and delete the line to get rid of the error.

PARTNERS