mesh transform problem

Blitz3D Forums/Blitz3D Programming/mesh transform problem

Rob(Posted 2003) [#1]
Hi lads,

Given two 3D coordinates in world space, how can we stretch a quad between them retaining thickness and yet rotate the points of the quad in such a way that it doesn't backface at any time, nor lose it's retangular form.

I am deforming the verts of a single surface quad to stretch between two pivots. A bit like a lightsaber effect. It has to be done by mesh vert manipulation.

As you know, it has to avoid backface culling. EntityFx 16 is just a waste we can avoid here.

I believe TformVector or point can help me achieve this goal. Any help/tips you can give will be appreciated lads!


Floyd(Posted 2003) [#2]
Hmmm... trying to visualize this:

The 'front' of a triangle is relative to the camera.
So the first step must to be to transform everything to camera space.

How about this. Use another pivot in the same location as the camera.
Aim it at one of the two target pivots.
Now rotate this 'camera pivot' around it's z-axis until the two
targets are on a horizontal line in camera pivot space.
They will both have y-coordinates equal to zero.

As seen from the camera pivot the targets are in front, on the same y level.
The four corners of a stretched quad would be slightly above and below the targets.
i.e. just add or subtract a little from the target y-coordinates (in camera pivot space).

Transform the results back into quad space and you are done.

You need to fill in some details here. But the idea sounds right.


Floyd(Posted 2003) [#3]
Here's a demo of the tricky part, rotating by the right amount.
It actually turns the camera rather than a 'camera pivot' so we can see the results.
; Tap a key to step through demo. Escape quits.

; 1. random positions
; 2. aim at red
; 3. turn so green is to the right

Graphics3D 640, 480, 32, 1

p1 = CreateSphere() : EntityColor p1, 255,0,0
p2 = CreateSphere() : EntityColor p2, 0,255,0

cam = CreateCamera()
Repeat

	PositionEntity p1,  Rnd(-4,4), Rnd(-4,4), 10 + Rnd(0,5)
	PositionEntity p2,  Rnd(-4,4), Rnd(-4,4), 10 + Rnd(0,5)
	
	RenderWorld : Flip : WaitKey  ; random
	
	PointEntity cam, p1
	
	RenderWorld : Flip : WaitKey  ; aim at red
	
	TFormPoint EntityX(p2,True), EntityY(p2,True), EntityZ(p2,True), 0, cam
	angle# = ATan2( TFormedY(), TFormedX() )
	
	TurnEntity cam, 0, 0, angle      ; After this we are aiming at red sphere
	RenderWorld : Flip : WaitKey     ; with green sphere to the right.
	
Until KeyHit(1)



Rob(Posted 2003) [#4]
Thanks for the help! Still a bit confused though. What do you mean by transforming back? Not sure how to in order to get a useful result... transform the camerapivot...


Rob(Posted 2003) [#5]
Basically trying to make a useful line using quads without skewing, and retaining thickness.


skidracer(Posted 2003) [#6]
problem - given p0,p1 two pivots in 3space calculate e0,e1 vectors that represent the end edges of a quad streteched between p0,p1 facing camera so 4 verts of quad in global space are positioned at p0+e0,p1+e1,p1-e1,p0-e0

solution - the vector e0 needs to be at a tangent to the vector p1-p0 and the vector camera-p0 (similarly e1 is normal to p0-p1 cam-p1) so won't that just involve a single cross product for each end?


Rob(Posted 2003) [#7]
Thanks for that skid, it seems logical although I haven't a single clue how to do it. But here's hoping I'll blunder my way to success.


skidracer(Posted 2003) [#8]
Just experimenting now, been meaning to have a hack at this for some time...


skidracer(Posted 2003) [#9]
Haven't tested with moving camera so may not be quite there yet. A lot of stuff in UpdateWireMesh could be precalculated in wire type if wires are not too dynamic.

; wired.bb

; 3d wire frame system
; wires are lines in 3D space with start and end widths
; CreateWireMesh creates single surface mesh with quad per wire
; UpdateWireMesh positions wire quad so as to face the camera

Type wire
	Field x0#,y0#,z0#,w0#
	Field x1#,y1#,z1#,w1#
End Type

Function CreateWire.wire(x0#,y0#,z0#,w0#,x1#,y1#,z1#,w1#)
	w.wire=New wire
	w\x0=x0
	w\y0=y0
	w\z0=z0
	w\w0=w0
	w\x1=x1
	w\y1=y1
	w\z1=z1
	w\w1=w1
End Function

Function CreateWireMesh()
	m=CreateMesh()
	EntityFX m,16 ;double sided flag so no tricky flip testing required
	s=CreateSurface(m,b)	
	For w.wire=Each wire
		AddVertex s,0,0,0,0,0
		AddVertex s,0,0,0,1,0
		AddVertex s,0,0,0,1,1
		AddVertex s,0,0,0,0,1
		AddTriangle s,v+0,v+1,v+2
		AddTriangle s,v+0,v+2,v+3
		v=v+4
	Next
	Return m
End Function

Function UpdateWireMesh(cam,mesh)
	s=GetSurface(mesh,1)
	camx#=EntityX(cam)
	camy#=EntityY(cam)
	camz#=EntityZ(cam)
		
	For w.wire=Each wire

		px#=w\x1-w\x0
		py#=w\y1-w\y0
		pz#=w\z1-w\z0
		l#=1.0/Sqr(px*px+py*py+pz*pz)
		px=px*l
		py=py*l
		pz=pz*l

		cx#=w\x0-camx
		cy#=w\y0-camy
		cz#=w\z0-camz
		l#=1.0/Sqr(cx*cx+cy*cy+cz*cz)
		cx=cx*l
		cy=cy*l
		cz=cz*l
		
		l=w\w0
		ex#=l*(py*cz-pz*cy)
		ey#=l*(-px*cz+pz*cx)
		ez#=l*(py*cx+px*cy)
	
		VertexCoords s,v+0,w\x0+ex,w\y0+ey,w\z0+ez
		VertexCoords s,v+3,w\x0-ex,w\y0-ey,w\z0-ez

		cx#=w\x1-camx
		cy#=w\y1-camy
		cz#=w\z1-camz
		l#=1.0/Sqr(cx*cx+cy*cy+cz*cz)
		cx=cx*l
		cy=cy*l
		cz=cz*l

		l=w\w1
		ex=l*(py*cz-pz*cy)
		ey=l*(-px*cz+pz*cx)
		ez=l*(py*cx+px*cy)

		VertexCoords s,v+1,w\x1+ex,w\y1+ey,w\z1+ez
		VertexCoords s,v+2,w\x1-ex,w\y1-ey,w\z1-ez
		v=v+4
	Next
End Function

Graphics3D 1024,768

; front square
CreateWire(-100,100,200,1, 100,100,200,1)
CreateWire(-100,-100,200,1, 100,-100,200,1)
CreateWire(-100,-100,200,1, -100,100,200,1)
CreateWire(100,100,200,1, 100,-100,200,1)
; side lines
CreateWire(-100,-100,200,1, -100,-100,-200,1)
CreateWire(100,-100,200,1, 100,-100,-200,1)
CreateWire(100,100,200,1, 100,100,-200,1)
CreateWire(-100,100,200,1, -100,100,-200,1)
; back square
CreateWire(-100,100,-200,1, 100,100,-200,1)
CreateWire(-100,-100,-200,1, 100,-100,-200,1)
CreateWire(-100,-100,-200,1, -100,100,-200,1)
CreateWire(100,100,-200,1, 100,-100,-200,1)

mesh=CreateWireMesh()
cam=CreateCamera()

While Not KeyHit(1)
	TurnEntity cam,0,1,.3
	UpdateWireMesh(cam,mesh)
	UpdateWorld
	RenderWorld
	Flip
Wend

End



skidracer(Posted 2003) [#10]
and try adding this after the CreateWireMesh for antialiased lines (need to double the end widths for best effect):

tube=CreateTexture(1,4,4)
brush=CreateBrush()
BrushTexture brush,tube
t=TextureBuffer(tube)
WritePixel 0,0,0,t
WritePixel 0,1,-1,t
WritePixel 0,2,-1,t
WritePixel 0,3,0,t
PaintMesh mesh,brush



Rob(Posted 2003) [#11]
Thats the business simon! There are issues when you look outside the wireframe box though.

It's pretty awesome having aa wireframes! Any chance of doing a bit more work on this for us? it's a god send for all aspiring tron programmers!


skidracer(Posted 2003) [#12]
The resulting width is a little varied so will hopefully come up with better maths soon.


John Pickford(Posted 2003) [#13]
I may be missing the point a bit but why not just transform the 3D coords into 2D then draw wires with a 2D in 3D solution? Each line could be just stretched 2D quad facing the camera (perhaps in orthographic mode) and you'll get perfect fixed width wires. Use a nice alpha mapped texture and you can get a nice glow on the lines.


Rob(Posted 2003) [#14]
I like that solution but we lose z, meaning the wires are always visible - even behind other objects. At the moment, I can put an original source object inside the wire cage if I want.


John Pickford(Posted 2003) [#15]
Fairy Nuff


Rob(Posted 2003) [#16]
*sneaky pointless bump*