Code archives/3D Graphics - Effects/Milkyway Panorama

This code has been declared by its author to be Public Domain code.

Download source code

Milkyway Panorama by Krischan2010
My God - it's full of stars! This include creates a nice lowpoly milkyway background with a 360° panorama emission nebula, fixed stars and background stars combined. It uses a splitted texture where the upper part represents the panorama from 0-180° and the lower part from 180-360° put on an open cylinder object.

Screenshot


Here is a demo how to use, just save the code entry as "milkyway.bb" and run this, you can switch between two different milkyways using the LMB and fly around with the arrow keys:



Media files:

nebula.jpg


star.png


stars.png
Const StarSingleTexture$="star.png"		; single star Texture
Const StarFieldsTexture$="stars.png"	; background starfield texture
Const FogTexture$="nebula.jpg"			; 360° split panorama nebula texture

Const StarTexScale#=1.5					; texture scaling of background stars
Const PanoSegments%=32					; number of panorama segments (should be at least 8)

; -----------------------------------------------------------------------------
; Initialize
; -----------------------------------------------------------------------------
Function InitMilkyway(Stars%,Dist#,MinAngle#,MaxAngle#,Scale,R1%=0,G1%=0,B1%=0,A1#=0.0,R2%=0,G2%=0,B2%=0,A2#=0.0,R3%=0,G3%=0,B3%=0,A3#=0.0)
	
	Local MilkyWay%,StarBox%,FogPanorama%,StarSphere%
	Local StarTex%,StarsTex%,FogTex%
	
	MilkyWay=CreatePivot()
	
	; load textures
	StarTex=LoadTexture(StarSingleTexture,2)
	StarsTex=LoadTexture(StarFieldsTexture,2)
	FogTex=LoadTexture(FogTexture,16+32)
	ScaleTexture StarsTex,StarTexScale,StarTexScale
	
	; create stars
	StarBox=InitStarBox(Scale,StarsTex,1,0)
	FogPanorama=InitPanorama(FogTex,Scale,Scale*0.8,PanoSegments,1+2+32,R1,G1,B1,A1,R2,G2,B2,A2,R3,G3,B3,A3)
	StarSphere=InitStarSphere(StarTex,Stars,0.5*(Scale/100.0),0.75*(Scale/50.0),0.5,Dist,MinAngle,MaxAngle,Scale,1)
	
	EntityParent StarBox,MilkyWay
	EntityParent FogPanorama,MilkyWay
	EntityParent StarSphere,MilkyWay
	
	; reorder
	EntityOrder StarBox,3
	EntityOrder FogPanorama,2
	EntityOrder StarSphere,1
	
	; blending
	TextureBlend FogTex,5
	EntityBlend FogPanorama,3
	EntityBlend StarSphere,3
	;EntityBlend StarBox,3
	
	Return MilkyWay
	
End Function


; -----------------------------------------------------------------------------
; create milkyway nebula panorama
; -----------------------------------------------------------------------------
Function InitPanorama(texture%,radius#,h#,segmente,fx%=0,r1%=255,g1%=255,b1%=255,a1#=1.0,r2%=255,g2%=255,b2%=255,a2#=1.0,r3%=255,g3%=255,b3%=255,a3#=1.0)
	
	Local ang1#,ang2#,inc#,x1#,z1#,x2#,z2#
	Local uu1#,uu2#,uv1#,uv2#,uv3#
	Local v0%,v1%,v2%,v3%,v4%,v5%
	
	Local mesh=CreateMesh()
	Local surf=CreateSurface(mesh)
	
	inc=360.0/segmente
	
	ang1=0
	
	While ang1<360
		
		ang2=(ang1+inc) Mod 360
		
		x1=radius*Cos(ang1)
		z1=radius*Sin(ang1)
		x2=radius*Cos(ang2)
		z2=radius*Sin(ang2)
		
		If ang1<180 Then
			
			; use upper texture UV coordinates
			uu1=1.0-(ang1/180.0)
			uu2=1.0-(ang1+inc)/180.0
			uv1=0.50
			uv2=0.25
			uv3=0.00
			
		Else
			
			; use lower texture UV coordinates
			uu1=1-(((ang1/180.0))-1)
			uu2=1-(((ang1+inc)/180.0)-1)
			uv1=1.0
			uv2=0.75
			uv3=0.5
			
		EndIf
		
		v0=AddVertex(surf,x1,-h,z1,uu1,uv1) : VertexColor surf,v0,r1,g1,b1,a1
		v1=AddVertex(surf,x2,-h,z2,uu2,uv1) : VertexColor surf,v1,r1,g1,b1,a1
		v2=AddVertex(surf,x1, 0,z1,uu1,uv2) : VertexColor surf,v2,r2,g2,b2,a2
		v3=AddVertex(surf,x2, 0,z2,uu2,uv2) : VertexColor surf,v3,r2,g2,b2,a2
		v4=AddVertex(surf,x1, h,z1,uu1,uv3) : VertexColor surf,v4,r3,g3,b3,a3
		v5=AddVertex(surf,x2, h,z2,uu2,uv3) : VertexColor surf,v5,r3,g3,b3,a3
		
		AddTriangle surf,v0,v1,v3
		AddTriangle surf,v3,v2,v0
		AddTriangle surf,v2,v5,v4
		AddTriangle surf,v5,v2,v3
		
		ang1=ang1+inc
		
	Wend
	
	EntityFX mesh,fx
	
	EntityTexture mesh,texture
	
	Return mesh
	
End Function


; -----------------------------------------------------------------------------
; create starsphere
; -----------------------------------------------------------------------------
Function InitStarSphere(texture%,stars%,min#,max#,fix#,centered#,centermin#,centermax#,range#,scale#=1.0)
	
	Local star%,mesh%,surf%
	Local i%,size#,a#
	Local r%,g%,b%
	Local col#,maxy#
	
	star=CreateStarQuad()
	
	mesh=CreateMesh()
	surf=CreateSurface(mesh)
	EntityFX mesh,1+2
	
	For i=1 To stars
		
		; create new surface if there are too many stars
		If CountVertices(surf)>=65532 Then surf=CreateSurface(mesh)
		
		; size
		size=min*scale
		If Rnd(1)>fix Then size=Rnd(min,max)*scale
		ScaleEntity star,size,size,size
		
		; reset quad
		PositionEntity star,0,0,0
		
		; more stars centered or random?
		If Rnd(1)>centered Then maxy=centermin Else maxy=centermax
		
		; turn and move starquad
		TurnEntity star,Rnd(-Rnd(0,maxy),Rnd(0,maxy)),Rnd(0,Rnd(0,360)),0
		MoveEntity star,0,0,range*scale
		PointEntity star,mesh
		
		; color
		col=Rnd(1)
		If col>0.75 And col<=1.00 Then r=255 : g=224 : b=192	; 25% orange stars
		If col>0.50 And col<=0.75 Then r=255 : g=255 : b=192	; 25% yellow stars
		If col>0.25 And col<=0.50 Then r=192 : g=224 : b=255	; 25% blue stars
		If col>0.00 And col<=0.25 Then r=255 : g=255 : b=255	; 25% white stars
		
		; alpha
		If size>min*scale Then a#=1.0 Else a#=Rnd(0.5,1)
		
		; add to single surface mesh
		AddToSurface(star,surf,mesh,r,g,b,a)
		
	Next
	
	FreeEntity star
	
	EntityTexture mesh,texture
	
	FlipMesh mesh
	
	Return mesh
	
End Function


; -----------------------------------------------------------------------------
; simple cube starbox
; -----------------------------------------------------------------------------
Function InitStarBox(scale#,texture%,fx%,blend%)
	
	Local starbox%
	
	starbox=CreateCube()
	EntityTexture starbox,texture
	FlipMesh starbox
	ScaleEntity starbox,scale,scale,scale
	
	EntityFX starbox,fx
	EntityBlend starbox,blend
	
	Return starbox
	
End Function


; -----------------------------------------------------------------------------
; add a mesh to another mesh
; -----------------------------------------------------------------------------
Function AddToSurface(mesh,surf,singlesurfaceentity,r%,g%,b%,a#) 
	
	Local vert%[2],vr%[2],vg%[2],vb%[2],va#[2]
	Local surface%,oldvert%,i%,i2%
	
	surface = GetSurface(mesh,1) 
	
	For i = 0 To CountTriangles(surface)-1
		
		For i2 = 0 To 2 
			
			oldvert = TriangleVertex(surface,i,i2)
			
			vr[i2]=r
			vg[i2]=g
			vb[i2]=b
			va[i2]=a
			
			TFormPoint VertexX(surface,oldvert),VertexY(surface,oldvert),VertexZ(surface,oldvert), mesh,singlesurfaceentity 
			vert[i2] = AddVertex(surf,TFormedX(),TFormedY(),TFormedZ(),VertexU(surface,oldvert),VertexV(surface,oldvert)) 
			VertexColor surf,vert[i2],r,g,b,a
			
		Next 
		
		AddTriangle(surf,vert[0],vert[1],vert[2])
		
	Next 
	
End Function


; -----------------------------------------------------------------------------
; create star quad
; -----------------------------------------------------------------------------
Function CreateStarQuad(r%=255,g%=255,b%=255,a#=1.0,fx%=0)
	
	Local mesh%,surf%,v1%,v2%,v3%,v4%
	
	mesh=CreateMesh()
	surf=CreateSurface(mesh)
	
	v1=AddVertex(surf,-1,1,0,1,0)
	v2=AddVertex(surf,1,1,0,0,0)
	v3=AddVertex(surf,-1,-1,0,1,1)
	v4=AddVertex(surf,1,-1,0,0,1)
	
	VertexColor surf,v1,r,g,b,a
	VertexColor surf,v3,r,g,b,a
	VertexColor surf,v2,r,g,b,a
	VertexColor surf,v4,r,g,b,a
	
	AddTriangle(surf,0,1,2)
	AddTriangle(surf,3,2,1)
	
	EntityFX mesh,fx
	
	Return mesh
	
End Function

Comments

MCP2010
Very nice indeed Krischan.


Sung2010
Beautifull!


*2010
Gorgeous, will look into using this for another project :)


_PJ_2010
It's really smooth and gives a great impression of depth.

I didnt see this before, but found it after the "Procedural Saturn" stuff you did.
I'm thinking, that, all this (excluding perhaps the very well defined star sprite') might be procedurally generated, giving dfifferent "shapes" and colours to the nebulae (within reason of course, the H-Alpha regions would likely be prominently red etc.)
Even ikf the separate pieces are generated individually, this actually gives a greater freedom of 'mix and match' variety.
Once i've finished playing with Saturn (I'm working on a means to seed a single, but different, AND RELATIVE value to make Neptune and Uranus so far....)
I'll look into playing with generating this too :)


Krischan2010
Just to mention: the original PSD file for the Nebula has 170MB, 4096x1024 pixels and 18 Layers! I really want to see how to obtain the same result procedurally in a few seconds which costed me several days to create (mostly tweaking) :-D


_PJ_2010
Just to mention: the original PSD file for the Nebula has 170MB, 4096x1024 pixels and 18 Layers! I really want to see how to obtain the same result procedurally in a few seconds which costed me several days to create (mostly tweaking) :-D



Oh I certainly didn't mean to take anything from your artistic talent! Naturally an image like that you've worked on clearly so dedicatedly would be VERY difficult to even come close too. Perhaps I shouldn't have said |"it can be done procedurally" but rather, "something similar could be attempted [procedurally".

The method (I presume) of building the nebula involved wvarious different 'levels' of density of the fibrous dust/gas carefully laid over each other with various transparencies...
This same process can be achieved, but certainly not necesarily as well-defined or 'accurately' by (agaiun a noise function like perlin noise,- incidentally, did you use Photoshop's 'Difference Cloud' algorithm?', - to generate the structure of the dust-gas. This can be made more or less dense and then different levels applied over one another (by combining multiple alpha'd buffers into a final single buffer image)

That's the theory at leastm, at any rate, it's worth a try!
If that process can be reduced to some kind of algorithm or algorithms, then it need not even be done with a large 4096 image, but the algorithm can be repreated across smaller buffers to tile up to the large version.

Certainly, I can say without a doubt that your work has paid off since the images are truly stunning, and if I can get anything done procedurally, it wont be half as nice to look at, but as an exercise in ther theory, I wanna give it a try all the same. It helps me learn too :)


Krischan2010
If you prefer a REAL panorama of our milkyway you should try this, I converted the ESO Milkyway Panorama (6000x3000 pixel!) for this. It is available in two DDS resolutions, 2048x2048 and 1024x1024 but I prefer the 2048 resolution, looks more realistic. To switch resolutions just change the line in the milkyway.bb.

Just for your info if you want to include own images: the color level range of the nebula panorama should be from 0...127, otherwise it will be too overbright and look weird.

Download Real Milkyway SFX [1.1MB]

Screenshot with my latest Saturn demo



Cubed Inc.2010
damn, this is reach quality. great job.


xlsior2010
If you do use the 'real' milky way images in a program: remember that while most of the ones you'll find are free to use, they do require attribution in the credits.
ESO, NASA, ESA, etc. all have similar requirements.


Code Archives Forum