Julian Posted November 29, 2004 Posted November 29, 2004 This is an outgrowth of an idea I originally floated in this post on the SDK forum. My objective is to create a sphere of randomly distributed stars 10 km in radius, where each star is a one-patch object with a diameter randomly ranging from 7.5 to 30 m. I also want to be able to control the size of all stars simultaneously with a pose slider, to ensure that the stars will always be rendered at about one pixel regardless of the resolution of the render or the focal length of the camera. After Yves put me on the track of a bones-based solution, I first tried to implement this idea in which each star has two bones, one to position it randomly and one to scale it, but I had to scrap it. First of all, the program hung when I tried to go from 1024 stars to 2048. Second, I found that having to evaulate an expression with a Rand() function on every bone made the model load up very slowly in an action or choreography. What I'm planning to do now is a two-stage approach: first, I create the randomly distributed and scaled stars with expressions -- this time, using only one bone per star -- then I bake the position of the bones in place by opening it in an action window and exporting as a model. After that, I'm going to create the pose slider that will scale each bone uniformly. The procedure goes like this: I made a single circular patch consisting of two splines, 15 m in diameter and centered on (0, 0, 10000 m). The CPs are assigned to a bone called Radius1 starting at the origin with a length of 10000 m. I replicated this model by saving the file, importing the model into itself and repeating 11 times to give 2048 stars, with bones numbered from Radius1 to Radius2048. What I need to do next is to apply these expressions to each of the 2048 bones: Transform.Rotate.X = 360*(-0.5+Rand()) Transform.Rotate.Y = 360*(-0.5+Rand()) (The Rand() function returns values between 0 and 1, so this will orient the bones randomly in a range of values between -180 and 180 degrees.) Transform.Scale.X = 0.5+Rand() Transform.Scale.Y = ..|X (Scales each bone by X randomly between 50% and 150%, and sets the Y scale equal to the X scale.) I can generate the names of all the bones using a FOR loop, and I'm choosing to do this using JavaScript, because I can very quickly use a web browser to save the ouput to a text file, open the .mdl file in a text editor, and paste the relationship into the right place. The relationship container in the model file looks like this: [RELATION] Name=Relationship1 KeyDim=1 [OBJECTSHORTCUT] MatchName=Bones [ENDOBJECTSHORTCUT] [FileInfo] LastModifiedBy=Julian Fong [EndFileInfo] [ENDRELATION] ...and the code I want to insert goes in where the blank line is. The JavaScript that generates the code is an HTML file which is presented here in its entirety: <script language="JavaScript"> var string1 = "[EMPTYDRIVER]<br>" string1 += "MatchName=Transform<br>" string1 += "[EMPTYDRIVER]<br>" string1 += "MatchName=Rotate<br>" string1 += "[EXPRESSION]<br>" string1 += "Value=360*(-0.5+Rand())<br>" string1 += "MatchName=X<br>" string1 += "[ENDEXPRESSION]<br>" string1 += "[EXPRESSION]<br>" string1 += "Value=360*(-0.5+Rand())<br>" string1 += "MatchName=Y<br>" string1 += "[ENDEXPRESSION]<br>" string1 += "[ENDEMPTYDRIVER]<br>" string1 += "[EMPTYDRIVER]<br>" string1 += "MatchName=Scale<br>" string1 += "[EXPRESSION]<br>" string1 += "Value=0.5+Rand()<br>" string1 += "MatchName=X<br>" string1 += "[ENDEXPRESSION]<br>" string1 += "[EXPRESSION]<br>" string1 += "Value=..|X<br>" string1 += "MatchName=Y<br>" string1 += "[ENDEXPRESSION]<br>" string1 += "[ENDEMPTYDRIVER]<br>" string1 += "[ENDEMPTYDRIVER]<br>" string1 += "[ENDOBJECTSHORTCUT]<br>" for(var i = 1; i <= 2048; i++) { document.write("[OBJECTSHORTCUT]<br>") document.write("MatchName=Radius" + i + "<br>") document.write(string1) } </script> After generating all the code and pasting it in, my model file now has a size of 1.8 MB, but that's okay, because including the model in an action and saving it as a new model will cut the size down almost by half. Opening it in an action window produces this result: But here's where I run into something unexpected: the Rand() function isn't producing a uniform distribution of bones. This is what the action looks like in muscle mode, from a front view: and a top view: Clearly, there's a higher concentration of stars around the poles, and I don't want that. I'm not even sure why this is happening -- something to do with the way the X and Y rotations are combining to produce the orientation of the bones? So now, I'm looking for some advice on how I can fix this. Maybe I can modify the expressions used to orient the bones originally, but how? If I export the action as a model and delete the original relationship, the bones will have random rotations in their Bone Position properties, but they will no longer be controlled by the expression and I can move them around. However, rotating the bones by hand is impractical. I could try using another expression to isolate just the bones clustered around the poles and randomizing their orientation again. As I had done before, I tested this expression on a model that contained only one bone before I'm going to apply it to all 2048 bones of my working model. Given that the name of the model is StarSphere2 and the first bone is called Radius1, I can apply this expression to Radius1: Transform.Rotate.X = If(80<Abs(..|..|..|..|..|..|..|..|Objects|StarSphere2|Bones|Radius1.Bone Position.Rotate.X)<100,180*(-0.5+Rand())) In other words, if the absolute value of the original X-rotation of this bone is between 80 and 100 degrees (which takes care of both the "north pole" and "south pole" clusters), rotate it by X again a random value between -90 and 90 degrees. I have to try this out to see how it'll look, but one problem that I can see may arise is getting stars clustered in two latitudinal circles. Maybe it'll happen and maybe it won't. Does anyone have any better ideas? Quote
aaver Posted November 29, 2004 Posted November 29, 2004 Julian, The clustering you see is what you should expect. On a sphere, an arc length is shorter close to the poles than around the equator, but your algorithm places just as many bones at latitude 0 as it does at latitude 89. The solution is to have a non uniform random distribution for the latitude angle. It may be shown that this distribution should have a frequency function as f(Lat) = cos(Lat) This is an algorithm that might help you to solve your problem. It produces evenly random distributed points on a half sphere. N = 2048; for (int i=1, i < N, i++){ Lat = asin(rand()); // Latitude angle [0,pi/2). This is the "magic" line... Long = 2*pi*rand(); // Longitude angle [0,2*pi) X[i]= R*cos(Lat)*cos(Long); // X coordinate for the light source Y[i] = R*cos(Lat)*sin(Long); // Y coordinate for the light source Z[i] = R*sin(Lat); // Z coordinate for the light source } Quote
aaver Posted November 29, 2004 Posted November 29, 2004 After some more thought, I think your problem will be solved if you simply change your line Transform.Rotate.X = 360*(-0.5+Rand()) to Transform.Rotate.X = 90 + 180/Pi()*ASin(2*Rand() - 1) EDIT: I wasn't sure if A:M trig functions used radians or not. Now I think it's correct though... Quote
ypoissant Posted November 29, 2004 Posted November 29, 2004 Between the two solution suggested by Anders, I would prefer the first one as it would be more efficient to generate the vectors this way rather than rotating them. Another faster variation of first Anders example would be: N = 2048; for (int i=1, i < N, i++){ costheta = sqrt( Rand() ); sintheta = sqrt( 1.0 - costheta * costheta ); phi = Rand() * 2.0 * Pi(); X[i]= R*cos(phi)*sintheta; Y[i] = R*sin(phi)*sintheta; Z[i] = R*costheta; } Quote
aaver Posted November 29, 2004 Posted November 29, 2004 [...]Another faster variation of first Anders example would be:[...] Yes, you are correct Yves, but I think you got a typo in your code. What I think meant was: N = 2048; for (int i=0, i < N, i++){ costheta = Rand(); sintheta = sqrt( 1.0 - costheta * costheta ); phi = Rand() * 2.0 * Pi(); X[i]= R*cos(phi)*sintheta; Y[i] = R*sin(phi)*sintheta; Z[i] = R*costheta; } I think costheta must have a uniform distribution. Am I right? (Edit: I guess I am since otherwise there will be a dimension error) (I also corrected the loop index, but that was trivial) Quote
ypoissant Posted November 29, 2004 Posted November 29, 2004 Anders, I know I can count on you for that sort of thing You are right. the first Sqrt is wrong. And, I also missed something else. For a random distribution on the whole sphere (not only on half sphere) the costheta should be: costheta = 1.0 - 2.0 * Rand(); Quote
aaver Posted November 29, 2004 Posted November 29, 2004 costheta = 1.0 - 2.0 * Rand(); Oh, all those details! At last, I think we have a working algorithm, though Quote
Julian Posted November 30, 2004 Author Posted November 30, 2004 Anders, Yves, thanks for the help. I can retool the model so that the arrangement of bones depends on translation instead of rotation, which would involve using a short bone for each star with an Aim At constraint to a null at the origin. The necessity of reusing variables means I would be better off computing the coordinates within the script instead letting A:M do it with expressions. In the SDK forum, I asked about generating a normal distribution with the Rand() function, and the thought occurs to me that if I used (Rand() + Rand()) /2, I would be able to produce values close to 0.5 more often than 0 or 1, a bit like rolling two dice. Anyway, I originally wanted to use an expression like that to control the size variablilty among the stars, but I probably won't be doing that now. For future reference, the problem of picking random points on a sphere is also discussed in this page on Wolfram MathWorld. Quote
Julian Posted December 9, 2004 Author Posted December 9, 2004 Success! I decided to do the arrangment of stars in an action instead of a pose, because a translate driver in a pose always has two keyframes, one for the pose turned off and one for it turned on, whereas in an action I only need to use one keyframe. It keeps the file size smaller and reduces processing time. I created a model called StarSphere_1-repl2048.mdl which contains 2048 copies of a 15 meter star centered on the origin, each with a 15 meter long bone (Bone1 to Bone2048) starting at the origin. I also have a null called Origin at the origin. The HTML script for generating the action file looks like this: <pre> [ACTIONFILE] ProductVersion=11.1 [POSTEFFECTS] [ENDPOSTEFFECTS] [IMAGES] [ENDIMAGES] [SOUNDS] [ENDSOUNDS] [MATERIALS] [ENDMATERIALS] [POSTEFFECTS] [ENDPOSTEFFECTS] [OBJECTS] [ENDOBJECTS] [ACTIONS] [ACTION] StrideStartPosition=0 0 0 StrideEndPosition=0 0 0 DefaultModel=StarSphere_1-repl2048 PlayRange=0 0 [OBJECTSHORTCUT] MatchName=Bones <script> for (var i=1; i<=2048; i++) { with (Math) { costheta = 1.0 - 2.0 * random() sintheta = sqrt( 1.0 - costheta * costheta ) phi = random() * 2.0 * PI X = round( 1000000 * cos(phi) * sintheta ) Y = round( 1000000 * sin(phi) * sintheta ) Z = round( 1000000 * costheta ) } document.write("[OBJECTSHORTCUT]\n") document.write("MatchName=Bone" + i + "\n") document.write("[EMPTYDRIVER]\n") document.write("MatchName=Transform\n") document.write("[EMPTYDRIVER]\n") document.write("MatchName=Scale\n") document.write("[EXPRESSION]\n") document.write("Value=0.5+Rand()\n") document.write("Name=X\n") document.write("MatchName=X\n") document.write("[ENDEXPRESSION]\n") document.write("[EXPRESSION]\n") document.write("Value=..|X\n") document.write("Name=Y\n") document.write("MatchName=Y\n") document.write("[ENDEXPRESSION]\n") document.write("[ENDEMPTYDRIVER]\n") document.write("[EMPTYDRIVER]\n") document.write("MatchName=Translate\n") document.write("[TRANSFDRIVER]\n") document.write("Name=X\n") document.write("MatchName=X\n") document.write("[SPLINE]\n") document.write("CPs=1\n") document.write("1\n") document.write("0 " + X + "\n") document.write("[ENDSPLINE]\n") document.write("[ENDTRANSFDRIVER]\n") document.write("[TRANSFDRIVER]\n") document.write("Name=Y\n") document.write("MatchName=Y\n") document.write("[SPLINE]\n") document.write("CPs=1\n") document.write("1\n") document.write("0 " + Y + "\n") document.write("[ENDSPLINE]\n") document.write("[ENDTRANSFDRIVER]\n") document.write("[TRANSFDRIVER]\n") document.write("Name=Z\n") document.write("MatchName=Z\n") document.write("[SPLINE]\n") document.write("CPs=1\n") document.write("1\n") document.write("0 " + Z + "\n") document.write("[ENDSPLINE]\n") document.write("[ENDTRANSFDRIVER]\n") document.write("[ENDEMPTYDRIVER]\n") document.write("[ENDEMPTYDRIVER]\n") document.write("[AIMATCONSTRAINT]\n") document.write("BoneTarget=..|Origin\n") document.write("[ENDAIMATCONSTRAINT]\n") document.write("[ENDOBJECTSHORTCUT]\n") } </script>[ENDOBJECTSHORTCUT] [ENDACTION] [ENDACTIONS] [CHOREOGRAPHIES] [ENDCHOREOGRAPHIES] [ENDACTIONFILE] </pre> And here is the distribution of stars it generates, from a top view: The next step will be to generate the pose allowing me to scale each bone. Quote
Julian Posted December 13, 2004 Author Posted December 13, 2004 Well, it's pretty much done, but it's not very practical to use. Sure, it renders really fast, but on my 1.5 GHz Mac it takes nearly six minutes to load up the project. Basically, this is the point of the whole exercise: Focal length 35 mm, 320x240 resolution, star size 20 m: Focal length 35 mm, 640x480 resolution, star size 12 m: Focal length 35 mm, 1024x768 resolution, star size 8 m: Focal length 100 mm, 640x480 resolution, star size 5 m: What I'm probably going to end up doing is to start with this sphere of variable-size stars that I've got, and by exporting actions to models, create different versions where the stars are fixed at particular sizes, and delete all the bones from each of these versions to make them load more efficiently. Quote
spikerthree Posted December 14, 2004 Posted December 14, 2004 Julian, Yves, aaver, This looks like it is coming along quite well, it seems promising and I'm hoping you'll share it with the rest of us This site: http://www.ap3d.com/betterspace/ Has a pretty decent starfied, it was done with Lightwave, but maybe there are somethings that apply (code is way beyond me) My question is how does it look with motion blur. I have a tough time getting a good look with stars whenever I have the camera moving i.e. spaceship flyby. I hope all goes well. Quote
Julian Posted December 14, 2004 Author Posted December 14, 2004 Thank you for your comment! When no one else was replying to this topic, I thought nobody was interested. I'd be willing to make this material available to download, but I'd have to document how to use the star sphere, because it's a little tricky. I forgot to mention that I applied an action to the original sphere of 2048 stars that created 15 duplicates of it as action objects, for a total of 32768 stars. These duplicates all have different rotations and are scaled -100% on 0, 1, 2, or all 3 axes. I'll try to render a test animation demonstrating motion blur soon. I'm also going to produce the boneless fixed-size variants, and before I'm done with the whole project, I want to investigate the possibility of using an expression to automate changing the size of the stars based on the focal length and output resolution of the camera. Quote
Zaryin Posted December 14, 2004 Posted December 14, 2004 I've been following this thread, but didn't have anything to say about the technical aspect so left it alone. I still don't reall understand the advantage of this? I don't do animation very much so would like to know if it's something to with that. Quote
Julian Posted December 15, 2004 Author Posted December 15, 2004 I've been following this thread, but didn't have anything to say about the technical aspect so left it alone. I still don't reall understand the advantage of this? I don't do animation very much so would like to know if it's something to with that. Okay, the advantage is this. Let's say we don't scale the stars, and we start off with the rendering I made in which the stars are the right size. 35 mm focal length, 640x480 resolution, star size 12 m: If we leave the stars at 12 meters, then when the frame is rendered at a lower resolution, the stars become almost too small to see. 35 mm focal length, 320x240 resolution, star size 12 m: And if we zoom the camera in, the stars become huge -- 100 mm focal length, 640x480 resolution, star size 12 m: This is what I'm trying to avoid. I want to keep the stars at just the right size so that they occupy only one pixel on the screen and don't lose brightness. Quote
Julian Posted December 15, 2004 Author Posted December 15, 2004 Here's an animation test where I'm trying to focus on motion blur. In case you're wondering, the TIE fighter is a 3DS prop that I downloaded from scifi3d.theforce.net. With the default A-buffer antialiasing, the motion blur is confined to a narrow band of stars in the middle of the picture. This is something I've observed on previous versions of A:M, and I don't know why it happens. Is there something that the Hash team can do to improve the default motion blur routines, or do we have to use multipass if we want better results? With 3x3 multipass, all the stars are motion blurred, but they look a little too aliased to me: So I went with 4x4 multipass, and it does look good, but these three seconds of footage took me nearly 5 hours to render. This is one frame: And here's the full scene: (video removed) Right at the end of the scene, when the camera is moving slowly, you can see the stars shimmering, and I'll have to try to find a way around that. Maybe I'll have to make the stars bigger, or increase the number of passes. What really seems to be holding up the rendering time is the TIE fighter itself, especially in the middle when it's close to the screen. I could try to render the TIE fighter in A-buffer with no background and an alpha channel, render just the starfield with multipass, and then composite them together. Quote
spikerthree Posted December 16, 2004 Posted December 16, 2004 I totally agree with you on the motion blur thing. I'm hoping that your star rig will help those of us who do a bunch of space scenes I tend to get areas of the image that are motion-blurred and then areas that aren't, it makes really hard to get a good fly-by. Quote
Zaryin Posted December 17, 2004 Posted December 17, 2004 I see now how that would help. For a guy who does only images this wouldn't be that important, but I can see how this would be excellent for animation. Great work. Quote
Julian Posted December 18, 2004 Author Posted December 18, 2004 I've had no luck with using an expression to automate the star size. The size of the stars is controlled by a pose slider that I called "Median star size in meters". I set the keyframes up so that the percentage of the pose reflects the original size of the stars -- i.e., the stars were 15 m in diameter before I randomized the size, and the default position of the slider is 15%. Right now, the slider goes between 5 m and 30 m, but I think I'll reset the minimum down to 0 since I do actually have keyframes at 0. Anyway, in the choregraphy I tried to set the position of the pose slider equal to this expression: 0.9*10000*Tan((2*ATan(17.5/..|..|..|Shortcut to Camera1.Focal Length))/Max(..|..|..|Shortcut to Camera1.Output Options.Resolution.Width, ..|..|..|Shortcut to Camera1.Output Options.Resolution.Height)) ...but trying to apply the expression causes A:M to crash. (The 0.9 at the beginning is a fudge factor to make the stars a little dimmer, and I left it there instead of saying "9000*..." to make it easier to make adjustments.) I'm going to give up on trying to automate the process, and I'll just leave it up to the user to keyframe the pose slider at the same time that the camera's focal length changes. Quote
rumplestilskin Posted December 19, 2004 Posted December 19, 2004 *This thread made me feel stupid and lonely* Quote
Julian Posted December 20, 2004 Author Posted December 20, 2004 Aw, don't feel bad about it. I feel pretty stupid and lonely myself for getting sidetracked for a month working on something that may be too complicated for most people to use. I made a little mistake on the math in the expression in my previous post. The 2 is in the wrong place, but considering how much smaller the stars are compared to the distance to them, the error only affects the sixth decimal place and beyond, so it has no real effect. Attached is a proof that shows how to determine how big the stars need to be. I'm probably going to include this graphic in the documentation when I release this project, because it's crucial to the understanding of how the star sphere works. Assume that the camera is located at the origin, inside a star sphere of radius R meters. The camera's focal length is f millimeters, and it is set to render an image whose largest dimension is W pixels. We want to solve for the diameter s of a star which will occupy one pixel in the render. Let angle A be the angle of the camera's field of view, and angle C be the angle subtended by the star. Quote
Julian Posted December 20, 2004 Author Posted December 20, 2004 The thing that needs to be kept in mind is that the formula I derived: s = 2R tan [atan (17.5 / f) / W] shouldn't be used as an exact measure of the size you want to set the stars at. For instance, plugging in the values R = 10000 m, f = 35 mm and W = 640 gives me the value s = 14.49 meters. However, because I made the star size vary randomly between 50% and 150% of the median, it would actually look better if you set the star size to 12 meters instead, which is what I did in my previous examples. Quote
spikerthree Posted December 21, 2004 Posted December 21, 2004 I was just thinking of how useful this will be. Being able to maintain the same star size is crucial to having multiple shots in a scene flow together seamlessly. I might be getting too far ahead, but being able to control the brightness of the stars would be cool too. Quote
Julian Posted December 23, 2004 Author Posted December 23, 2004 I've done one more animation test in which the camera zooms in and the stars shrink at the same rate. To try to save time, I rendered the stars with multipass and the TIE fighter with A-buffer antialiasing, and composited them together in After Effects. Here's one frame as the camera is zooming and panning simultaneously: (video removed) Immediately after this post, I'm going to make the star sphere model available to download in the Showcase forum. Quote
Julian Posted December 23, 2004 Author Posted December 23, 2004 You can find the files here in the Showcase forum. Quote
martin Posted December 23, 2004 Posted December 23, 2004 Wow, Julian; That star sphere is pretty cool. Thanks for making it available to the whole community. Martin Hash Quote
seven Posted July 14, 2005 Posted July 14, 2005 I had a try: http://www.hash.com/forums/index.php?showtopic=15940&st=15 The stars are too small I think. Where to alter the size? I cannot find the expression you are talking about. And there is the script hiding? Thanks for a little help - a little summary. Note: I did not say WINK it - but you are free to do it - telling the steps in doing it. Quote
Admin Rodney Posted November 9, 2012 Admin Posted November 9, 2012 Bumping this up as not only the Star Sphere is cool but so is the coding (javascript) behind it. We were previously talking about how much we love the A:M file formats here. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.