// Last updated 16/02/05 // // Blaze 3D Actionscript code to allow an 'around and over' navigation paradigm ideal for automotive applications. // Simply copy and paste into the 3D MovieClip and modify the top 4 variable values as desired onClipEvent (load) { ZOOM_MINDIST = 3000; //closest the camera can get to the origin ZOOM_MAXDIST = 12000; //furthest the camera can get from the origin ROTX_SPEED = 0.55; //determines how much an x mouse movement will rotate the camera ROTY_SPEED = 0.55; //determines how much a y mouse movement will rotate the camera bAllowPan = false; stageWidth = 550; stageHeight = 400; xProjectionCentre = this._x; yProjectionCentre = this._y; omousex = _root._xmouse; omousey = _root._ymouse; //mouse velocities velx = 0; vely = 0; //control panel velocities xRot = 0; yRot = 0; xPan = 0; yPan = 0; zoom = 0; xRotMax = 10; yRotMax = 10; velocityDecayRate = Math.exp(0.17); //it's the velocity decay rate - don't set to zero rotatePoint = new Vector3d(); mouseState = 0; STOP_STATE = 0; DRAG_STATE = 1; DECAY_STATE = 2; PANELDRAG_STATE = 3; PANELDECAY_STATE = 4; movementState = STOP_STATE; ROTATE_MOVETYPE = 1; ZOOM_MOVETYPE = 2; PAN_MOVETYPE = 3; movementType = 0; ROTXU_PANELBUTTON = 0; ROTXD_PANELBUTTON = 1; ROTYL_PANELBUTTON = 2; ROTYR_PANELBUTTON = 3; PANXL_PANELBUTTON = 4; PANXR_PANELBUTTON = 5; PANYU_PANELBUTTON = 6; PANYD_PANELBUTTON = 7; ZOOMIN_PANELBUTTON = 8; ZOOMOUT_PANELBUTTON = 9; panelButton = 0; buttonPressed = false; //Added this buttonPressed flag in case buttonPress and buttonRelease occur in same frame - always PANELDRAG gotoposMatrix = new Matrix3d(); gotoposFrames = 0; gotoposActive = false; gotoposStart = false; halfPi = 90; lowerAngleLimit = 30; //Angle from lower vertical allowed upperAngleLimit = 5; //Angle from upper vertical allowed radToDeg = 180/3.1415; degToRad = 1/radToDeg; allowNav = true; } onClipEvent (mouseUp) { // update mouseState here whether in render window or not so we stop dragging mouseState = getMouseButtons(); if (!bAllowPan && mouseState==3) mouseState = 1; //Both buttons same as left button if (movementState == DRAG_STATE && mouseState==0) movementState = DECAY_STATE; if (movementState == DRAG_STATE || movementState == STOP_STATE) { movementType = mouseState; } omousex = _root._xmouse; omousey = _root._ymouse; } onClipEvent (mouseDown) { if (this.hitTest(_root._xmouse, _root._ymouse, 0)) //mouse inside render window { mouseState = getMouseButtons(); if (!bAllowPan && mouseState==3) mouseState = 1; //Both buttons same as left button if (mouseState!=0) //if mouseState == 0 after a mouseDown event, //it means that the event was handled by the flash player, so do nothing { //only stop if the movement is a different sort if (mouseState != movementType) { movementType = mouseState; movementState = STOP_STATE; } omousex = _root._xmouse; omousey = _root._ymouse; } } } onClipEvent (mouseMove) { if (mouseState!=0) { movementState = DRAG_STATE; } } onClipEvent (enterFrame) { cameraObj = getCamera(); if (gotoposStart) { gotoposMatrix = new Matrix3d(gotoposMatrix); //kill off any momentum movementState = STOP_STATE; //allow for not pointing at the origin //removing pan component //find the centre of rotation in the frame of the camera inverseMatrix = gotoposMatrix.inverse(); rotationPointInCameraFrame = inverseMatrix.multiply(rotatePoint); toDx = rotationPointInCameraFrame.x; toDy = rotationPointInCameraFrame.y; adx = toDx*gotoposMatrix.m00 + toDy*gotoposMatrix.m10; ady = toDx*gotoposMatrix.m01 + toDy*gotoposMatrix.m11; adz = toDx*gotoposMatrix.m02 + toDy*gotoposMatrix.m12; gotoposMatrix.translate(adx, ady, adz); //Store altered gotoposMatrix toVector = new Vector3d(gotoposMatrix.m30, gotoposMatrix.m31, gotoposMatrix.m32); toUpVector = new Vector3d(gotoposMatrix.m10, gotoposMatrix.m11, gotoposMatrix.m12); toAimVector = new Vector3d(gotoposMatrix.m20, gotoposMatrix.m21, gotoposMatrix.m22); toRadius = toVector.length(); toVector.normalize(); gotoposStart = false; gotoposActive = true; } if (gotoposActive) { //check for meaningless gotoposFrames if (gotoposFrames<1) gotoposFrames = 1; fromMatrix = new Matrix3d(cameraObj.matrix); //Remove pan component //find the centre of rotation in the frame of the camera inverseMatrix = fromMatrix.inverse(); rotationPointInCameraFrame = inverseMatrix.multiply(rotatePoint); dx = rotationPointInCameraFrame.x; dy = rotationPointInCameraFrame.y; adx = dx*fromMatrix.m00 + dy*fromMatrix.m10; ady = dx*fromMatrix.m01 + dy*fromMatrix.m11; adz = dx*fromMatrix.m02 + dy*fromMatrix.m12; fromMatrix.translate(adx, ady, adz); //Now work on altered matrix fromVector = new Vector3d(fromMatrix.m30, fromMatrix.m31, fromMatrix.m32); fromUpVector = new Vector3d(fromMatrix.m10, fromMatrix.m11, fromMatrix.m12); fromAimVector = new Vector3d(fromMatrix.m20, fromMatrix.m21, fromMatrix.m22); fromRadius = fromVector.length(); //translation //get polar position dot = fromVector.dot(toVector); //sometimes came out as greater than fromRadius and caused problem in Math.acos function if (dot>fromRadius) dot = fromRadius; else if (dot<-fromRadius) dot = -fromRadius; translationPolarAngle = Math.acos(dot/fromRadius); //fromVector is not normalized //new polar position translationPolarAngle -= translationPolarAngle/gotoposFrames; radiusToGo = toRadius - fromRadius; fromRadius += radiusToGo/gotoposFrames; //set new translation outOfPlaneVector = fromVector.cross(toVector); thirdAxisVector = toVector.cross(outOfPlaneVector); thirdAxisVector.normalize(); cosAngle = Math.cos(translationPolarAngle); sinAngle = Math.sin(translationPolarAngle); fromMatrix.m30 = fromRadius*cosAngle*toVector.x + fromRadius*sinAngle*thirdAxisVector.x; fromMatrix.m31 = fromRadius*cosAngle*toVector.y + fromRadius*sinAngle*thirdAxisVector.y; fromMatrix.m32 = fromRadius*cosAngle*toVector.z + fromRadius*sinAngle*thirdAxisVector.z; //new aim vector... always point at origin fromAimVector.x = - fromMatrix.m30; fromAimVector.y = - fromMatrix.m31; fromAimVector.z = - fromMatrix.m32; fromAimVector.normalize(); fromMatrix.m20 = fromAimVector.x; fromMatrix.m21 = fromAimVector.y; fromMatrix.m22 = fromAimVector.z; //new up vector... fromUpVector.x = fromUpVector.x + (toUpVector.x - fromUpVector.x)/gotoposFrames; fromUpVector.y = fromUpVector.y + (toUpVector.y - fromUpVector.y)/gotoposFrames; fromUpVector.z = fromUpVector.z + (toUpVector.z - fromUpVector.z)/gotoposFrames; //x vector... xVector = fromUpVector.cross(fromAimVector); xVector.normalize(); fromMatrix.m00 = xVector.x; fromMatrix.m01 = xVector.y; fromMatrix.m02 = xVector.z; //actual up vector fromUpVector = fromAimVector.cross(xVector); fromUpVector.normalize(); fromMatrix.m10 = fromUpVector.x; fromMatrix.m11 = fromUpVector.y; fromMatrix.m12 = fromUpVector.z; //Now translate back to account for pan newDx = dx + (toDx - dx)/gotoposFrames; newDy = dy + (toDy - dy)/gotoposFrames; adx = -newDx*fromMatrix.m00 - newDy*fromMatrix.m10; ady = -newDx*fromMatrix.m01 - newDy*fromMatrix.m11; adz = -newDx*fromMatrix.m02 - newDy*fromMatrix.m12; fromMatrix.translate(adx, ady, adz); //set new camera matrix... cameraObj.matrix = fromMatrix; gotoposFrames -= 1; if (gotoposFrames==0) gotoposActive = false; } if (movementState==STOP_STATE) { velx = 0; vely = 0; xRot = 0; yRot = 0; xPan = 0; yPan = 0; zoom = 0; } else if (allowNav) { //trace(cameraObj.matrix); if (buttonPressed || movementState==PANELDRAG_STATE) { xPanMax = stageWidth/30; yPanMax = stageHeight/30; zoomMax = (ZOOM_MAXDIST - ZOOM_MINDIST)/30; if (panelButton==ROTXD_PANELBUTTON) { xRot += xRotMax/10; if (xRot>xRotMax) xRot = xRotMax; movementType = ROTATE_MOVETYPE; } else if (panelButton==ROTXU_PANELBUTTON) { xRot -= xRotMax/10; if (xRot<-xRotMax) xRot = -xRotMax; movementType = ROTATE_MOVETYPE; } else if (panelButton==ROTYL_PANELBUTTON) { yRot += yRotMax/10; if (yRot>yRotMax) yRot = yRotMax; movementType = ROTATE_MOVETYPE; } else if (panelButton==ROTYR_PANELBUTTON) { yRot -= yRotMax/10; if (yRot<-yRotMax) yRot = -yRotMax; movementType = ROTATE_MOVETYPE; } else if (panelButton==ZOOMIN_PANELBUTTON) { zoom -= zoomMax/10; if (zoom<-zoomMax) zoom = -zoomMax; movementType = ZOOM_MOVETYPE; } else if (panelButton==ZOOMOUT_PANELBUTTON) { zoom += zoomMax/10; if (zoom>zoomMax) zoom = zoomMax; movementType = ZOOM_MOVETYPE; } else if (panelButton==PANXR_PANELBUTTON) { xPan += xPanMax/10; if (xPan>xPanMax) xPan = xPanMax; movementType = PAN_MOVETYPE; } else if (panelButton==PANXL_PANELBUTTON) { xPan -= xPanMax/10; if (xPan<-xPanMax) xPan = -xPanMax; movementType = PAN_MOVETYPE; } else if (panelButton==PANYU_PANELBUTTON) { yPan -= yPanMax/10; if (yPan<-yPanMax) yPan = -yPanMax; movementType = PAN_MOVETYPE; } else if (panelButton==PANYD_PANELBUTTON) { yPan += yPanMax/10; if (yPan>yPanMax) yPan = yPanMax; movementType = PAN_MOVETYPE; } buttonPressed = false; } else if (movementState == PANELDECAY_STATE) { zoom /= velocityDecayRate; xRot /= velocityDecayRate; yRot /= velocityDecayRate; xPan /= velocityDecayRate; yPan /= velocityDecayRate; if (Math.abs(xRot)<0.001 && Math.abs(yRot) < 0.001 && Math.abs(zoom)<0.001 && Math.abs(xPan)<0.001 && Math.abs(yPan)<0.001) { movementState = STOP_STATE; } } else if (movementState==DRAG_STATE) { mousex = _root._xmouse; mousey = _root._ymouse; velx = 0.6*velx+0.4*(mousex-omousex); vely = 0.6*vely+0.4*(mousey-omousey); //To stop moving with zero speed if (Math.abs(velx) < 0.1 && Math.abs(vely) < 0.1) { movementState = STOP_STATE; } omousex = mousex; omousey = mousey; } else if (movementState==DECAY_STATE) { velx /= velocityDecayRate; vely /= velocityDecayRate; if (Math.abs(velx) < 0.1 && Math.abs(vely) < 0.1) { movementState = STOP_STATE; } } if (movementState != STOP_STATE) { //Get camera position matrix cameraMatrix = new Matrix3d(cameraObj.matrix); //find the centre of rotation in the frame of the camera inverseMatrix = cameraMatrix.inverse(); rotationPointInCameraFrame = inverseMatrix.multiply(rotatePoint); if (movementType == ROTATE_MOVETYPE) { if (movementState == PANELDRAG_STATE || movementState == PANELDECAY_STATE) { xang = yRot; yang = xRot; } else { xang = -velx*ROTX_SPEED; yang = -vely*ROTY_SPEED; } //Limit movement yaxis = new Vector3d(cameraMatrix.m10, cameraMatrix.m11, cameraMatrix.m12); zaxis = new Vector3d(cameraMatrix.m20, cameraMatrix.m21, cameraMatrix.m22); ylength = yaxis.length(); yAngToGlobY = Math.acos(cameraMatrix.m11/ylength)*radToDeg; //angle of y axis to global y if((yAngToGlobY-yang>halfPi-upperAngleLimit) && yang<0 && cameraMatrix.m21<0) { if(yAngToGlobYhalfPi-lowerAngleLimit) && yang>0 && cameraMatrix.m21>0) { if(yAngToGlobYZOOM_MINDIST)?dx*(zDistFromCamera - ZOOM_MINDIST)/(zDistFromCamera-newZDistFromCamera):0.0; dy = (zDistFromCamera>ZOOM_MINDIST)?dy*(zDistFromCamera - ZOOM_MINDIST)/(zDistFromCamera-newZDistFromCamera):0.0; dz = (zDistFromCamera>ZOOM_MINDIST)?dz*(zDistFromCamera - ZOOM_MINDIST)/(zDistFromCamera-newZDistFromCamera):0.0; vely = 0.0; zoom = 0; } else if (newZDistFromCamera > ZOOM_MAXDIST && dz > 0.0) { //if dz>0.0 dx==dy==0.0; dz = (zDistFromCamera0)?dx*midx/(midx-newmidx):0.0; velx = 0.0; xPan = 0; } else if (newmidx > stageWidth && dx > 0.0) { dx = (midx 0.0) { dy = (midy>0)?dy*midy/(midy-newmidy):0.0; vely = 0.0; yPan = 0; } else if (newmidy > stageHeight && dy < 0.0) { dy = (midy