Code archives/3D Graphics - Effects/Ambient Volume Lib
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
With this lib you can Create and save Ambient Volume Maps which are basically a large 3D grid containing ambient color settings per cell. The lib allows you to make these over your large maps. Once done you can ambient map your level and ambient shade moving and still entities dynamically with very little cpu or gpu cost. No additional line picks or collision checks will be needed to utilize the volume data once its been created. You can also drop ambient volume static lights, once i improve the colored light placement im going to add moving lights as well via a second grid holding only lights. If you make any improvements please post them here. Thanks | |||||
Include "amb_volume.bb" ;//---------------------------------------------------------- ----TEST LIB--- ;//---------------------------------------------------------- ----TEST LIB--- ;//---------------------------------------------------------- ----TEST LIB--- ;// PRESS 1 TO DROP A RANDOM COLORED LIGHT ;// click SPACE BAR button to toggle ambient volume map on the level mesh Print "AMBIENT VOLUME LIB v1.0" Print "" Print "" Print "" Print "[ SPACEBAR ] : Toggle ambient scene mapping." Print "[ 1 ] : Drop a ambient volume light." Print "[ ESCAPE ] : Quit program. " Print "[ MOUSE BUTTONS ] : move around." Print "" Print "press any key to start " WaitKey() amb_smoothContrastdown_Startat=3 amb_smoothContrastdown_Endat=5 amb_smoothContrastDown#=.95 amb_SmoothContrastup_Startat=2 amb_SmoothContrastup_Endat=3 amb_SmoothContrastup#=1.01 Graphics3D 800,600,0,2 displayamb=1 camera=CreateCamera() CameraClsColor camera,0,55,125 CameraRange camera,1,13000 avatar=CreateSphere() EntityFX avatar,1 PositionEntity avatar,0,-2,3 EntityParent avatar,camera mesh=LoadMesh("yourmodelhere.b3d") ;toonmeshuv mesh EntityPickMode mesh,2 Amb_width# = MeshWidth(mesh) Amb_Height#= MeshHeight(mesh) Amb_Depth# = MeshDepth(mesh) AmbientLight 190,190,190 PositionEntity camera,-100,-250,0 ;//if you want to play with different settings in this test, just change ;//the filename here to something that will never exist.. such as "ambientvolume44.dat" ;//if you dont then it will only create the volume once, then load it the next time. If FileType("ambientvolume.dat")<>1 Then amb_smoothContrastdown_Startat=2 amb_smoothContrastdown_Endat=3 amb_smoothContrastDown#=.95 amb_SmoothContrastup_Startat=3 amb_SmoothContrastup_Endat=5 amb_SmoothContrastup#=1.5 smooth_times=5 lowest_Ambient=15 x_cells=100 y_cells=60 z_cells=100 ;another setting to try ; amb_smoothContrastdown_Startat=3 ; amb_smoothContrastdown_Endat=5 ; amb_smoothContrastDown#=.95 ; amb_SmoothContrastup_Startat=1 ; amb_SmoothContrastup_Endat=5 ; amb_SmoothContrastup#=1.01 ; smooth_times=5 ; lowest_Ambient=30 ; x_cells=120 ; y_cells=90 ; z_cells=120 ;prep and create flipped mesh copy Amb_prepMeshBeforeCreation(mesh) ;//the following two calls accomplish the same thing, but can be useful to use area if youre level mesh is not centered in global space ;//you can specify how many smooths to do in the creaion.. or you can do it later with a direct call to smoothambientvolume() ;createambientvolume_area(-1660,-1250,-1700,1660,1250,1700,smooth_times,lowest_ambient,x_cells,y_cells,z_cells) ;CreateblankAmbientVolume (mesh,Smooth_Times,Lowest_Ambient,x_cells,y_cells,z_cells) CreateAmbientVolume_SizeOfMesh (mesh,Smooth_Times,Lowest_Ambient,x_cells,y_cells,z_cells) ;remove flipped mesh copy Amb_freesparemeshes() ;save and apply the volume saveambientvolume ("ambientvolume.dat") ApplyAmbientVolumeToMesh(mesh) Else ;if the file exists load and apply volume loadambientvolume("ambientvolume.dat") ApplyAmbientVolumeToMesh(mesh) EndIf While Not KeyDown(1) ;hit SPACEBAR to see with and without volume applied to level mesh If KeyHit(57) Then displayamb=displayamb-1 If displayamb<=0 Then displayamb=3 Select displayamb Case 2 FreeEntity mesh mesh=LoadMesh("cabin.b3d") EntityPickMode mesh,2 removeambientvolumefrommesh(mesh,0) EntityFX mesh,2 Case 3 removeambientvolumefrommesh(mesh,1) applyambientvolumetomesh(mesh) EntityFX mesh,2 Case 1 applyambientvolumetomesh(mesh) EntityFX mesh,2 End Select EndIf ;press 1 on the keyboard to drop a random colored volume light If KeyHit(2) Then ;go ahead and prep main mesh (make flipped copy) to help the light accuracy (needs all the help it can get) Amb_prepMeshBeforeCreation(mesh) r=Rand(120,255) g=Rand(120,255) b=Rand(120,255) Amb_InsertLight(EntityX(camera),EntityY(Camera),EntityZ(Camera),350,r,g,b) Amb_freesparemeshes() applyambientvolumetomesh(mesh) EndIf ;allow camera movement with the mouse buttons MoveEntity Camera,(KeyDown(205)-KeyDown(203))*5,0,(MouseDown(1)-MouseDown(2))*5 TurnEntity Camera,MouseYSpeed()*0.1,-MouseXSpeed()*0.1,0 RotateEntity Camera,EntityPitch(Camera,True),EntityYaw(Camera,True),0 ;use amb_entitycolor() to show how an enity can be shaded by the ambient volume amb_entitycolor(Avatar) ;position mouse in middle so mouselook can work MoveMouse GraphicsWidth()*.5,GraphicsHeight()*.5 UpdateWorld() RenderWorld() Flip Wend amb_vol_clearall() EndGraphics() End ;//---------------------------------------------------------- ----END TEST--- ;//---------------------------------------------------------- ----END TEST--- ;//---------------------------------------------------------- ----END TEST--- |
Comments
| ||
;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ;Ambient volume dynamic shading lib. by Jeff Frazier ( rifraf ) ;Aug, 2011 ;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ; if you improve on this lib , please update me ( gamemaker04@... ) and/or repost in the original code archives entry ; thank you. ;///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Dim ambientVolume(0,0,0) Dim ambientVolumeSmooth(0,0,0) Global amb_brightest=255 ;the following four globals are used in SmoothAmbientVolume() ;to allow contrasting freedoms per volume created, please review the ;smoothing loop "for rep=" in that function to see how these play a part Global amb_smoothContrastdown_Endat=5 Global amb_smoothContrastdown_Startat=2 Global amb_smoothContrastDown#=.95 Global amb_SmoothContrastup_Startat=3 Global amb_SmoothContrastup_Endat=5 Global amb_SmoothContrastup#=1.2 ;THE DIVISION FOR CURVING THE COLOR OF SHADED ENTITIES ;LARGER NUMBERS = SMOOTHING COLOR TRANSITIONS.. Const AMB_ColorShiftFrames=30 Global Amb_default_Ambient%=40 ;Used to store temporaty flipped mesh copies before a createvolume() call Type Amb_flippedmesh Field ent End Type ;used as return values from Amb_splitcolors() Global amb_split_red% Global amb_split_green% Global amb_split_blue% ;Stores an entities scale factors when you call Amb_getmeshscale() Global amb_XScale# Global amb_YScale# Global amb_ZScale# ;used as return values from createambientvolume() and loadambientvolume(() ;these pertain the the volume dementions and space it takes up Global AMB_Vol_MaxGridX=1 Global AMB_Vol_MaxGridY=1 Global AMB_Vol_MaxGridZ=1 Global AMB_VOL_SPACEX#=1 Global AMB_VOL_SPACEY#=1 Global AMB_VOL_SPACEZ#=1 ;used as return values from createambientvolume() and loadambientvolume(() ;these values are needed to use Amb_InsertLight() Global Amb_width# Global Amb_Height# Global Amb_Depth# ;Return values from the coordinate convertion functions Global Grid_getx# Global Grid_gety# Global Grid_getz# Global ent_Gridx% Global ent_Gridy% Global ent_Gridz% ;used store entities that are colored via Amb_Entitycolor() but the type list is handled by the lib Type Amb_RGB Field r Field g Field b End Type Function Delete_AmbEntityColor(ent) ;NOTE if you free an entity that could have a amb_rbg type assosiated with it then ;you must call this function before you free the entity else the next call here ;for that entity will MAV This.amb_RGB = Object.amb_RGB( EntityName( Ent ) ) If this<>Null Then Delete this End Function Global Recent_EntityRed%,Recent_EntityGreen%,Recent_EntityBlue% Function amb_entitycolor_update(ent,r,g,b) This.amb_RGB = Object.amb_RGB( EntityName( Ent ) ) If this<>Null Then recent_entityred%= amb_curve(r,this\r,AMB_ColorShiftFrames) recent_entitygreen%= amb_curve(g,this\g,AMB_ColorShiftFrames) recent_entityblue%= amb_curve(b,this\b,AMB_ColorShiftFrames) Amb_EntityAnimColor ent,Recent_EntityRed%,Recent_EntityGreen%,Recent_EntityBlue% this\r=Recent_EntityRed% this\g=Recent_EntityGreen% this\b=Recent_EntityBlue% Else This.amb_RGB = New amb_RGB This\R = r This\G = g This\B = b NameEntity Ent, Handle( This ) Amb_EntityAnimColor ent,r,g,b EndIf End Function ;use this on entities that will be moving around so they can change shades smoothly Function amb_entitycolor(ent) GetEntityGrid(ent) amb_splitcolors(ambientvolume(ent_gridx,ent_gridy,ent_gridz)) amb_entitycolor_update ent,amb_split_Red,amb_split_green,amb_split_blue End Function ;use this one if you dont want gradually shade shifting.. for example on scenery items dropped into place ;durring map loading. Function amb_entitycolor_instant(ent,plusr=-1,plusg=-1,plusb=-1) EntityFX ent,0 EntityBlend ent,1 PositionEntity projectilepivot,EntityX(ent,1),EntityY(Ent,1)+10,EntityZ(Ent,1) GetEntityGrid(projectilepivot) amb_splitcolors(ambientvolume(ent_gridx,ent_gridy,ent_gridz)) If plusr>-1 Or plusg>-1 Or plusb>-1 Then Newr#=((amb_split_red+plusr)/2) Newg#=((amb_split_green+plusg)/2) Newb#=((amb_split_blue+plusb)/2) Else newr=amb_split_red newg=amb_split_green newb=amb_split_blue EndIf Amb_EntityAnimColor ent,newr,newg,newb End Function ;returns where an entity is in the volume array ;storing the result in ent_gridx,ent_gridy,ent_gridz Function GetEntityGrid(entity) gx#=EntityX(entity,1) gy#=EntityY(entity,1)+4 gz#=EntityZ(entity,1) ent_gridX=Int((gx/AMB_VOL_SPACEX))+(AMB_Vol_MaxGridX/2) ent_gridY=Int((gy/AMB_VOL_SPACEY))+(AMB_Vol_MaxGridY/2) ent_gridZ=Int((gz/AMB_VOL_SPACEZ))+(AMB_Vol_MaxGridZ/2) If ent_gridx<0 Or ent_gridx>AMB_Vol_MaxGridx Then ent_gridx=0 If ent_gridy<0 Or ent_gridy>AMB_Vol_MaxGridy Then ent_gridy=0 If ent_gridz<0 Or ent_gridz>AMB_Vol_MaxGridz Then ent_gridz=0 End Function ;returns the 3d space real coordinates of a volume array space ;stores the result in grid_getx,grid_getx,grid_getz Function GridToCoords(gx,gy,gz) grid_getx#=((gx*AMB_VOL_SPACEX)-(AMB_Vol_MaxGridX/2)*AMB_VOL_SPACEX) grid_gety#=((gy*AMB_VOL_SPACEY)-(AMB_Vol_MaxGridY/2)*AMB_VOL_SPACEY) grid_getz#=((gz*AMB_VOL_SPACEZ)-(AMB_Vol_MaxGridZ/2)*AMB_VOL_SPACEZ) End Function ;returns the volume array space of a real global x,y,z coordinate ;storing the result in ent_gridx,ent_gridy,ent_gridz Function CoordsToGrid(gx#,gy#,gz#) ent_gridX=Int((gx/AMB_VOL_SPACEX))+(AMB_Vol_MaxGridX/2) ent_gridY=Int((gy/AMB_VOL_SPACEY))+(AMB_Vol_MaxGridY/2) ent_gridZ=Int((gz/AMB_VOL_SPACEZ))+(AMB_Vol_MaxGridZ/2) ;error check If ent_gridx<0 Or ent_gridx>AMB_Vol_MaxGridx Then ent_gridx=0 If ent_gridy<0 Or ent_gridy>AMB_Vol_MaxGridy Then ent_gridy=0 If ent_gridz<0 Or ent_gridz>AMB_Vol_MaxGridz Then ent_gridz=0 End Function Function CoordsToGridBetter(gx#,gy#,gz#) ;this snaps the coors to grid, but also checks the vertex coordinat distance from all ;neightbor grids to make sure we arent landing near the line of a neighbor cell and are closer to its ;center than the default snap location. . used in creating lights.. but not for real time dynamic entity shading ent_gridX=Int((gx/AMB_VOL_SPACEX))+(AMB_Vol_MaxGridX/2) ent_gridY=Int((gy/AMB_VOL_SPACEY))+(AMB_Vol_MaxGridY/2) ent_gridZ=Int((gz/AMB_VOL_SPACEZ))+(AMB_Vol_MaxGridZ/2) Dister#=999999 For GridX=-2 To 2 For Gridz=-2 To 2 For gridY=-2 To 2 gridtocoords(ent_gridx+gridx,ent_gridy+gridy,ent_gridz+gridz) checkd#= amb_distance(grid_getx,grid_Gety,grid_getz,gx,gy,gz) If checkd#<dister# Then dister#=checkd# winnerx=ent_gridx+gridx winnery=ent_gridy+gridy winnerz=ent_gridz+gridz EndIf Next Next Next ;error check ent_gridx=winnerx ent_gridy=winnery ent_gridz=winnerz If ent_gridx<0 Or ent_gridx>AMB_Vol_MaxGridx Then ent_gridx=0 If ent_gridy<0 Or ent_gridy>AMB_Vol_MaxGridy Then ent_gridy=0 If ent_gridz<0 Or ent_gridz>AMB_Vol_MaxGridz Then ent_gridz=0 End Function ;save the volume for later use.. much faster than recalculating each time you need it Function SaveAmbientVolume(fn$) F=WriteFile(fn$) WriteFloat f,Amb_width# WriteFloat f,Amb_Height# WriteFloat f,Amb_Depth# WriteInt F,AMB_Vol_MaxGridX WriteInt F,AMB_Vol_MaxGridY WriteInt F,AMB_Vol_MaxGridZ WriteInt F,AMB_VOL_SPACEX WriteInt F,AMB_VOL_SPACEY WriteInt F,AMB_VOL_SPACEZ For i=0 To AMB_Vol_MaxGridX For ii=0 To AMB_Vol_MaxGridY For iii=0 To AMB_Vol_MaxGridZ WriteInt f,ambientvolume(i,ii,iii) Next Next Next CloseFile f Return End Function ;loading of volume Function LoadAmbientVolume(fn$,scalex#=1.0,scaley#=1.0,scalez#=1.0,loadpower#=1.0) If FileType(fn$)=0 Then Use_AmbVolume=False Return EndIf F=ReadFile(fn$) Amb_width# = ReadFloat(f)*scalex# Amb_Height#= ReadFloat(f)*scaley# Amb_Depth# = ReadFloat(f)*scalez# AMB_Vol_MaxGridX=ReadInt(F) AMB_Vol_MaxGridY=ReadInt(F) AMB_Vol_MaxGridZ=ReadInt(F) AMB_VOL_SPACEX=ReadInt(F)*scalex AMB_VOL_SPACEY=ReadInt(F)*scaley AMB_VOL_SPACEZ=ReadInt(F)*scalez Dim AMBIENTVOLUME(AMB_Vol_MaxGridX,AMB_Vol_MaxGridY,AMB_Vol_MaxGridZ) For ax=0 To AMB_Vol_MaxGridX For ay=0 To AMB_Vol_MaxGridY For az=0 To AMB_Vol_MaxGridZ cv=ReadInt(f) amb_splitcolors(cv) amb_split_red=amb_split_Red*loadpower amb_split_green=amb_split_green*loadpower amb_split_blue=amb_split_blue*loadpower cv=amb_Tricolor(amb_split_Red,amb_split_green,amb_split_blue) ambientVolume(ax,ay,az)=cv Next Next Next CloseFile f Return End Function ;The slowest part of this library, smooths a newly created volume to look much much better Function SmoothAmbientVolume(amount=1,offset#=1) Dim ambientVolumeSmooth(AMB_Vol_MaxGridX,AMB_Vol_MaxGridy,AMB_Vol_MaxGridz) For rep=1 To amount totalseen=0 newr=0 newg=0 newb=0 multi#=1.0 For ax=1 To AMB_Vol_MaxGridX-1 For ay=1 To AMB_Vol_MaxGridY-1 For az=1 To AMB_Vol_MaxGridZ-1 amb_splitcolors(ambientvolume(ax,ay,az)) r0=amb_split_Red g0=amb_split_green b0=amb_split_blue ;newr=newr+r0 ; newg=newg+g0 ; newb=newb+b0 ;totalseen=totalseen+1 ; If r0=255 And b0=255 And g0=255 Then If REP=>amb_smoothContrastdown_Startat And rep<= amb_smoothContrastdown_endat Then multi#= amb_smoothContrastDown# ;.95 ;Else If REP=>amb_SmoothContrastup_Startat And rep<= amb_SmoothContrastup_endat Then multi=amb_SmoothContrastup# ;1.1 ; EndIf If Grids_Inview(ax,ay,az,ax+1,ay,az) Then amb_splitcolors(ambientvolume(ax+1,ay,az)) r1=amb_split_Red g1=amb_split_green b1=amb_split_blue newr=newr+(r1*multi#) newg=newg+(g1*multi#) newb=newb+(b1*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax-1,ay,az) Then amb_splitcolors(ambientvolume(ax-1,ay,az)) r2=amb_split_Red g2=amb_split_green b2=amb_split_blue newr=newr+(r2*multi#) newg=newg+(g2*multi#) newb=newb+(b2*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax,ay,az+1) Then amb_splitcolors(ambientvolume(ax,ay,az+1)) r3=amb_split_Red g3=amb_split_green b3=amb_split_blue newr=newr+(r3*multi#) newg=newg+(g3*multi#) newb=newb+(b3*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax,ay,az-1) Then amb_splitcolors(ambientvolume(ax,ay,az-1)) r4=amb_split_Red g4=amb_split_green b4=amb_split_blue newr=newr+(r4*multi#) newg=newg+(g4*multi#) newb=newb+(b4*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax+1,ay,az-1) Then amb_splitcolors(ambientvolume(ax+1,ay,az-1)) r5=amb_split_Red g5=amb_split_green b5=amb_split_blue newr=newr+(r5*multi#) newg=newg+(g5*multi#) newb=newb+(b5*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax+1,ay,az+1) Then amb_splitcolors(ambientvolume(ax+1,ay,az+1)) r6=amb_split_Red g6=amb_split_green b6=amb_split_blue newr=newr+(r6*multi#) newg=newg+(g6*multi#) newb=newb+(b6*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax-1,ay,az-1) Then amb_splitcolors(ambientvolume(ax-1,ay,az-1)) r7=amb_split_Red g7=amb_split_green b7=amb_split_blue newr=newr+(r7*multi#) newg=newg+(g7*multi#) newb=newb+(b7*multi#) totalseen=totalseen+1 EndIf If Grids_Inview(ax,ay,az,ax-1,ay,az+1) Then amb_splitcolors(ambientvolume(ax-1,ay,az+1)) r8=amb_split_Red g8=amb_split_green b8=amb_split_blue newr=newr+(r8*multi#) newg=newg+(g8*multi#) newb=newb+(b8*multi#) totalseen=totalseen+1 EndIf If totalseen>0 Then newr=(newr/totalseen)*offset newg=(newg/totalseen)*offset newb=(newb/totalseen)*offset EndIf totalseen=0 If newr>255 Then newr=255 If newg>255 Then newg=255 If newb>255 Then newb=255 If newr<amb_default_Ambient Then newr=amb_default_ambient If newg<amb_default_Ambient Then newg=amb_default_ambient If newb<amb_default_Ambient Then newb=amb_default_ambient ambientvolumesmooth(ax,ay,az)=amb_tricolor(newr,newg,newb) Next Next Next For ax=1 To AMB_Vol_MaxGridX-1 For ay=1 To AMB_Vol_MaxGridY-1 For az=1 To AMB_Vol_MaxGridZ-1 ambientvolume(ax,ay,az)=ambientvolumesmooth(ax,ay,az) Next Next Next Next;rep Dim ambientVolumeSmooth(0,0,0) End Function Function CreateAmbientVolume_Area(x1#,y1#,z1#,x2#,y2#,z2#,Smoothing=3,AmbC=30,maxx=90,maxy=90,maxz=90,replacemesh=0) tempmesh=CreateCube() ScaleMesh tempmesh,1,1,1 sizex#=x2-x1 sizey#=y2-y1 sizez#=z2-z1 FitMesh tempmesh,x1,y1,z1,sizex,sizey,sizez,False FlipMesh tempmesh EntityColor tempmesh,255,0,0 CreateAmbientVolume_SizeOfMesh(tempmesh,Smoothing,AmbC,maxx,maxy,maxz) FreeEntity tempmesh End Function Function Amb_prepMeshBeforeCreation(mesh,flipit=True) ;//NOTICE YOU WILL AT LEAST WANT TO RUN THIS ON YOUR MAIN LEVEL MESH ;//BECORE THE CREATION PROCESS.. it is not required though for a load from file ambvolume ;copy the mesh and flip it ;our smoothing is done by doing vision checks from one cell to the other ;these checks will be inacurate if the map mesh is one sided ;any objects that you want to inpact the volume creation need to have a pickmode of 2 ;however large complex objects should be ran through this prepmesh function ;basically we record a flipped version of the entity so that picks dont go though walls if they are ;going from the backface to a light source , and proper light source obsuring accurs Ambf.Amb_flippedmesh=New Amb_flippedmesh ambf\ent=CopyMesh (mesh) If flipit=True Then FlipMesh ambf\ent EntityPickMode ambf\ent,2 PositionEntity ambf\ent,EntityX(mesh,1),EntityY(mesh,1),EntityZ(mesh,1) RotateEntity ambf\ent,EntityPitch(mesh,1),EntityYaw(mesh,1),EntityRoll(mesh,1) EntityPickMode mesh,2 End Function Function Amb_FreeSpareMeshes() For Ambf.Amb_flippedmesh=Each Amb_flippedmesh FreeEntity ambf\ent Delete ambf Next End Function Function CreateBlankambientvolume(Mesh,Smoothing=3,AmbC=30,maxx=90,maxy=90,maxz=90) Amb_width# = MeshWidth(mesh)*4 Amb_Height#= MeshHeight(mesh)*4 Amb_Depth# = MeshDepth(mesh)*4 ;The default setting gives you 90 cells on all axi = 90x90x90 cell resoluton ;all created around your mesh. This consumes about 6 megs or ram, and a 6 meg save file ;you can reduce this my reducing the cell counts on one or all axis. Be careful using higher values ;as theres no limit to the ram you can use.. ive used up to 400 megs on very high res volumes ;those sizes also take hours to calculate and smooth. On my system this default volume res takes about 1 minute ;copy the mesh and flip it ;our smoothing is done by doing vision checks from one cell to the other ;these checks will be inacurate if the map mesh is one sided ;also any objects that you want to inpact the volume creation need to have a pickmode of 2 before you call this ;function Amb_default_Ambient=ambc If abv_amb<0 Then amv_ambient=0 If abv_amb>255 Then amv_ambient=255 AMB_Vol_MaxGridX=MAXX AMB_Vol_MaxGridY=MAXY AMB_Vol_MaxGridZ=MAXZ AMB_VOL_SPACEX=amb_width / (maxx/2) AMB_VOL_SPACEY=amb_height/ (maxy/2) AMB_VOL_SPACEZ=amb_depth / (maxz/2) Dim AMBIENTVOLUME(AMB_Vol_MaxGridX,AMB_Vol_MaxGridY,AMB_Vol_MaxGridZ) ;set all cells to default ambient color For ix=0 To maxx:For iy=0 To maxy:For iz=0 To maxz ambientvolume(ix,iy,iz)=amb_tricolor(Amb_default_Ambient,Amb_default_Ambient,Amb_default_Ambient) Next:Next:Next End Function Function amb_FillVolumeColor(Cvalr,cvalg,cvalb) For i=0 To amb_col_maxgridx For ii=0 To amb_col_maxgridx For ii=0 To amb_col_maxgridx ambientvolume(i,i,ii)=amb_tricolor(cvalr,cvalg,cvalb) Next Next Next End Function Function CreateAmbientVolume_SizeOfMesh(Mesh,Smoothing=3,AmbC=30,maxx=90,maxy=90,maxz=90) Amb_width# = MeshWidth(mesh) Amb_Height#= MeshHeight(mesh) Amb_Depth# = MeshDepth(mesh) ;The default setting gives you 90 cells on all axi = 90x90x90 cell resoluton ;all created around your mesh. This consumes about 6 megs or ram, and a 6 meg save file ;you can reduce this my reducing the cell counts on one or all axis. Be careful using higher values ;as theres no limit to the ram you can use.. ive used up to 400 megs on very high res volumes ;those sizes also take hours to calculate and smooth. On my system this default volume res takes about 1 minute ;copy the mesh and flip it ;our smoothing is done by doing vision checks from one cell to the other ;these checks will be inacurate if the map mesh is one sided ;also any objects that you want to inpact the volume creation need to have a pickmode of 2 before you call this ;function Amb_default_Ambient=ambc If abv_amb<0 Then amv_ambient=0 If abv_amb>amb_brightest Then amv_ambient=amb_brightest AMB_Vol_MaxGridX=MAXX AMB_Vol_MaxGridY=MAXY AMB_Vol_MaxGridZ=MAXZ AMB_VOL_SPACEX=amb_width / (maxx/2) AMB_VOL_SPACEY=amb_height/ (maxy/2) AMB_VOL_SPACEZ=amb_depth / (maxz/2) Dim AMBIENTVOLUME(AMB_Vol_MaxGridX,AMB_Vol_MaxGridY,AMB_Vol_MaxGridZ) ;set all cells to default ambient color For ix=0 To maxx:For iy=0 To maxy:For iz=0 To maxz ambientvolume(ix,iy,iz)=amb_tricolor(Amb_default_Ambient,Amb_default_Ambient,Amb_default_Ambient) Next:Next:Next ;pick down from just the top most Height of the volume.. where the pick lands.. we assign that column all the way ;up from the pick to the top of the volume to full bright, then we smooth out the entire volume to finish it up For ix=0 To maxx:For iz=0 To maxz iy=maxy gridtocoords(ix,iy,iz) xloop=grid_getx# yloop=grid_gety# zloop=grid_getz# pk= LinePick(xloop,yloop+400,zloop,0 ,-7500 ,0 ,.1) pkx#=PickedX() pky#=PickedY()+Float(amb_vol_spacey)*.2 pkz#=PickedZ() coordstogrid(pkx,pky,pkz) If pk=0 Then ent_gridy=0 For colmn=ent_gridy To maxy Step 1 ambientvolume(ent_gridx,colmn,ent_gridz)=amb_tricolor(amb_brightest,amb_brightest,amb_brightest) Next Next Next smoothambientvolume(smoothing) End Function Function MatchVert_toEnt(mesh) ;if you entity has a rotation other than 0,0,0 or scale other than 1,1,1 you ;must pass it though this if you want to use ApplyAmbientVolumetoMesh() so the verts will fall into ;the proper volmues and be colored correctly. RotateMesh mesh,EntityPitch(mesh,1),EntityYaw(mesh,1),EntityRoll(mesh,1) amb_getmeshscale(mesh) ScaleMesh mesh,amb_XScale#,amb_yScale#,amb_zccale# ;we dont need to positionmesh because we can use entityxyz offsets in the applyambientcolumetomesh() call ;PositionMesh End Function Function ApplyAmbientVolumeToMesh(ent,power#=1.0) ;//NOTE this will not work on entiies that were copied via copyentity() ;to work on several copies you must use copymesh() EntityFX ent,2 scount=CountSurfaces(ent) For sloop=1 To scount surf=GetSurface(ent,sloop) v=CountVertices(surf)-1 For vloop=0 To v vnx#=VertexNX(surf,vloop) vny#=VertexNY(surf,vloop) vnz#=VertexNZ(surf,vloop) vx#=VertexX(surf,vloop)+EntityX(ent)+(Sgn(vnx)*(AMB_VOL_SPACEx/2)) ; vy#=VertexY(surf,vloop)+EntityY(ent)+(Sgn(vny)*(AMB_VOL_SPACEY/2)) ;move up or down slightly vz#=VertexZ(surf,vloop)+EntityZ(ent)+(Sgn(vnz)*(AMB_VOL_SPACEz/2)) ; CoordsToGrid(vx#,vy#,vz#) gridtocoords(ent_gridx,ent_gridy,ent_gridz) amb_splitcolors(ambientvolume(ent_gridx,ent_gridy,ent_gridz)) va#=VertexAlpha(surf,vloop) finish_Red#=Float(amb_split_red)*power finish_green#=Float(amb_split_green)*power finish_blue#=Float(amb_split_blue)*power If finish_red>255 Then finish_Red=255 If finish_green>255 Then finish_green=255 If finish_blue>255 Then finish_blue=255 VertexColor(surf,vloop,finish_Red,finish_green,finish_blue,va) Next Next End Function ;useless function I made for fun.. kept it in because you can really see the ambient volume mapping this way Function ToonmeshUV(ent) scount=CountSurfaces(ent) For sloop=1 To scount surf=GetSurface(ent,sloop) v=CountVertices(surf)-1 For vloop=0 To v VertexTexCoords (surf,vloop,.4,.4) Next Next UpdateNormals(ent) End Function ;useless in a game, but useful in editing ambient volumes Function RemoveAmbientVolumeFromMesh(ent,cleartextures=0) scount=CountSurfaces(ent) For sloop=1 To scount surf=GetSurface(ent,sloop) If cleartextures<>0 Then b=CreateBrush(255,255,255) PaintSurface surf,b FreeBrush b EndIf v=CountVertices(surf)-1 For vloop=0 To v va#=VertexAlpha(surf,vloop) VertexColor(surf,vloop,255,255,255,va) Next Next End Function Function amb_tricolor(r,g,b) Return $FF000000 Or b Or g Shl 8 Or r Shl 16 End Function Function amb_splitcolors(val%) amb_Split_Red= (val% Shr 16) And $ff amb_split_Green=(val% Shr 8) And $ff amb_split_Blue= val% And $ff End Function Function Amb_Distance#( x#, y#, z#, x2#, y2#, z2# ) value#=Sqr((x#-x2#)*(x#-x2#)+(y#-y2#)*(y#-y2#)+(z#-z2#)*(z#-z2#)) Return value# End Function Function Amb_Distance2d#( v#, v2#) value#=Sqr((v#-v2#)*(v#-v2#)) Return value# End Function Function Amb_Curve#(newvalue#,oldvalue#,increments#) If increments>1 Then oldvalue#=oldvalue#-(oldvalue#-newvalue#)/increments If increments<=1 Then oldvalue=newvalue Return oldvalue# End Function ;///NOTE THIS FUNCTION COULD BE BETTER.. IF ANY SMART BLITZERS WANT TO IMPROVE ON THIS, PLEASE DO. Function Amb_InsertLight(x#,y#,z#,range#,r,g,b) ;you must have any light obscuring meshes set to pick mode 2 ;convert range from coordinate range To volume cell range average_Space#=((AMB_VOL_SPACEX+AMB_VOL_SPACEZ+AMB_VOL_SPACEY)/3) range= range / average_space temppiv3=CreateCube() temppiv2=CreateCube() temppiv=CreateCube() EntityRadius temppiv,1 EntityPickMode temppiv,1 ScaleEntity temppiv,1,1,1 EntityRadius temppiv2,1 EntityPickMode temppiv2,1 ScaleEntity temppiv2,1,1,1 ;//AQUIRE 3D ASPECT ----------- ;because the same amount of Cells represent varied length width and height ; of the light volume depending on the size of level mesh used ; we must sort out the 3D apsect ratio to get a circular light range rangex=range rangey=range rangez=range If amb_width>amb_depth Then dif#=amb_width / amb_Depth ratio_x#=1.0 ratio_z#=dif# rangex=range rangez=range*dif If amd_height<amb_width Then dif#=amb_width / amb_height rangey=range*dif ratio_y#=dif# Else dif#=amb_height / amb_width ratio_y#=1.0 ratio_x#=dif# rangey=range rangex=range*dif EndIf ;// Else ;// dif#= amb_depth / amb_width rangez=range ratio_z#=1.0 ratio_x#=dif# rangex=range*dif If amd_height<amb_depth Then dif#=amb_depth / amb_height rangey=range*dif ratio_y#=dif# Else dif#=amb_height / amb_depth rangey=range rangez=range*dif ratio_y#=1.0 ratio_z#=dif# EndIf EndIf ;// ASPECT RATIOS CALCULATED CORRECTLY halfrangex=rangex/2 halfrangey=rangey/2 halfrangez=rangez/2 CoordsToGrid(x,y,z) ;//LOOP THROUGH THE REGION For xl=ent_gridx-halfrangex To ent_gridx+halfrangex For yl=ent_gridy+halfrangey To ent_gridy-halfrangey Step -1 For zl=ent_gridz-halfrangez To ent_gridz+halfrangez If xl>0 And xl< AMB_Vol_MaxGridX And yl>0 Or yl< AMB_Vol_MaxGridY And zl>0 And zl< AMB_Vol_MaxGridZ Then ;ok inside the volume and inside the range of the light ;//CALCULATE THE POWER OF THE LIGHT OUTWARD FROM ITS CENTER ----------- ;//PERHAPS B3D MATH WIZARD CAN IMPROVE ON THIS ROUTING ddx#=amb_distance2d(xl,ent_gridx)*(1.0/ratio_x) ddy#=amb_distance2d(yl,ent_gridy)*(1.0/ratio_y) ddz#=amb_distance2d(zl,ent_gridz)*(1.0/ratio_z) dd#=(ddx+ddy+ddz) power#=(1.2/range) * (dd/2) If power#<0 Then power=0 If power>1 Then power=1 amb_splitcolors(ambientvolume(xl,yl,zl)) totalr#=Float(amb_split_red)* (1.0-power) totalg#=Float(amb_split_green)*(1.0-power) totalb#=Float(amb_split_blue)* (1.0-power) totalr=totalr + (Float(r)*power) totalg=totalg + (Float(g)*power) totalb=totalb + (Float(b)*power) ;dont allow the light to bring a color below the ambient If totalr<amb_split_red Then totalr=amb_split_Red If totalg<amb_split_green Then totalg=amb_split_green If totalb<amb_split_blue Then totalb=amb_split_blue If totalr>255 Then totalr=255 If totalg>255 Then totalg=255 If totalb>255 Then totalb=255 ;dy#=DeltaYaw(temppiv,temppiv2) ;dp#=DeltaPitch(temppiv,temppiv2) ;Since the volume is a rigid grid and mapping fluid flowing vertex patterns are not, then ;you will likely get some vertex bleeding.. the below is my attempt to best set the ;volumes for added colored lights so that mesh mapping can look alright. ;gridtocoords(xl,yl,zl) ;PositionEntity temppiv,x,y,z ;PositionEntity temppiv3,x,y,z ;PositionEntity temppiv2,grid_getx,grid_gety,grid_getz ;PointEntity temppiv2,temppiv ;PointEntity temppiv,temppiv2 ;dlp#=EntityDistance(temppiv,temppiv2) ; ;MoveEntity temppiv2,0,0,dlp/10 ; MoveEntity temppiv,0,0,dlp/5 ;If EntityPick (temppiv,2000)=temppiv2 Then ;If EntityPick (temppiv2,2000)=temppiv Then ambientvolume(xl,yl,zl)=amb_tricolor(totalr,totalg,totalb) ;EndIf ;EndIf EndIf Next Next Next FreeEntity temppiv FreeEntity temppiv2 FreeEntity temppiv3 End Function ;returns whether or not two grid spaces have a line of sight to each other from any of the straight lines Function Grids_Inview(x1,y1,z1,x2,y2,z2) If grid_linepick(x1,y1,z1,x2,y2,z2)<>0 Then If grid_linepick(x1+1,y1,z1,x2,y2,z2)<>0 Then If grid_linepick(x1,y1,z1+1,x2,y2,z2)<>0 Then If grid_linepick(x1-1,y1,z1,x2,y2,z2)<>0 Then If grid_linepick(x1,y1,z1-1,x2,y2,z2)<>0 Return 0 EndIf EndIf EndIf EndIf Return 1 End Function ;performs a line pick from two volume cells(grids) Function Grid_linepick(x1#,y1#,z1#,x2#,y2#,z2#) overshotx=AMB_VOL_SPACEX overshoty=AMB_VOL_SPACEy overshotz=AMB_VOL_SPACEz GridToCoords(x1,y1,z1) x1#=grid_getx# y1#=grid_gety# z1#=grid_getz# GridToCoords(x2,y2,z2) x2#=grid_getx# y2#=grid_gety# z2#=grid_getz# dx#=Sgn(x2-x1) dy#=Sgn(y2-y1) dz#=Sgn(z2-z1) Pck=LinePick(x1-(dx*overshotx),Y1-(dy*overshoty),Z1-(dz*overshotz),dx+(dx*overshotx),dy+(dx*overshoty),dz+(dx*overshotz),.1) Return pck+pck2 End Function ;color an entity and all its children, you can filter out children by entityname$ .. if you dont want all children colored Function Amb_EntityAnimColor(ent,r,g,b) EntityColor ent,r,g,b numc=CountChildren(ent) For c=1 To numc this=GetChild(ent,c) If EntityClass$(this)="Mesh" Then ename$=Lower$(EntityName$(this)) ; And Instr(ename$,"classbox")=0 ;Instr(ename$,"hbar")=0 If ename$<>"flag" And Instr(ename$,"rel")=0 And Instr(ename$,"rank")=0 Then EntityColor this,r,g,b amb_entityanimcolor this,r,g,b EndIf EndIf Next End Function Function amb_getmeshscale(mesh) vx# = GetMatElement#(Mesh, 0, 0) vy# = GetMatElement#(Mesh, 0, 1) vz# = GetMatElement#(Mesh, 0, 2) amb_XScale# = Sqr(vx# * vx# + vy# * vy# + vz# * vz#) vx# = GetMatElement#(Mesh, 1, 0) vy# = GetMatElement#(Mesh, 1, 1) vz# = GetMatElement#(Mesh, 1, 2) amb_YScale# = Sqr(vx# * vx# + vy# * vy# + vz# * vz#) vx# = GetMatElement#(Mesh, 2, 0) vy# = GetMatElement#(Mesh, 2, 1) vz# = GetMatElement#(Mesh, 2, 2) amb_ZScale# = Sqr(vx# * vx# + vy# * vy# + vz# * vz#) End Function ;free the lib Function Amb_Vol_ClearAll() Amb_FreeSpareMeshes() Delete Each amb_rgb Dim ambientVolume(0,0,0) AMB_Vol_MaxGridX=1 AMB_Vol_MaxGridY=1 AMB_Vol_MaxGridZ=1 AMB_VOL_SPACEX=1 AMB_VOL_SPACEY=1 AMB_VOL_SPACEZ=1 End Function |
| ||
ok I updated this lib. Above in the first post is the testing code, just add your own model to try it. A level map works best The second post is the library itself "amb_volume.bb" |
| ||
This is very nice code - I've been mulling over how to create some terrain from some GPS data - this nicely fits the bill. I just need to invoke some logic to even out the 'spikes'.... |
Code Archives Forum