Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
TumblerSource/Tumbler_camera.c
#include <FixMath.h> |
#include "Tumbler_globals.h" |
#include "QD3D.h" |
#include "QD3DDrawContext.h" |
#include "QD3DDrawContext.h" |
#include "QD3DCamera.h" |
#include "QD3DView.h" |
#include "QD3DRenderer.h" |
#include "QD3DGroup.h" |
#include "QD3DMath.h" |
#include "Tumbler_prototypes.h" |
#include "QD3DGeometry.h" |
#include "QD3DLight.h" |
#include "Tumbler_camera.h" |
void GetGroupBBox( |
TQ3ViewObject viewObject, |
TQ3GroupObject mainGroup, |
TQ3GroupObject lightGroup, |
TQ3BoundingBox *viewBBox) |
{ |
TQ3Point3D from = { 0.0, 0.0, 1.0 }; |
TQ3Point3D to = { 0.0, 0.0, 0.0 }; |
TQ3Vector3D up = { 0.0, 1.0, 0.0 }; |
float fieldOfView = .52359333333; |
float hither = 0.5; |
float yon = 1.5; |
TQ3Status status; |
Q3View_StartBoundingBox(viewObject, kQ3ComputeBoundsExact); |
do { |
status = Q3DisplayGroup_Submit(mainGroup, viewObject); |
} while (Q3View_EndBoundingBox(viewObject, viewBBox) == kQ3ViewStatusRetraverse); |
// |
// If we have a point model, then the "viewBBox" would end up |
// being a "singularity" at the location of the point. As |
// this bounding "box" is used in setting up the camera spec, |
// we get bogus input into Escher. |
{ |
float xSize, ySize, zSize; |
xSize = viewBBox->max.x - viewBBox->min.x; |
ySize = viewBBox->max.y - viewBBox->min.y; |
zSize = viewBBox->max.z - viewBBox->min.z; |
if (xSize <= kQ3RealZero && |
ySize <= kQ3RealZero && |
zSize <= kQ3RealZero) { |
viewBBox->max.x += 0.0001; |
viewBBox->max.y += 0.0001; |
viewBBox->max.z += 0.0001; |
viewBBox->min.x -= 0.0001; |
viewBBox->min.y -= 0.0001; |
viewBBox->min.z -= 0.0001; |
} |
} |
} |
#define SIZESCALE 0.03 |
#define POSSCALE 0.5 |
void AdjustLightsPositions( |
DocumentPtr theDocument) |
{ |
#if defined(ESCHER_VER_15) && ESCHER_VER_15 |
TQ3BoundingBox viewBBox; |
TQ3Vector3D diagonalVector, radius; |
TQ3GroupPosition position, lightPosition; |
TQ3Object ellipsoid; |
TQ3Point3D origin; |
float maxDimension; |
TQ3GroupObject lightGroup; |
TQ3LightObject theLight; |
float ratio; |
GetGroupBBox(theDocument->theView, theDocument->documentGroup, nil, &viewBBox); |
Q3Point3D_Subtract(&viewBBox.max, |
&viewBBox.min, |
&diagonalVector); |
maxDimension = Q3Vector3D_Length(&diagonalVector); |
maxDimension *= 8.0 / 7.0; |
ratio = 6.0 / maxDimension; |
/* Adjust the light from the viewer first */ |
Q3View_GetLightGroup(theDocument->theView, &lightGroup); |
Q3Group_GetFirstPosition(lightGroup, &lightPosition); |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
origin.x = -10.0; |
origin.y = 10.0; |
origin.z = 30.0; |
Q3PointLight_SetLocation(theLight, &origin); |
Q3Object_Dispose(theLight); |
/* Set the geometry and the light parameters for the red light */ |
Q3Group_GetFirstPositionOfType(theDocument->light1, |
kQ3ShapeTypeGeometry, &position); |
Q3Group_GetPositionObject(theDocument->light1, position, &ellipsoid); |
origin.x = ratio * diagonalVector.x * POSSCALE; |
origin.y = ratio * diagonalVector.y * POSSCALE; |
origin.z = ratio * diagonalVector.z * POSSCALE; |
Q3Ellipsoid_SetOrigin( ellipsoid, &origin); |
radius.x = radius.z = 0.0; |
radius.y = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetOrientation( ellipsoid, &radius); |
radius.x = radius.y = 0.0; |
radius.z = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetMajorRadius( ellipsoid, &radius); |
radius.z = radius.y = 0.0; |
radius.x = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetMinorRadius( ellipsoid, &radius); |
Q3Group_GetNextPosition(lightGroup, &lightPosition); |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
Q3PointLight_SetLocation(theLight, &origin); |
Q3Object_Dispose(theLight); |
Q3Object_Dispose(ellipsoid); |
/* Set the geometry and the light parameters for the green light */ |
Q3Group_GetFirstPositionOfType(theDocument->light2, |
kQ3ShapeTypeGeometry, &position); |
Q3Group_GetPositionObject(theDocument->light2, position, &ellipsoid); |
origin.x = - ratio * diagonalVector.x * POSSCALE; |
origin.y = - ratio * diagonalVector.y * POSSCALE; |
origin.z = ratio * diagonalVector.z * POSSCALE; |
Q3Ellipsoid_SetOrigin( ellipsoid, &origin); |
radius.x = radius.z = 0.0; |
radius.y = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetOrientation( ellipsoid, &radius); |
radius.x = radius.y = 0.0; |
radius.z = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetMajorRadius( ellipsoid, &radius); |
radius.z = radius.y = 0.0; |
radius.x = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetMinorRadius( ellipsoid, &radius); |
Q3Group_GetNextPosition(lightGroup, &lightPosition); |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
Q3PointLight_SetLocation(theLight, &origin); |
Q3Object_Dispose(theLight); |
Q3Object_Dispose(ellipsoid); |
/* Set the geometry and the light parameters for the blue light */ |
Q3Group_GetFirstPositionOfType(theDocument->light3, |
kQ3ShapeTypeGeometry, &position); |
Q3Group_GetPositionObject(theDocument->light3, position, &ellipsoid); |
origin.x = 0.0; |
origin.y = ratio * diagonalVector.y * POSSCALE + 1.0; |
origin.z = 0.0; |
Q3Ellipsoid_SetOrigin( ellipsoid, &origin); |
radius.x = radius.z = 0.0; |
radius.y = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetOrientation( ellipsoid, &radius); |
radius.x = radius.y = 0.0; |
radius.z = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetMajorRadius( ellipsoid, &radius); |
radius.z = radius.y = 0.0; |
radius.x = ratio * maxDimension * SIZESCALE; |
Q3Ellipsoid_SetMinorRadius( ellipsoid, &radius); |
Q3Group_GetNextPosition(lightGroup, &lightPosition); |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
Q3PointLight_SetLocation(theLight, &origin); |
Q3Object_Dispose(theLight); |
Q3Object_Dispose(ellipsoid); |
Q3Object_Dispose(lightGroup); |
#endif |
} |
//=========================================================================== |
// |
// Routine: AdjustCamera() |
// |
// Comments: |
// |
//=========================================================================== |
TQ3Point3D AdjustCamera( |
DocumentPtr theDocument, |
short winWidth, |
short winHeight) |
{ |
float fieldOfView; |
float hither; |
float yon; |
TQ3CameraPlacement placement; |
TQ3CameraRange range; |
TQ3BoundingBox viewBBox; |
long fromAxis; |
float maxDimension; |
float xSize, ySize, zSize; |
float weights[2] = { 0.5, 0.5 }; |
TQ3Point3D points[2]; |
TQ3Vector3D viewVector; |
TQ3Vector3D normViewVector; |
TQ3Vector3D eyeToFrontClip; |
TQ3Vector3D eyeToBackClip; |
float viewDistance; |
TQ3Vector3D diagonalVector; |
float ratio; |
TQ3CameraObject camera; |
Q3View_GetCamera(theDocument->theView, &camera); |
GetGroupBBox(theDocument->theView, theDocument->documentGroup, |
theDocument->dynamicLights, &viewBBox); |
/* |
* If we have a point model, then the "viewBBox" would end up |
* being a "singularity" at the location of the point. As |
* this bounding "box" is used in setting up the camera spec, |
* we get bogus input into Escher. |
* |
* Therefore, determine if the bounding box is really really small |
* (kQ3RealZero) and increase it so it's just a little small. |
*/ |
xSize = viewBBox.max.x - viewBBox.min.x; |
ySize = viewBBox.max.y - viewBBox.min.y; |
zSize = viewBBox.max.z - viewBBox.min.z; |
if (xSize <= kQ3RealZero && |
ySize <= kQ3RealZero && |
zSize <= kQ3RealZero) |
{ |
viewBBox.max.x += 0.0001; |
viewBBox.max.y += 0.0001; |
viewBBox.max.z += 0.0001; |
viewBBox.min.x -= 0.0001; |
viewBBox.min.y -= 0.0001; |
viewBBox.min.z -= 0.0001; |
} |
points[0] = viewBBox.min; |
points[1] = viewBBox.max; |
/* |
This sets the "documentGroupCenter" to the center of our bbox. |
(point[0] * weight[0] + point[1] * weight[1]) or |
(point[0] * 0.5 + point[1] * 0.5) or |
point[0] + point[1] |
-------------------, essentially, the average of the points. |
2 |
*/ |
Q3Point3D_AffineComb(points, weights, 2, &theDocument->documentGroupCenter); |
/* |
* The "from" point is on a vector perpendicular to the plane |
* in which the bounding box has greatest dimension. As "up" is |
* always in the positive y direction, look at x and z directions. |
*/ |
xSize = viewBBox.max.x - viewBBox.min.x; |
zSize = viewBBox.max.z - viewBBox.min.z; |
if (xSize > zSize) { |
fromAxis = kQ3AxisZ; |
} else { |
fromAxis = kQ3AxisX; |
} |
/* |
* Compute the length of the diagonal of the bounding box. |
* |
* The hither and yon planes are adjusted so that the |
* diagonal of the bounding box is 7/8 the size of the |
* minimum dimension of the view frustum. The diagonal is used instead |
* of the maximum size (in x, y, or z) so that when you rotate |
* the object, the corners don't get clipped out. |
*/ |
Q3Point3D_Subtract( |
&viewBBox.max, |
&viewBBox.min, |
&diagonalVector); |
maxDimension = Q3Vector3D_Length(&diagonalVector); |
maxDimension *= 8.0 / 7.0; |
/* |
This scales all objects in the scene so they gets scaled to fit |
in the window. We're using the length of the diagonal of the box |
to scale. We can now assume the maximum dimension of the model is |
1.0. |
*/ |
ratio = 1.0 / maxDimension; |
theDocument->documentGroupScale = ratio; |
/* |
Now, adjust the camera's hither and yon planes. |
(We don't edit the camera location, etc. as it will always be in |
the same location - we always scale the objects and leave the camera |
in the same location.) |
*/ |
Q3Camera_GetPlacement(camera, &placement); |
/* |
Compute the camera vector |
*/ |
Q3Point3D_Subtract( |
&placement.cameraLocation, |
&placement.pointOfInterest, |
&viewVector); |
viewDistance = Q3Vector3D_Length(&viewVector); |
Q3Vector3D_Normalize(&viewVector, &normViewVector); |
/* |
Essentially, here we are "scaling" the normalized camera vector |
to a location in front of the object (half of maxDimension) |
and another location in back of the camera. |
Assume these three vectors below are co-linear. |
A = ratio * maxDimension/2.0 |
|------hither-------||----A----|----A-----| |
|------------------yon--------------------| |
camera location |
* -----------------> * eyeToFrontClip |
* --------camera vector------> * object center |
* --------------------------------------> * eyeToBackClip |
*/ |
Q3Vector3D_Scale(&normViewVector, |
viewDistance - ratio * maxDimension/2.0, |
&eyeToFrontClip); |
Q3Vector3D_Scale(&normViewVector, |
viewDistance + ratio * maxDimension/2.0, |
&eyeToBackClip); |
hither = Q3Vector3D_Length(&eyeToFrontClip); |
yon = Q3Vector3D_Length(&eyeToBackClip); |
/* |
Set the field of view. This will determine the width of our lens. |
Or, (more appropriately), as someone here mentioned, |
where the blinders begin in our image. |
This is the angle created by the triangle of the camera vector and the |
maximum dimension of our object. |
We use the hither point because it's closest and convenient. |
we know: |
atan(opposite/adjacent) = the angle we need |
Our angle is at the camera, so our "opposite" leg is "A" (above) |
our "adjacent" leg is the hither length. |
We double our result because our triangle gets us the half angle |
for the entire field of view. |
*/ |
fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither); |
range.hither = hither; |
range.yon = yon; |
Q3Camera_SetRange(camera, &range); |
Q3ViewAngleAspectCamera_SetFOV( |
camera, fieldOfView); |
/* |
And finally, set up our aspect ratio depending on how big the |
window is. |
*/ |
Q3ViewAngleAspectCamera_SetAspectRatio( |
camera, (float) winWidth / (float) winHeight); |
Q3Object_Dispose(camera); |
return(theDocument->documentGroupCenter); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14