mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-14 22:00:05 +00:00
cc9995d44b
use debug visualizer camera viewmatrix/projection matrix if not provided, in ER_BULLET_HARDWARE_OPENGL mode. fix broken changeRGBAColor implementation, thanks to Laura for the report!
443 lines
9.9 KiB
C++
443 lines
9.9 KiB
C++
#include "SimpleCamera.h"
|
|
|
|
#include "Bullet3Common/b3Vector3.h"
|
|
#include "Bullet3Common/b3Quaternion.h"
|
|
#include "Bullet3Common/b3Matrix3x3.h"
|
|
#include "Bullet3Common/b3Transform.h"
|
|
|
|
|
|
B3_ATTRIBUTE_ALIGNED16(struct) SimpleCameraInternalData
|
|
{
|
|
SimpleCameraInternalData()
|
|
:m_cameraTargetPosition(b3MakeVector3(0,0,0)),
|
|
m_cameraDistance(20),
|
|
m_cameraUp(b3MakeVector3(0,1,0)),
|
|
m_cameraForward(b3MakeVector3(1,0,0)),
|
|
m_cameraUpAxis(1),
|
|
m_yaw(20),
|
|
m_pitch(0),
|
|
m_aspect(1),
|
|
m_frustumZNear(0.01),
|
|
m_frustumZFar(1000),
|
|
m_enableVR(false)
|
|
{
|
|
b3Transform tr;
|
|
tr.setIdentity();
|
|
tr.getOpenGLMatrix(m_offsetTransformVR);
|
|
}
|
|
|
|
B3_DECLARE_ALIGNED_ALLOCATOR();
|
|
|
|
B3_ATTRIBUTE_ALIGNED16(float) m_offsetTransformVR[16];
|
|
b3Vector3 m_cameraTargetPosition;
|
|
float m_cameraDistance;
|
|
b3Vector3 m_cameraUp;
|
|
b3Vector3 m_cameraForward;
|
|
int m_cameraUpAxis;
|
|
//the m_cameraPosition is a cached value, recomputed from other values
|
|
b3Vector3 m_cameraPosition;
|
|
float m_yaw;
|
|
|
|
float m_pitch;
|
|
float m_aspect;
|
|
float m_frustumZNear;
|
|
float m_frustumZFar;
|
|
|
|
bool m_enableVR;
|
|
float m_viewMatrixVR[16];
|
|
float m_projectionMatrixVR[16];
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SimpleCamera::SimpleCamera()
|
|
{
|
|
m_data = new SimpleCameraInternalData;
|
|
}
|
|
SimpleCamera::~SimpleCamera()
|
|
{
|
|
delete m_data;
|
|
}
|
|
|
|
void SimpleCamera::setVRCamera(const float viewMat[16], const float projectionMatrix[16])
|
|
{
|
|
m_data->m_enableVR = true;
|
|
|
|
b3Matrix3x3 vm;
|
|
vm.setValue(viewMat[0],viewMat[4],viewMat[8],
|
|
viewMat[1],viewMat[5],viewMat[9],
|
|
viewMat[2],viewMat[6],viewMat[10]);
|
|
|
|
b3Vector3 vp = b3MakeVector3(viewMat[12],viewMat[13],viewMat[14]);
|
|
b3Transform tr;
|
|
tr.setBasis(vm);
|
|
tr.setOrigin(vp);
|
|
b3Transform cp = tr.inverse();
|
|
m_data->m_cameraPosition = cp.getOrigin();
|
|
|
|
|
|
for (int i=0;i<16;i++)
|
|
{
|
|
m_data->m_viewMatrixVR[i] = viewMat[i];
|
|
m_data->m_projectionMatrixVR[i] = projectionMatrix[i];
|
|
m_data->m_frustumZNear = m_data->m_projectionMatrixVR[14]/(m_data->m_projectionMatrixVR[10]-1);
|
|
m_data->m_frustumZFar = m_data->m_projectionMatrixVR[14]/(m_data->m_projectionMatrixVR[10]+1);
|
|
}
|
|
}
|
|
|
|
bool SimpleCamera::getVRCamera(float viewMat[16], float projectionMatrix[16])
|
|
{
|
|
if (m_data->m_enableVR)
|
|
{
|
|
for (int i=0;i<16;i++)
|
|
{
|
|
viewMat[i] = m_data->m_viewMatrixVR[i];
|
|
projectionMatrix[i] = m_data->m_projectionMatrixVR[i];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
void SimpleCamera::disableVRCamera()
|
|
{
|
|
m_data->m_enableVR = false;
|
|
}
|
|
|
|
bool SimpleCamera::isVRCamera() const
|
|
{
|
|
return m_data->m_enableVR ;
|
|
}
|
|
|
|
|
|
static void b3CreateFrustum(
|
|
float left,
|
|
float right,
|
|
float bottom,
|
|
float top,
|
|
float nearVal,
|
|
float farVal,
|
|
float frustum[16])
|
|
{
|
|
|
|
frustum[0*4+0] = (float(2) * nearVal) / (right - left);
|
|
frustum[0*4+1] = float(0);
|
|
frustum[0*4+2] = float(0);
|
|
frustum[0*4+3] = float(0);
|
|
|
|
frustum[1*4+0] = float(0);
|
|
frustum[1*4+1] = (float(2) * nearVal) / (top - bottom);
|
|
frustum[1*4+2] = float(0);
|
|
frustum[1*4+3] = float(0);
|
|
|
|
frustum[2*4+0] = (right + left) / (right - left);
|
|
frustum[2*4+1] = (top + bottom) / (top - bottom);
|
|
frustum[2*4+2] = -(farVal + nearVal) / (farVal - nearVal);
|
|
frustum[2*4+3] = float(-1);
|
|
|
|
frustum[3*4+0] = float(0);
|
|
frustum[3*4+1] = float(0);
|
|
frustum[3*4+2] = -(float(2) * farVal * nearVal) / (farVal - nearVal);
|
|
frustum[3*4+3] = float(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
static void b3CreateDiagonalMatrix(float value, float result[4][4])
|
|
{
|
|
for (int i=0;i<4;i++)
|
|
{
|
|
for (int j=0;j<4;j++)
|
|
{
|
|
if (i==j)
|
|
{
|
|
result[i][j] = value;
|
|
} else
|
|
{
|
|
result[i][j] = 0.f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static void b3CreateOrtho(float left, float right, float bottom, float top, float zNear, float zFar, float result[4][4])
|
|
{
|
|
b3CreateDiagonalMatrix(1.f,result);
|
|
|
|
result[0][0] = 2.f / (right - left);
|
|
result[1][1] = 2.f / (top - bottom);
|
|
result[2][2] = - 2.f / (zFar - zNear);
|
|
result[3][0] = - (right + left) / (right - left);
|
|
result[3][1] = - (top + bottom) / (top - bottom);
|
|
result[3][2] = - (zFar + zNear) / (zFar - zNear);
|
|
}
|
|
#endif
|
|
static void b3CreateLookAt(const b3Vector3& eye, const b3Vector3& center,const b3Vector3& up, float result[16])
|
|
{
|
|
b3Vector3 f = (center - eye).normalized();
|
|
b3Vector3 u = up.normalized();
|
|
b3Vector3 s = (f.cross(u)).normalized();
|
|
u = s.cross(f);
|
|
|
|
result[0*4+0] = s.x;
|
|
result[1*4+0] = s.y;
|
|
result[2*4+0] = s.z;
|
|
|
|
result[0*4+1] = u.x;
|
|
result[1*4+1] = u.y;
|
|
result[2*4+1] = u.z;
|
|
|
|
result[0*4+2] =-f.x;
|
|
result[1*4+2] =-f.y;
|
|
result[2*4+2] =-f.z;
|
|
|
|
result[0*4+3] = 0.f;
|
|
result[1*4+3] = 0.f;
|
|
result[2*4+3] = 0.f;
|
|
|
|
result[3*4+0] = -s.dot(eye);
|
|
result[3*4+1] = -u.dot(eye);
|
|
result[3*4+2] = f.dot(eye);
|
|
result[3*4+3] = 1.f;
|
|
}
|
|
|
|
void SimpleCamera::setCameraUpAxis(int upAxis)
|
|
{
|
|
m_data->m_cameraUpAxis = upAxis;
|
|
|
|
update();
|
|
}
|
|
|
|
int SimpleCamera::getCameraUpAxis() const
|
|
{
|
|
return m_data->m_cameraUpAxis;
|
|
}
|
|
|
|
void SimpleCamera::update()
|
|
{
|
|
b3Scalar yawRad = m_data->m_yaw * b3Scalar(0.01745329251994329547);// rads per deg
|
|
b3Scalar pitchRad = m_data->m_pitch * b3Scalar(0.01745329251994329547);// rads per deg
|
|
b3Scalar rollRad = 0.0;
|
|
b3Quaternion eyeRot;
|
|
|
|
int forwardAxis(-1);
|
|
switch (m_data->m_cameraUpAxis)
|
|
{
|
|
case 1:
|
|
forwardAxis = 2;
|
|
m_data->m_cameraUp = b3MakeVector3(0,1,0);
|
|
//gLightPos = b3MakeVector3(-50.f,100,30);
|
|
eyeRot.setEulerZYX(rollRad, yawRad, -pitchRad);
|
|
break;
|
|
case 2:
|
|
forwardAxis = 1;
|
|
m_data->m_cameraUp = b3MakeVector3(0,0,1);
|
|
//gLightPos = b3MakeVector3(-50.f,30,100);
|
|
eyeRot.setEulerZYX(yawRad, rollRad, pitchRad);
|
|
break;
|
|
default:
|
|
{
|
|
//b3Assert(0);
|
|
return;
|
|
}
|
|
};
|
|
|
|
b3Vector3 eyePos = b3MakeVector3(0,0,0);
|
|
eyePos[forwardAxis] = -m_data->m_cameraDistance;
|
|
eyePos = b3Matrix3x3(eyeRot)*eyePos;
|
|
|
|
m_data->m_cameraPosition = eyePos;
|
|
|
|
|
|
|
|
m_data->m_cameraPosition+= m_data->m_cameraTargetPosition;
|
|
|
|
m_data->m_cameraForward = m_data->m_cameraTargetPosition-m_data->m_cameraPosition;
|
|
if (m_data->m_cameraForward.length2() < B3_EPSILON)
|
|
{
|
|
m_data->m_cameraForward.setValue(1.f,0.f,0.f);
|
|
} else
|
|
{
|
|
m_data->m_cameraForward.normalize();
|
|
}
|
|
}
|
|
|
|
void SimpleCamera::getCameraProjectionMatrix(float projectionMatrix[16]) const
|
|
{
|
|
if (m_data->m_enableVR)
|
|
{
|
|
for (int i=0;i<16;i++)
|
|
{
|
|
projectionMatrix[i] = m_data->m_projectionMatrixVR[i];
|
|
}
|
|
} else
|
|
{
|
|
b3CreateFrustum(-m_data->m_aspect * m_data->m_frustumZNear, m_data->m_aspect * m_data->m_frustumZNear, -m_data->m_frustumZNear,m_data->m_frustumZNear, m_data->m_frustumZNear, m_data->m_frustumZFar,projectionMatrix);
|
|
}
|
|
}
|
|
void SimpleCamera::setVRCameraOffsetTransform(const float offset[16])
|
|
{
|
|
for (int i=0;i<16;i++)
|
|
{
|
|
m_data->m_offsetTransformVR[i] = offset[i];
|
|
}
|
|
}
|
|
void SimpleCamera::getCameraViewMatrix(float viewMatrix[16]) const
|
|
{
|
|
if (m_data->m_enableVR)
|
|
{
|
|
for (int i=0;i<16;i++)
|
|
{
|
|
b3Transform tr;
|
|
tr.setFromOpenGLMatrix(m_data->m_viewMatrixVR);
|
|
b3Transform shift=b3Transform::getIdentity();
|
|
shift.setFromOpenGLMatrix(m_data->m_offsetTransformVR);
|
|
tr = tr*shift;
|
|
tr.getOpenGLMatrix(viewMatrix);
|
|
//viewMatrix[i] = m_data->m_viewMatrixVR[i];
|
|
}
|
|
} else
|
|
{
|
|
b3CreateLookAt(m_data->m_cameraPosition,m_data->m_cameraTargetPosition,m_data->m_cameraUp,viewMatrix);
|
|
}
|
|
}
|
|
|
|
void SimpleCamera::getCameraTargetPosition(double pos[3]) const
|
|
{
|
|
pos[0] =m_data->m_cameraTargetPosition[0];
|
|
pos[1] =m_data->m_cameraTargetPosition[1];
|
|
pos[2] =m_data->m_cameraTargetPosition[2];
|
|
}
|
|
|
|
void SimpleCamera::getCameraPosition(double pos[3]) const
|
|
{
|
|
pos[0] =m_data->m_cameraPosition[0];
|
|
pos[1] =m_data->m_cameraPosition[1];
|
|
pos[2] =m_data->m_cameraPosition[2];
|
|
}
|
|
|
|
|
|
void SimpleCamera::getCameraTargetPosition(float pos[3]) const
|
|
{
|
|
pos[0] =m_data->m_cameraTargetPosition[0];
|
|
pos[1] =m_data->m_cameraTargetPosition[1];
|
|
pos[2] =m_data->m_cameraTargetPosition[2];
|
|
}
|
|
void SimpleCamera::getCameraPosition(float pos[3]) const
|
|
{
|
|
pos[0] =m_data->m_cameraPosition[0];
|
|
pos[1] =m_data->m_cameraPosition[1];
|
|
pos[2] =m_data->m_cameraPosition[2];
|
|
}
|
|
|
|
void SimpleCamera::setCameraTargetPosition(float x,float y,float z)
|
|
{
|
|
m_data->m_cameraTargetPosition.setValue(x,y,z);
|
|
update();
|
|
}
|
|
float SimpleCamera::getCameraDistance() const
|
|
{
|
|
return m_data->m_cameraDistance;
|
|
}
|
|
|
|
void SimpleCamera::setCameraDistance(float dist)
|
|
{
|
|
m_data->m_cameraDistance = dist;
|
|
update();
|
|
}
|
|
void SimpleCamera::setCameraUpVector(float x,float y ,float z)
|
|
{
|
|
m_data->m_cameraUp.setValue(x,y,z);
|
|
update();
|
|
}
|
|
|
|
void SimpleCamera::getCameraUpVector(float up[3]) const
|
|
{
|
|
if (m_data->m_enableVR)
|
|
{
|
|
float viewMatTotal[16];
|
|
getCameraViewMatrix(viewMatTotal);
|
|
up[0] = viewMatTotal[0];
|
|
up[1] = viewMatTotal[4];
|
|
up[2] = viewMatTotal[8];
|
|
} else
|
|
{
|
|
up[0] = float(m_data->m_cameraUp[0]);
|
|
up[1] = float(m_data->m_cameraUp[1]);
|
|
up[2] = float(m_data->m_cameraUp[2]);
|
|
}
|
|
}
|
|
|
|
void SimpleCamera::getCameraForwardVector(float fwd[3]) const
|
|
{
|
|
if (m_data->m_enableVR)
|
|
{
|
|
float viewMatTotal[16];
|
|
getCameraViewMatrix(viewMatTotal);
|
|
fwd[0] = viewMatTotal[2];
|
|
fwd[1] = viewMatTotal[6];
|
|
fwd[2] = viewMatTotal[10];
|
|
} else
|
|
{
|
|
fwd[0] = float(m_data->m_cameraForward[0]);
|
|
fwd[1] = float(m_data->m_cameraForward[1]);
|
|
fwd[2] = float(m_data->m_cameraForward[2]);
|
|
}
|
|
}
|
|
|
|
void SimpleCamera::setCameraYaw(float yaw)
|
|
{
|
|
m_data->m_yaw = yaw;
|
|
update();
|
|
}
|
|
|
|
float SimpleCamera::getCameraYaw() const
|
|
{
|
|
return m_data->m_yaw;
|
|
}
|
|
|
|
void SimpleCamera::setCameraPitch(float pitch)
|
|
{
|
|
m_data->m_pitch = pitch;
|
|
update();
|
|
}
|
|
|
|
void SimpleCamera::setAspectRatio(float ratio)
|
|
{
|
|
m_data->m_aspect = ratio;
|
|
update();
|
|
}
|
|
|
|
float SimpleCamera::getCameraPitch() const
|
|
{
|
|
return m_data->m_pitch;
|
|
}
|
|
float SimpleCamera::getAspectRatio() const
|
|
{
|
|
return m_data->m_aspect;
|
|
}
|
|
|
|
float SimpleCamera::getCameraFrustumFar() const
|
|
{
|
|
return m_data->m_frustumZFar;
|
|
}
|
|
|
|
float SimpleCamera::getCameraFrustumNear() const
|
|
{
|
|
return m_data->m_frustumZNear;
|
|
}
|
|
|
|
void SimpleCamera::setCameraFrustumFar(float far)
|
|
{
|
|
m_data->m_frustumZFar = far;
|
|
}
|
|
|
|
void SimpleCamera::setCameraFrustumNear(float near)
|
|
{
|
|
m_data->m_frustumZNear = near;
|
|
}
|