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