I reworked my old Frustum code for the terrain engine project.
This code is much faster than Microsoft's method.
They calculate the frustum vertices, then use them to obtain planes.
This version extracts planes directly from the combined view/proj matrix.
You can obtain planes AND/OR vertices with this version, depending apon your project's requirements.

If you can see any way to further optimize this code please tell me !!


;The following code is used to extract the "view frustum"
;from the current view and proj matrices
;
;UpdateFrustum is your common entrypoint procedure
;Its parameters are:
;bWantVertices - Want the frustum bounding vertices? True or False
;bWantPlanes - Want the frustum bounding planes? True or False
;pmatView - Pointer to the current View matrix
;pmatProj - Pointer to the current Projection matrix
;pOutputVertices - Pointer to 8 x Vec3 output
;pOutputPlanes - Pointer to 6 x Plane output (see Frustum struct)
;


;We describe a Plane with a Normal and Distance
Plane struct
   vNormal Vec3 <>
   fDistance REAL4 ?
Plane ends

; We describe a Frustum as SIX PLANES
Frustum struct
plLeft Plane <>
plRight Plane <>
plTop Plane <>
plBottom Plane <>
plNear Plane <>
plFar Plane <>
Frustum ends

;Just some helper macros for simple vector math
vecadd macro pvout:req, pv1in:req, pv2in:req
fld  pv1in
fadd pv2in
fstp pvout
endm

vecsub macro pvout:req, pv1in:req, pv2in:req
fld  pv1in
fsub pv2in
fstp pvout
endm

vecmul macro pvout:req, pv1in:req, pv2in:req
fld  pv1in
fmul pv2in
fstp pvout
endm


.data
;This describes a UNIT CUBE which we will
;deform to calculate frustum corner vertices
FrustumUn Vec3 <-1.0f, -1.0f,  0.0f>
Vec3 < 1.0f, -1.0f,  0.0f>
Vec3 <-1.0f,  1.0f,  0.0f>
Vec3 < 1.0f,  1.0f,  0.0f>
Vec3 <-1.0f, -1.0f,  1.0f>
Vec3 < 1.0f, -1.0f,  1.0f>
Vec3 <-1.0f,  1.0f,  1.0f>
Vec3 < 1.0f,  1.0f,  1.0f>


.code
Vec3Normalize proc uses esi,pVec
LOCAL fdenom
mov esi,pVec
assume esi:ptr Vec3

;Calculate denominator
fld1
fld  .X
fmul .X
fld  .Y
fmul .Y
fld  .Z
fmul .Z
fadd
fadd
fdiv
fstp fdenom
;Multiply vector components by denom
vecmul .X, .X, fdenom
vecmul .Y, .Y, fdenom
vecmul .Z, .Z, fdenom

assume esi:nothing
ret
Vec3Normalize endp

;This procedure extracts the PLANES of the view frustum
;from the current Projection and View matrices
ExtractFrustumPlanesFromView proc uses edi esi, pmatComb, pFrustPlanes

mov edi,pFrustPlanes
mov esi,pmatComb
assume edi:ptr Frustum
assume esi:ptr D3DXMATRIX

;Get Left clipping plane
vecadd .plLeft.vNormal.X, .m03, .m00
vecadd .plLeft.vNormal.Y, .m13, .m10
vecadd .plLeft.vNormal.Z, .m23, .m20
vecadd .plLeft.fDistance, .m33, .m30

;Get Right clipping plane
vecsub .plRight.vNormal.X, .m03, .m00
vecsub .plRight.vNormal.Y, .m13, .m10
vecsub .plRight.vNormal.Z, .m23, .m20
vecsub .plRight.fDistance, .m33, .m30

;Get Top clipping plane
vecsub .plTop.vNormal.X, .m03, .m01
vecsub .plTop.vNormal.Y, .m13, .m11
vecsub .plTop.vNormal.Z, .m23, .m21
vecsub .plTop.fDistance, .m33, .m31

;Get Bottom clipping plane
vecadd .plBottom.vNormal.X, .m03, .m01
vecadd .plBottom.vNormal.Y, .m13, .m11
vecadd .plBottom.vNormal.Z, .m23, .m21
vecadd .plBottom.fDistance, .m33, .m31

;Get Near clipping plane
m2m .plNear.vNormal.X, .m02
m2m .plNear.vNormal.Y, .m12
m2m .plNear.vNormal.Z, .m22
m2m .plNear.fDistance, .m32

;Get Far clipping plane
vecsub .plFar.vNormal.X, .m03, .m02
vecsub .plFar.vNormal.Y, .m13, .m12
vecsub .plFar.vNormal.Z, .m23, .m22
vecsub .plFar.fDistance, .m33, .m32

;Normalize plane normals
invoke Vec3Normalize, addr .plLeft.vNormal
invoke Vec3Normalize, addr .plRight.vNormal
invoke Vec3Normalize, addr .plTop.vNormal
invoke Vec3Normalize, addr .plBottom.vNormal
invoke Vec3Normalize, addr .plNear.vNormal
invoke Vec3Normalize, addr .plFar.vNormal

assume edi:nothing
assume esi:nothing
ret
ExtractFrustumPlanesFromView endp

;This procedure extracts the BOUNDING VERTICES of the view frustrum
;by deforming a Unit Cube with the Inverse of the Combined View and Proj matrices
ExtractFrustumVerticesFromView proc uses esi edi ecx,pInverseComb,pOutputVertices
;Transform the untransformed boundingbox of the Frustrum
;by the inverse view/projection
xor ecx,ecx
lea esi,FrustumUn
mov edi,pOutputVertices
.while ecx<8
push ecx
invoke D3DXVec3TransformCoord, edi,esi, pInverseComb
add esi,sizeof Vec3
add edi,sizeof Vec3
pop ecx
inc ecx
.endw
ret
ExtractFrustumVerticesFromView endp

UpdateFrustum proc bWantVertices,bWantPlanes, pmatView,pmatProj,pOutputVertices, pOutputPlanes
LOCAL matComb:D3DXMATRIX
LOCAL imatComb:D3DXMATRIX

;Calculate the combined projection/view matrix
invoke D3DXMatrixMultiply,addr matComb, pmatView, pmatProj
.if bWantVertices==TRUE
;In order to deform the unit cube for obtaining frustum vertices,
;we need the INVERSE of the aforementioned combined matrix
invoke D3DXMatrixInverse, addr imatComb,NULL, addr matComb
invoke ExtractFrustumVerticesFromView,addr imatComb,pOutputVertices
.endif
.if bWantPlanes==TRUE
invoke ExtractFrustumPlanesFromView,addr matComb, pOutputPlanes
.endif

ret

UpdateFrustum endp

Posted on 2006-01-06 22:31:34 by Homer
Nice code.
Using the FPU there's really no hope for optimization :D

I rewrote one of the functions using SIMD instructions. I noticed that if you rotate the matrix data you can make the job extremely parallel.


;;SSE2 then SSE3 for the normalize code
ExtractFrustumPlanesFromView:
;;ebp+16 = pmatComb
;;ebp+20 = pFrustPlanes
;;trash all xmm0-6 wOOt! for xmm7
;;ASSUMING edi's address is 16byte aligned
push ebp
push esi
push edi
mov ebp,esp
mov esi,
mov edi,
sub esp,16
and esp,0FFFFFFF0h ;; 16byte align the stack
;;make a copy of the matrix rotated 90degrees for sse
;;16 pushes
push ;;col 0
push
push
push      
push ;;col 1
push
push
push
push ;;col 2
push
push
push
push ;;col 3
push
push
push
;;|esp col3 col2 col1 col0|
movdqa xmm3,;;col 3
movdqa xmm2,;;col 2
movdqa xmm1,;;col 1
movdqa xmm0,;;col 0
;;calc and store left and right clip planes
movdqa xmm4,xmm3
movdqa xmm5,xmm3
movdqa xmm6,xmm0
addps xmm4,xmm6
subps xmm5,xmm6
;;if edi is 16byte aligned use dqA instead
movdqa ,xmm4
movdqa ,xmm5
;;calc and store top and bottom
movdqa xmm4,xmm3
movdqa xmm5,xmm3
movdqa xmm6,xmm1
subps xmm4,xmm6
addps xmm4,xmm6
movdqa ,xmm4
movdqa ,xmm5
;;near and far
movdqa ,xmm2;;near
subps xmm3,xmm2
movdqa ,xmm3
;;;NORMALIZING time
;;;SSE3 haddps and movsldup will be used
movdqa xmm6,;;data to mask out dist
;;normals for right left and top
LABEL1: ;;for laziness
movdqa xmm0,
movdqa xmm1,
movdqa xmm2,
andps xmm0,xmm6 ;;no more dst
andps xmm1,xmm6
andps xmm2,xmm6
movdqa xmm3,xmm0 ;;copy
movdqa xmm4,xmm1
movdqa xmm5,xmm2
mulps xmm0,xmm0 ;;x^2 y^2 z^2
mulps xmm1,xmm1
mulps xmm2,xmm2
haddps xmm0,xmm0 ;;x^2+y^2+z^2
haddps xmm1,xmm1
haddps xmm2,xmm2
haddps xmm0,xmm0
haddps xmm1,xmm1
haddps xmm2,xmm2
rsqrtss xmm0,xmm0 ;;1/sqrt
rsqrtss xmm1,xmm1
rsqrtss xmm2,xmm2
movsldup xmm0,xmm0 ;;1/sqrt 1/sqrt 1/sqrt 1/sqrt
movsldup xmm1,xmm1
movsldup xmm2,xmm2
movlhps xmm0,xmm0
movlhps xmm1,xmm1
movlhps xmm2,xmm2
mulps xmm3,xmm0 ;;normalize
mulps xmm4,xmm1
mulps xmm5,xmm2
mov eax, ;; save dists
mov ecx,
mov edx,
movdqa ,xmm3
movdqa ,xmm4
movdqa ,xmm5
mov ,eax
mov ,ecx
mov ,edx
;;NORMALIZE bottom near and far planes
;;I'm not redoing all these indexes into edi
;;Time for a hack job!
add esp,1 ;;I aligned it before
add edi,48
test esp,1
jnz LABEL1
mov esp,ebp
pop edi
pop esi
pop ebp
ret 8
;;data
align 16
NoDist dd -1,-1,-1,0


sorry for the total lack of formating I wrote it in notepad (current time 4:47AM)
at least there's a few comments
Posted on 2006-01-07 03:47:45 by r22