Deforming Vertices randomly

Blitz3D Forums/Blitz3D Programming/Deforming Vertices randomly

_PJ_(Posted 2004) [#1]
Just toying with some ideas...
I am just getting to grips with code-based 3D mesh altering functions, and I am wondering if it's possible to take a cube, then, on one face of this cube, 'morph' the flat side into a jaggedy, 'natural' shape using random values.

I have only thought about this so far, and haven't touched any code, but I can see some potential issues...

1) This wont work with a Primitive, because primitives only have two triangles per face (or could extra triangles be created within the morphing process???)

2) The morphing needs to be congruent with adjacent cubes eventually***

3) The morphing needs to be 'aware' of whether the face is vertical or horizontal, as stalagmites etc. would be more prominent on 'floor' cubes than 'wall' cubes.

*** The idea behind this, is to create a 'dungeon map' designer, that shows a theoretical 3D view of the dungeon. To make cavernous walls look better, but to account for enormous variety, I envisioned using simple cubes, then with the faces morphed to look less regular. Exact repetition is not necessary (though could be achieved with a specific 'seed' value.


Dreamora(Posted 2004) [#2]
you can introduce new triangles in the morphing if you created the cube from the scratch not using blitz3ds function for creation of it.

you might check the clearsurface command, where you will see that you can delete all triangles from a surface -> you can recreate them with some new triangles to change the mesh during deformation


_PJ_(Posted 2005) [#3]
I still haven't got the hang of this.

I understand I need to create vertices instead of using Primitives (I guess because Primitive's faces use just 2 large tris, limiting the amount of morphing that is possible.)

If I explain what I am trying to do:

I wish to create a cavernous environment, however, this will be based on a squared map. To stop the 'walls' from looking too square, and introduce some degree of randomness( that a word?), I wish to deform the faces of the cubes by random amounts to appear more natural. This doesn't need to be especially fast, as it will be done and finished with upon initial level creation.

In fact, if I am not using primitive cubes, then just the outward facing quads need to be created. The main problem, is ensuring the angles of tris at the edges of adjacent quads match up. I don't want to have gaps.

I have no clue as to how to do any of this :( All my projects so far have relied on 3rd-party meshes and primitives, I wouldnt know where to start on creating my own, nor knowing how to find the angles of each tri.


Rob Farley(Posted 2005) [#4]
This may help.

http://www.blitzbasic.com/codearcs/codearcs.php?code=1120


_PJ_(Posted 2005) [#5]
Doh!

I only looked at that the other day for incorporating into Galactic Allegiance (don't worry, full credit will be given!)

Thanks, Rob!

I should've thought it's the same principle!

Q:
Am I right to assume it is this line that deals with the actual amount of morphing?

VertexCoords as1,nn,vpos(nn,0)+xm,vpos(nn,1)+ym,vpos(nn,2)+zm
			vpos(nn,3)=1



And how do I ensure it will line-up with the verts next-door?

----------edit: just read

The 'clever' bit is it checks all the verts that are joined together first so you don't get cracks and stuff.

!!!


puki(Posted 2005) [#6]
Mmm, I think you need a mesh tube and a sweeping deformation algo - I have seen mesh tubes the code archives before. The hard bit will be doing the algo, but it would make life easier - you'd just sweep through the tube from one end to the other altering the surface - taking into account that you will probably want to make the floor a bit flatter. Creating the algo would be the hardest bit - but you could create more than one to sweep through - maybe flatten the floor first, then re-sweep and make the walls a bit more uneven, another sweep to do stalagmites/stalacties, etc. and maybe, when you have got them all worked out, then combine them into one sweep.

In fact, I think there is a piece of code that deforms a tube into a 'breathing' motion - it might be in the 3D samples folder - I'll take a look.

EDIT:
Yep - "halo" did it 'Mesh deformation demo' (meshfx.bb). Take a look at it - obviously he deforms it uniformally, but you get the idea.


_PJ_(Posted 2005) [#7]
that sounds a bit more complex than I think I need, puki - but thanks!

In fact, to make life easier, the floor can remain flat with some customised meshes. I still dunno if there will actually BE a cieling or not yet. Il have a look at halo's code...

________________________________________________________

um... got a link, there, puki? I searched the code arcs, the tutorials and all sorts for it...


puki(Posted 2005) [#8]
It's in your B3D 3D samples folder in "halo's" folder - it's called 'MeshFX'.


big10p(Posted 2005) [#9]
So, you basically want to do a tile map, but in 3D using cube 'tiles'?

I think the easiest way to ensure that all adjacent cube faces 'fit together' is to have all edge vertices shared with the cube it's touching. That way, any alterations to the edge verts will automatically deform the cube face it's touching. If you see what I mean. :P


BlackJumper(Posted 2005) [#10]
I would recommend that you have a look at big10p's exploding mesh demo in the code arcs...

http://www.blitzbasic.com/codearcs/codearcs.php?code=680

The code contains a function to subdivide a mesh. {Strictly speaking it makes an unwelded copy of the mesh and subdivides that to a user-controlled degree.} I have managed to get this to operate on B3D primitives by looping through the surfaces and vertices... here to individually colour each face:
Case 6
	shape = CreateCube()
	EntityFX shape, 2
			
	DebugLog "surfaces of cube = " + CountSurfaces(shape)

	For n = 1 To CountSurfaces(shape)
		surf = GetSurface(shape, n)
		DebugLog n + "    number vertices = " + CountVertices(surf)
		verts = CountVertices(surf)

		For v = 0 To CountVertices(surf)
			Select Int(v / 4)
				Case 1 VertexColor surf, v, 0, 0, 255
				Case 2 VertexColor surf, v, 0, 255, 0
				Case 3 VertexColor surf, v, 255, 0, 0
				Case 4 VertexColor surf, v, 255, 255, 0
				Case 6 VertexColor surf, v, 255, 0, 255
				Case 0 VertexColor surf, v, 0, 255, 255
				End Select

			Next
		Next
				
		UpdateNormals shape


However, it may just be simplest to create your own primitives from the outset. Dave Bird has code in the codearcs to create a cube from six faces.


Stevie G(Posted 2005) [#11]
Take a look at bezier patches if you would like the scene to be more organic. There are a few good tuts on GameDev. Basically you set up 9 control points per cube face and then create a patch using interpolation.


_PJ_(Posted 2005) [#12]
Hmm all still seems a little involved. Il have a go and see what I can do!
Thanks, peeps!


_PJ_(Posted 2005) [#13]
Puki - I am currently having to work from just the demo version of B3D until I get my computer set up at home. The demo version doesnt have that file included unfortunately.

Stevie G, I understand Beziers are like smooth curves. I think I see what you mean, and yeah, the end result would make some great looking caverns, but it's way beyond my capabilities right now!

I combined Rob Farley's "Asteroid" code, and Dave Bird's "Segmented Cube" code, but it only seems to deform one face (typically the one facing vertically down), Not too sure what to do with it. Sorry I know Im being a pain with this, I never realised such a simple concept could get so involved!

Here's what I have so far:



_________________________________EDIT__________________________________



Ive amended the code. Ive kinda got it sussed, only because CopyMesh would need retexturing and remorphing, and CopyEntity would result in identical blocks, I have simply created a new block for every map position. This shouldnt be much of a problem, graphics memory wise, and I hope to occlude more distant blocks eventually for rendering speeds etc. As I trial, I am quite pleased so far, although I still need to determine how to match the split edges up...


Stevie G(Posted 2005) [#14]
Malice,

Why not addmesh a clump of deformed cubes? The way your doing this would generate far too many surfaces which would be a frame rate killer!!


puki(Posted 2005) [#15]
Don't alter the verts at the edges is your answer.

However, if you want uneven edges then you will have to see where vertices pair and them move them accordingly. You can automate this - but you'll probably have to sit there working out the coords. Once you have paired them - you are laughing.

Try doing it manually first. Just create a 2-sided cube and work on how you can alter the edge of one face first - then look at how you have to move the edge of the adjoining side to join it - you'll see a pattern (in 3D space) - once you have worked out the pattern you can automate it - you then just optimise it for the other sides (assuming you retain your 'block' structure).

Ps - "StevieG" is right - you might consider a cube structure with 2 sides facing inwards and build your levels that way - you may not need to be using 4 sides - depends on what you have on the other side of the walls.


_PJ_(Posted 2005) [#16]
Yeah, seeing as the texture will always be the same for these 'cubes', minimising the surface count with AddMesh should be better.

Yeah, Optimising the cubes with regaards to non-visible faces is also an important consideration. Especially the top and bottom of the 'cubes' these I think will never be seen.

puki, the idea of pairing the verts is something I wouldn't know where to start, especially considering the random nature of the deformations. Not affecting the tris along the edge did cross my mind, but then the meshes would lose a lot of their 'caverny' feeling.

Here's my code so far, with step-by-step movement and torchlighting (the code needs two texture files in the root folder t.bmp and floor.bmp)

Graphics3D 800,600

SetBuffer BackBuffer()


;*****************************INITIALISE******************************

AmbientLight 150,150,150

cam=CreateCamera()

CameraViewport cam,0,0,800,600
CameraRange cam,0.01,100

CameraFogMode cam,1
CameraFogColor cam,1,1,1
CameraFogRange cam,-20,20


camlight=CreateLight(2)
EntityParent camlight,cam,1

LightRange camlight,1
;****************************BUILD ARRAYS *****************************

Dim vpos#(1,1)
Dim Map(200)

;***************************CREATE QUICK RANDOM MAP**********************


Fl=CreatePlane()
MoveEntity fl,0,-1,0
ft=LoadTexture("floor.bmp",1)

EntityTexture Fl,ft


	For f= 1 To 200

		Map(f)=CreateWall()
		
			If f>1
				AddMesh Map(f),Map(f-1)
			EndIf
		
		tt=LoadTexture("t.bmp",9)

		EntityTexture Map(f),tt
		
		Morph(Map(f))
				
		PositionEntity Map(f),Rand(-15,15),0,Rand(-15,15)
	Next

;*************************** MAIN LOOP ****************************

timer=MilliSecs()

While Not KeyDown(1)

If KeyDown(200) Then walkforward(cam)
If KeyDown(208) Then walkbackward(cam)

If KeyDown(203) Then turnleft(cam)
If KeyDown(205) Then turnright(cam)


;*************************TORCHLIGHT*******************************
LightColor camlight,Rand(150,200),Rand(170,220),100

;*************************COUNT FRAMES*****************************

fpscount=fpscount+1

	If (MilliSecs()-timer)>=1000
		timer=MilliSecs()
		fps=fpscount
		fpscount=0
	EndIf

render()

Wend
End

;*******************************************FUNCTIONS************************




Function walkforward(entity)

For f= 1 To 10 

MoveEntity entity,0,0,0.1

render()

Next
End Function




Function walkbackward(entity)

For f=1 To 10

MoveEntity entity,0,0,-.1

render()

Next
End Function


Function turnleft(entity)

For f=1 To 20

TurnEntity entity,0,4.5,0

render()

Next

End Function


Function turnright(entity)

For f=1 To 20

TurnEntity entity,0,-4.5,0

render()

Next

End Function







Function CreateWall()

;*****************************CREATE SEGMENTED CUBE FROM 6 SIDES **************

	mesh=CreateMesh()
	
	segs=3
	
	For scnt=0 To 3
		surf=CreateSurface( mesh )
		stx#=-.5
		sty#=stx
		stp#=Float(1)/Float(segs)
		y#=sty
		For a=0 To segs
			x#=stx
			v#=a/Float(segs)
			For b=0 To segs
				u#=b/Float(segs)
				AddVertex(surf,x,y,0.5,u,v)
				x=x+stp
			Next
			y=y+stp
		Next
		For a=0 To segs-1
			For b=0 To segs-1
				v0=a*(segs+1)+b:v1=v0+1
				v2=(a+1)*(segs+1)+b+1:v3=v2-1
				AddTriangle( surf,v0,v1,v2 )
				AddTriangle( surf,v0,v2,v3 )
			Next
		Next
		RotateMesh mesh,0,90,0
	Next
	;top and bottom
	RotateMesh mesh,90,0,0
	For scnt=0 To 1
		surf=CreateSurface( mesh )
		stx#=-.5
		sty#=stx
		stp#=Float(1)/Float(segs)
		y#=sty
		For a=0 To segs
			x#=stx
			v#=a/Float(segs)
			For b=0 To segs
				u#=b/Float(segs)
				AddVertex(surf,x,y,0.5,u,v)
				x=x+stp
			Next
			y=y+stp
		Next
		For a=0 To segs-1
			For b=0 To segs-1
				v0=a*(segs+1)+b:v1=v0+1
				v2=(a+1)*(segs+1)+b+1:v3=v2-1
				AddTriangle( surf,v0,v1,v2 )
				AddTriangle( surf,v0,v2,v3 )
			Next
		Next
		RotateMesh mesh,180,0,0
	Next
	UpdateNormals mesh

Return mesh
End Function


;**************************MORPH VERTS*****************************

Function Morph(mesh)

surftotal=CountSurfaces(mesh)

For xx= 1 To surftotal
as1=GetSurface(mesh,xx)

; record the locations of the verts
Dim vpos#(CountVertices(as1)-1,3)
For n=0 To CountVertices(as1)-1
	vpos(n,0)=VertexX(as1,n)
	vpos(n,1)=VertexY(as1,n)
	vpos(n,2)=VertexZ(as1,n)
	vpos(n,3)=0
Next

For n=0 To CountVertices(as1)-1

; change these to make it more or less messy
xm#=Rnd(-.2,.2)
ym#=Rnd(-.0,.0)
zm#=Rnd(-.2,.2)

	For nn=0 To CountVertices(as1)-1
	
	; if the vert has not been monkeyed with monkey away
	If vpos(nn,3)=0
		If vpos(n,0)=vpos(nn,0) And vpos(n,1)=vpos(nn,1) And vpos(n,2)=vpos(nn,2)
			VertexCoords as1,nn,vpos(nn,0)+xm,vpos(nn,1)+ym,vpos(nn,2)+zm
			vpos(nn,3)=1
			EndIf
		EndIf
		
	Next
Next

Next

Return mesh

End Function


Function render()

UpdateWorld
RenderWorld

Text 0,100,"POLYS: "+TrisRendered(),0,1

Text 0,200,"FPS: "+fps,0,1


Flip

End Function



----------------Now I seem to have a problem that the 'timer' variable doesn't = millisecs at the start(?) it maintains a 'null' value, so my framecounter doesn't work here.


Stevie G(Posted 2005) [#17]
At a glance you haven't made FPS global so will be 0 in the render function.


_PJ_(Posted 2005) [#18]
That was it! Cheers! This is also my first real use of Functions, Ive usually jsut repeated code or used *eek!* subroutines. (bad programmer bad programmer) So not being able to declare the vars unless outside the routines is taking a little getting used to. Still Im getting there!

I've removed the (kindly anotated) mesh building section for the top and bottom of the walls, which helps a lot. I notice the Tris are still rendered even if invisible due to camera fog, this seems a little pointless, but I need to work on an occlusion routine anyway... oh well... no rest for the wicked...