Hi Polycount! Long time lurker here, first time posting. I finally landed my first job in the game industry about 8 months ago(!!!) as a 3D artist, it's been awesome and I really owe this community a big thanks for all the wisdom, laughs and inspiration it has given me over the years. So, thank you Polycounters!
But I've now been tasked with learning the art of shaders, which I've always wanted to do, but I think I may be in need of some guidance from you guys...
So I'm trying to achieve the look of a "Point Cloud" much like the following images:
The Specifics:
I'm trying to achieve this on Shader Model 2.0, and
without using the actual geometry verts (the geometry is very low poly, mostly interior walls). Ideally there would be a greater number of points along edges to give the player a fairly accurate representation of the room depth/shape.
On top of all of this, I'm hoping to get this working on iOS. I know this is a really tall order but I'm determined to make this work if it can be done. (Or get as close as possible to the desired effect)
Initially I thought the easiest/cheapest way to go about this was a rim lighting shader that has an alpha channel for the rim to create the illusion of points. (I then planned to distribute points (2D texture) evenly along the rest of the surface on a second pass) However, this did not give me even close to the desired effect, and I'm a bit lost as to what I should try next.
I should mention I'm working in Unity, using the Cg/Shaderlab language. I'm not necessarily looking for actual code or anything (although that is welcome) but more of your guys' opinion on how you would go about achieving such an effect.
Any ideas?
Replies
If you have normal maps, use them to shift the UVs around to generate the impression of bunching in seams/etc.
Hope it makes some sense?
Also, pending on engine, you should also be able to get the depth distance, to make things up close brighter, and those further away darker, although at 2.0 level, I'm not sure how much math you can push before falling off.
Here you go, this works:
That's a pixel shader, make sure to feed in a proper worldposition ( = mul(In.position, WorldMatrix) )
scale determines the spacing of grid points, dotsize is the size of dots. That last one is really dependant on distance, as I expected it becomes a jittery mess easily...
edit: you can use UV-space as well, instead of world space. It doesn't look great on curved meshes, since some pixels can fall between the grid. Disadvantage of UV space is your UV density will cause scaling to be all over the place...
IIRC, this is how it would be;
Length = Square Root (X^2 + Y^2 + Z^2)
Correct me if I'm wrong.
Either way, thanks for the math, looks awesome.
Need to pass in the world normal obviously. It's still a bit sloppy where for curved objects the scale and point size isn't uniform, that just comes down to using something more elegant than just the vector length.
Edit: here's the FX: https://dl.dropbox.com/u/12093849/dump/pointcloud.fx
Xoliul, I'm incredibly grateful for your help with achieving this result, and even going as far as improving it and sharing your work. Besides what I've learned in the past 2 weeks from tutorials and experimentation I'm brand new to this so I really appreciate your help.
That being said, I have loaded the .fx file into Max and started playing around with it. It's very very close to effect I'm looking for! At this time I'm attempting to get this working in Unity and then I'm planning on trying to control the size (and possibly color) of the dots by screen distance. Our level designer has some experience with shaders so I'm hoping he'll be able to help with this. Regardless, this is a great start and it's looking awesome. Thank you!
One more question; do you guys have any suggestions for further reading/learning shaders? I've been drudging through the Cg Tutorial provided by nVidia, but it has been a fairly steep learning curve for an artist with zero C/C++/C# experience. Slowly but surely I'm getting my head wrapped around it, but if there's an easier-for-newbs solution that anyone has experience with I'd love to hear about it.
Thanks again!
I had some fun converting this to a shader you can use in Unity3D. One strange issue is that the dots aren't dots but quarter circles. I'm not as smart as Xoliul so maybe he knows what's going on.
Preview:
Download package with shader and material: Download
Would be fun to expand on this.
should give you points,
fmod basically chops values into segments each of the length [0,scale], the grid coordinates. Think of tiles, every tile has a local x,y axis. points within a tile go from (0,0) in one corner (scale,scale) to the other diagonal corner.
The length operation done gives you distance from origin 0,0. Because every tile has its origin in one corner, and every tile starts "freshly" you only see one quadrant.
With the step function at the end you get 1 or 0 depending if length (distance to origin) is smaller than the threshold provided (dotsize).
The code above basically ensures the origin is at center of the tile (half the tile size), therefore should give you all quadrants in the coordinate system of each tile = circles.
Depending on the normal one "tile wall" is chosen (facing x,y or z).
I tried CrazyButcher's edit and it's not working 100%, it needs an extra abs() thrown in, so the correct code for dots would be :
This is fun
Oh and Jerry, cool to see you here again. Nice job converting! How much work is that for Unity ? I'm not familiar with their shader system/language.
Converting to Unity wasn't that bad, it can have blocks of CG code inside the shader files so it's pretty straightforward. I just had to look up how to get the worldnormal and worldpos and added the parameters for the inspector etc.
Jerry, I just realized I never replied to this so I wanted to make sure you knew how much I appreciated you helping me out with this. Your code conversion has been a great help in understanding the differences in Cg code, thank you for taking the time to do this.
I've got quite a bit of coding/scripting experience, but nothing directly in Shaders like this.
I've added a color variable in the shader, which is showing up in the Unity editor now, but I can't figure out where white is getting specified, and how you might alter that.
I'm assuming I'd have to do something before returning the function in the last couple lines, but Float 4 is a positional call, from what I can tell?
float4 ret = float4(1, result);
Any help appreciated! :-)
I guess because its just white (1) times the RGB values of whatever you set in the Editor.
ret = ret*_Color; return ret;