Celshading and Outlines
BlitzMax Forums/MiniB3D Module/Celshading and Outlines
| ||
I've been putting this together in between making tools to edit animated meshes in MiniB3D over the last week. (Moving, rotating, adding, and removing bones is done along with adding and removing key frames. Still need vertex assignments and weights and of course an exporter...) Several places it seems I have seen requests for a celshading and outlining technique on here so I thought I would post it. Its been built ontop of code from the archives for Blitz3D, the Animation demo included with MiniB3D and some descriptions of how to achieve the effect using cubemapping. Also I updated the outliner to do animation. Example on the good ol' Zombie. ![]() Click here to get the shading texture I used here Hope somebody finds it useful. Import sidesign.minib3d 'A cel shading and outline example cobbled together by JetFireDX. 'The outlining code was found in the code archives for Blitz3D by 'SSwift here: http://www.blitzmax.com/Community/posts.php?topic=79166 'I ported it and extended it to support animated meshes in MiniB3D 'The cubemapping comes from the included example and a description of 'how to achive the effect in one of the forums. 'Enjoy and use as you like! Global width=800,height=600,depth=32,mode=0,rate=60 Graphics3D width,height,depth,mode,rate AmbientLight(255,255,255) Local cam=CreateCamera() CameraClsColor(cam,32,32,127) PositionEntity cam,0,10,-15 Local light=CreateCube() 'Yes a cube and not a real light. Just an object to point at and pretend its a light. PositionEntity light,40,20,-20 HideEntity(light) ' create texture with color + cubic environment map Local tex:TTexture=celshade(light,"celshade2.png") SetCubeMode tex,2 'Personally I think mode 2 looks better. Local ent=LoadAnimMesh("media/zombie.b3d") EntityTexture (ent,tex,0,1) Local outLine:TEntity = LoadAnimMesh("media/zombie.b3d") 'This creates the outlining effect on the Zombie celOutline(outLine,0.07) EntityParent(outLine,ent) Local anim_time#=0 ' used by camera code Local move#=0.5 While Not KeyDown(KEY_ESCAPE) If KeyDown(KEY_W)=True Then MoveEntity cam,0,0,move# ' move camera forward If KeyDown(KEY_S)=True Then MoveEntity cam,0,0,-move# ' move camera back If KeyDown(KEY_A)=True Then MoveEntity cam,-move#,0,0 ' move camera left If KeyDown(KEY_D)=True Then MoveEntity cam,move#,0,0 ' move camera right If KeyDown(KEY_MINUS) Then anim_time#=anim_time#-0.25 If KeyDown(KEY_EQUALS) Then anim_time#=anim_time#+0.25 GroupSetAnimTime(ent,anim_time#) 'Animate an entity and its children y:Float:+0.5 RotateEntity(ent,0,y,0) RenderWorld Text 0,20,"+/- to animate" Text 0,40,"anim_time#: "+AnimTime(ent) Flip Wend End Function celshade:TTexture(lite:TEntity,map:String) texSize = 256 'Much lower than this and the resulting texture shows a lot of pixelation. 'The texture that will be returned. Local retTex:TTexture=CreateTexture(texSize,texSize,1+16+32+128+256+512) Local shadeMap:TTexture = LoadTexture(map) Local celCam:TCamera = CreateCamera() Local sphere:TMesh = CreateSphere(60) EntityBlend(sphere,1) FlipMesh(sphere) EntityTexture(sphere,shadeMap) ScaleEntity(sphere,5,5,5) PositionEntity(sphere,0,0,0) RotateMesh(sphere,90,0,0) PointEntity(sphere,lite) CameraClsMode celCam,True,True ' set the camera's viewport so it is the same size as our texture - so we can fit entire screen contents into texture CameraViewport celCam,0,0,texSize,texSize ' do left view RenderWorld SetCubeFace retTex,0 RotateEntity celCam,0,90,0 RenderWorld BackBufferToTex(retTex) ' bmx ' do forward view SetCubeFace retTex,1 RotateEntity celCam,0,0,0 RenderWorld BackBufferToTex(retTex) ' bmx ' do right view SetCubeFace retTex,2 RotateEntity celCam,0,-90,0 RenderWorld BackBufferToTex(retTex) ' bmx ' do backward view SetCubeFace retTex,3 RotateEntity celCam,0,180,0 RenderWorld BackBufferToTex(retTex) ' bmx ' do up view SetCubeFace retTex,4 RotateEntity celCam,-90,0,0 RenderWorld BackBufferToTex(retTex) ' bmx ' do down view SetCubeFace retTex,5 RotateEntity celCam,90,0,0 RenderWorld BackBufferToTex(retTex) ' bmx FreeEntity celCam FreeEntity sphere Return retTex EndFunction Function celOutline(outLine:TEntity Var,scale:Float) If scale > 0 UpdateNormals TMesh(outLine) EntityColor(outLine,0,0,0) EntityFX(outLine,9) For Local currSurf:TSurface = EachIn TMesh(outLine).surf_list Local verts = CountVertices(currSurf) For v:Int = 0 To verts-1 Local VX# = VertexX (currSurf,v) Local VY# = VertexY (currSurf,v) Local VZ# = VertexZ (currSurf,v) Local VNX# = VertexNX (currSurf,v) Local VNY# = VertexNY (currSurf,v) Local VNZ# = VertexNZ (currSurf,v) If (VNX<-1) Or (VNX>1) Then VNX = 0 If (VNY<-1) Or (VNY>1) Then VNY = 0 If (VNZ<-1) Or (VNZ>1) Then VNZ = 0 VX = VX + (VNX*scale) VY = VY + (VNY*scale) VZ = VZ + (VNZ*scale) VertexCoords currSurf,v,VX,VY,VZ Next Next EndIf FlipMesh TMesh(outLine) End Function Function GroupSetAnimTime(ent:TEntity,anim_time:Float) If ent = Null Then Return SetAnimTime(ent,anim_time) For Local childEnt:TEntity = EachIn ent.child_list SetAnimTime(childEnt,anim_time) Next EndFunction |