Editor camera
For Demo programm I need to add better camera. I want to move it using RMB,
and rotate holding Alt
Add new data into slCamera
// for Editor camera
enum class Direction : uint32_t
{
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest
};
enum CameraEditorType
{
Perspective,
Bottom, Left, Right, Back, Front, Top
};
slVec3f m_rotationPlatform;
slVec4 m_positionPlatform; // w = height, zoom, mouse wheel value
slVec4 m_positionCamera; // in world
Direction m_direction;
CameraEditorType m_editorCameraType = CameraEditorType::Perspective;
bool m_forceOrtho = false;
void EditorUpdate();
void EditorPanMove(slVec2f* mouseDelta, float timeDelta);
void EditorRotate(slVec2f* mouseDelta, float timeDelta);
void EditorZoom(int wheelDelta);
void EditorChangeFOV(slVec2f* mouseDelta, float timeDelta);
void EditorRotateZ(slVec2f* mouseDelta, float timeDelta);
void EditorReset();
Move camera using m_positionPlatform. w component will move camera forward or backward
so it will be zoom for camera
void slCamera::_afterUpdate()
{
slMath::mul(m_projectionMatrix, m_viewMatrix, m_viewProjectionMatrix);
m_viewMatrixInvert = m_viewMatrix;
slMath::invert(m_viewMatrixInvert);
auto pi = m_projectionMatrix;
slMath::invert(pi);
slMath::mul(m_viewMatrixInvert, pi, m_viewProjectionInvertMatrix);
m_frust.CalculateFrustum(m_projectionMatrix, m_viewMatrix);
}
void slCamera::EditorUpdate() {
if ((m_editorCameraType != CameraEditorType::Perspective) || m_forceOrtho)
{
float zoom = (float)m_positionPlatform.w;
slMath::orthoRH(
m_projectionMatrix,
zoom * m_aspect,
zoom,
-m_far,
m_far);
}
else
{
slMath::perspectiveRH(m_projectionMatrix, m_fov, m_aspect, m_near, m_far);
}
m_projectionMatrix.m_data[0].x = -m_projectionMatrix.m_data[0].x;
slMat4 MX(slQuaternion(m_rotationPlatform.x, 0.f, 0.f));
slMat4 MY(slQuaternion(0.f, m_rotationPlatform.y, 0.f));
//Mat4 MZ(Quat(0.f, 0.f, m_rotationPlatform.z));
m_positionCamera = slVec4(0.f, m_positionPlatform.w, 0.f, 0.f);
slMath::mul((MY * MX), slVec4(m_positionCamera), m_positionCamera);
m_positionCamera += slVec4(m_positionPlatform.x, m_positionPlatform.y, m_positionPlatform.z, 0.f);
slMat4 T;
T.m_data[3].x = -m_positionCamera.x;
T.m_data[3].y = -m_positionCamera.y;
T.m_data[3].z = -m_positionCamera.z;
T.m_data[3].w = 1.f;
slMat4 P(slQuaternion(slVec4(-m_rotationPlatform.x + slMath::DegToRad(-90.f), 0.f, 0.f, 1.f)));
slMat4 Y(slQuaternion(slVec4(0.f, -m_rotationPlatform.y + slMath::DegToRad(0.f), 0.f, 1.f)));
slMat4 R(slQuaternion(slVec4(0.f, 0.f, m_rotationPlatform.z, 1.f)));
m_viewMatrix = (R * (P * Y)) * T;
m_viewProjectionMatrix = m_projectionMatrix * m_viewMatrix;
m_viewMatrixInvert = m_viewMatrix; m_viewMatrixInvert.invert();
auto pi = m_projectionMatrix; pi.invert();
m_viewProjectionInvertMatrix = m_viewMatrixInvert * pi;
m_frust.CalculateFrustum(m_projectionMatrix, m_viewMatrix);
m_direction = Direction::NorthEast;
if (m_rotationPlatform.y >= 2.7488936 && m_rotationPlatform.y <= 3.5342917)
m_direction = Direction::North;
else if (m_rotationPlatform.y >= 5.8904862 || m_rotationPlatform.y <= 0.3926991)
m_direction = Direction::South;
else if (m_rotationPlatform.y >= 1.1780972 && m_rotationPlatform.y <= 1.9634954)
m_direction = Direction::West;
else if (m_rotationPlatform.y >= 4.3196899 && m_rotationPlatform.y <= 5.1050881)
m_direction = Direction::East;
else if (m_rotationPlatform.y >= 1.9634954 && m_rotationPlatform.y <= 2.7488936)
m_direction = Direction::NorthWest;
else if (m_rotationPlatform.y >= 0.3926991 && m_rotationPlatform.y <= 1.1780972)
m_direction = Direction::SouthWest;
else if (m_rotationPlatform.y >= 5.1050881 && m_rotationPlatform.y <= 5.8904862)
m_direction = Direction::SouthEast;
_afterUpdate();
}
void slCamera::EditorPanMove(slVec2f* mouseDelta, float timeDelta)
{
float speed = 10.f * ((float)m_positionPlatform.w * 0.01f);
slVec4 vec(
speed * mouseDelta->x * timeDelta,
0.f,
speed * -mouseDelta->y * timeDelta,
0.f);
slMat4 MX(slQuaternion(m_rotationPlatform.x, 0.f, 0.f));
slMat4 MY(slQuaternion(0.f, m_rotationPlatform.y, 0.f));
//Mat4 MZ(Quat(0.f, 0.f, m_rotationPlatform.z));
slMath::mul(MY * MX, slVec4(vec), vec);
m_positionPlatform += vec;
}
void slCamera::EditorRotate(slVec2f* mouseDelta, float timeDelta)
{
const float speed = 0.69f * timeDelta;
m_rotationPlatform.x += mouseDelta->y * speed;
m_rotationPlatform.y += -mouseDelta->x * speed;
if (m_rotationPlatform.y < 0.f) m_rotationPlatform.y = m_rotationPlatform.y + (float)PIPI;
if (m_rotationPlatform.x > PIPI) m_rotationPlatform.x = 0.f;
if (m_rotationPlatform.y > PIPI) m_rotationPlatform.y = 0.f;
//if (m_rotationPlatform.x < -math::PIPI) m_rotationPlatform.x = 0.f;
//if (m_rotationPlatform.y < -math::PIPI) m_rotationPlatform.y = 0.f;
//if (m_type != miViewportCameraType::Perspective)
// m_viewport->SetViewportName(L"Orthogonal");
//Update();
}
void slCamera::EditorZoom(int wheelDelta)
{
float mult = 1.f;
//if (g_app->m_inputContext->m_kbm == miKeyboardModifier::Shift)
//mult = 3.f;
if (wheelDelta > 0)
m_positionPlatform.w *= 0.9f * (1.f / mult);
else
m_positionPlatform.w *= 1.1f * mult;
if (m_positionPlatform.w < 0.01f)
m_positionPlatform.w = 0.01f;
//Update();
}
void slCamera::EditorChangeFOV(slVec2f* mouseDelta, float timeDelta)
{
m_fov += mouseDelta->x * timeDelta;
if (m_fov < 0.01f)
m_fov = 0.01f;
if (m_fov > PI)
m_fov = PI;
}
void slCamera::EditorRotateZ(slVec2f* mouseDelta, float timeDelta)
{
m_rotationPlatform.z += mouseDelta->x * timeDelta;
}
void slCamera::EditorReset()
{
m_near = 0.01f;
m_far = 2500.f;
m_fov = 0.683264f;
m_aspect = 800.f / 600.f;
m_positionPlatform = slVec4(0.f, 0.f, 0.f, 15.f);
switch (m_editorCameraType)
{
case CameraEditorType::Perspective:
m_rotationPlatform = slVec3f(slMath::DegToRad(-45.f), 0.f, 0.f);
break;
case CameraEditorType::Bottom:
m_rotationPlatform = slVec3f(slMath::DegToRad(-180.f), 0.f, 0.f);
break;
case CameraEditorType::Left:
m_rotationPlatform = slVec3f(slMath::DegToRad(-90.f), slMath::DegToRad(-90.f), 0.f);
break;
case CameraEditorType::Right:
m_rotationPlatform = slVec3f(slMath::DegToRad(-90.f), slMath::DegToRad(90.f), 0.f);
break;
case CameraEditorType::Back:
m_rotationPlatform = slVec3f(slMath::DegToRad(-90.f), slMath::DegToRad(180.f), 0.f);
break;
case CameraEditorType::Front:
m_rotationPlatform = slVec3f(slMath::DegToRad(-90.f), slMath::DegToRad(0.f), 0.f);
break;
case CameraEditorType::Top:
m_rotationPlatform = slVec3f();
break;
}
slVec2f rp;
EditorRotate(&rp, 1.f);
}
Text in 3D space
I very need to draw text in 3d space.
I can use sprite code for this
void slGSD3D11::DrawText3D(const slVec4& _position, const char32_t* text, size_t textSz, slGUIFont* font, const slColor& c,
float sizeMultipler)
{
SL_ASSERT_ST(text);
SL_ASSERT_ST(font);
SL_ASSERT_ST(textSz);
SL_ASSERT_ST(slFramework::GetMatrix(slMatrixType::ViewInvert));
//SL_ASSERT_ST(slFramework::GetMatrix(slMatrixType::World));
SL_ASSERT_ST(slFramework::GetMatrix(slMatrixType::View));
SL_ASSERT_ST(slFramework::GetMatrix(slMatrixType::Projection));
slVec2f textSzInPixels = slFramework::GetTextSize(text, font);
slVec4 position;
position.x += (textSzInPixels.x * 0.5f)* sizeMultipler;
auto oldW = slFramework::GetMatrix(slMatrixType::World);
static slMat4 W;
slFramework::SetMatrix(slMatrixType::World, &W);
W.m_data[3].set(_position.x, _position.y, _position.z, 1.f);
SetShader(slShaderType::Sprite, 0);
for (uint32_t i = 0; i < textSz; ++i)
{
slGUIFontGlyph* g = font->GetGlyphMap()[text[i]];
slVec4 rct;
rct.x = position.x - ((float)g->m_width * sizeMultipler);
rct.y = position.y;
rct.z = position.x;
rct.w = rct.y + ((float)g->m_height * sizeMultipler);
_drawSprite(c, rct, g->m_UV, 0.5f, dynamic_cast<slGSD3D11Texture*>(font->GetTexture(g->m_textureSlot)));
position.x -= ((float)g->m_width + g->m_overhang + g->m_underhang + font->m_characterSpacing) * sizeMultipler;
switch (text[i])
{
case U' ':
position.x -= font->m_spaceSize;
break;
case U'\t':
position.x -= font->m_tabSize;
break;
case U'\n':
position.y += font->GetMaxSize().y;
position.x = _position.x;
break;
}
}
slFramework::SetMatrix(slMatrixType::World, oldW);
}
Before using need to set matrices like when you draw sprite.
I put common things for drawing a sprite into _drawSprite method.
Mesh generation
And last. For frustum culling I want to visualize bounding volume.
Bounding volume is not only AABB but also sphere.
Box, cube
I am not sure about texture coordinates.
void slPolygonMesh::AddCube(float size, const slMat4& m)
{
SL_ASSERT_ST(size != 0.f);
float halfSize = size * 0.5f;
slAabb aabb;
aabb.m_min.set(-halfSize);
aabb.m_max.set(halfSize);
AddBox(aabb, m);
}
/*
* x - max
* n - min
nxx+______________+ xxx
|\ \
| \ .\
| \ . \
| \ nxn . \
| \+____________\+ xxn
| | . |
nnx+.....|........+xnx |
\ | . |
\ | . |
\ | . |
\ | .|
nnn \+_____________+ xnn
*/
void slPolygonMesh::AddBox(const slAabb& box, const slMat4& m)
{
slPolygonCreator pc;
// maybe UV is not correct...
// top
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_max.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_max.y, (float)box.m_max.z));
pc.SetUV(slVec2f(1.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_max.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 1.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_max.y, (float)box.m_min.z));
pc.SetUV(slVec2f(0.f, 1.f));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
// bottom
pc.Clear();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_min.y, (float)box.m_min.z));
pc.SetUV(slVec2f(0.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_min.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_min.y, (float)box.m_max.z));
pc.SetUV(slVec2f(1.f, 1.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_min.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 1.f));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
// left
pc.Clear();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_max.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_max.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_min.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 1.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_min.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 1.f));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
// right
pc.Clear();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_max.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_min.y, (float)box.m_max.z));
pc.SetUV(slVec2f(1.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_min.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 1.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_max.y, (float)box.m_min.z));
pc.SetUV(slVec2f(0.f, 1.f));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
// back
pc.Clear();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_max.y, (float)box.m_min.z));
pc.SetUV(slVec2f(0.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_max.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_min.y, (float)box.m_min.z));
pc.SetUV(slVec2f(1.f, 1.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_min.y, (float)box.m_min.z));
pc.SetUV(slVec2f(0.f, 1.f));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
// front
pc.Clear();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_max.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_min.x, (float)box.m_min.y, (float)box.m_max.z));
pc.SetUV(slVec2f(1.f, 0.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_min.y, (float)box.m_max.z));
pc.SetUV(slVec2f(1.f, 1.f));
pc.AddVertex();
pc.SetPosition(slVec3f((float)box.m_max.x, (float)box.m_max.y, (float)box.m_max.z));
pc.SetUV(slVec2f(0.f, 1.f));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
}
Sphere
Generate 3D sphere. Segments from 3 to 30.
I thought it hard, but actually easy. Generate points in 2D, only half circle.
Then use this points for creating poligons.
Create 2 rotation matrices for current latitude and for next latitude.
Create points, for current latitude(red) and for next latitude (green),
use them for creating polygon.
void slPolygonMesh::AddSphere(float radius, uint32_t segments, const slMat4& m)
{
if (radius == 0.f) radius = 1.f;
if (radius < 0.f) radius = 1.f;
if (segments < 3)
segments = 3;
if (segments > 30)
segments = 30;
// 1. Generate points in 2D.
// Generate from 90 to 270 degrees
// 2 points must be in 90 and in 270 degrees
slArray<slVec3> points;
float angle = 90.f;
float angleStep = 180.f / (segments-1);
for (uint32_t i = 0; i < segments; ++i)
{
if (i == segments - 1)
angle = 270.f;
auto sn = ::sin(slMath::DegToRad(angle));
auto cs = ::cos(slMath::DegToRad(angle));
// printf("A[%f]: %f %f\n", angle, sn, cs);
points.push_back(slVec3((real_t)cs, (real_t)sn, 0.0));
angle += angleStep;
}
// 2. Create polygons. Take points, rotate them, use them to build new polygon.
/*
* +0
* / |
* / |
* / |
* / /
* 1+ - - +1rotated
* | |
* | |
* | |
* | |
* 2+ - - +2rotated
* \ \
* \ |
* \ |
* \ |
* 3+
* Top and bottom polygons are triangles
*/
angle = 0.f;
angleStep = 360.f / (segments);
float nextAngle = angleStep;
slVec2f UV;
float UVstep = 1.f / (segments-1);
for (uint32_t i1 = 0; i1 < segments; ++i1)
{
slMat4 M, Mn;
M.set_rotation(slQuaternion(0.f, slMath::DegToRad(angle), 0.f));
Mn.set_rotation(slQuaternion(0.f, slMath::DegToRad(nextAngle), 0.f));
for (uint32_t i2 = 0; i2 < segments - 1; ++i2)
{
// top triangle
if (i2 == 0)
{
slVec3 v0 = points[i2];
slVec3 v1 = points[i2 + 1];
slVec3 v2 = v1;
slMath::mul(M, points[i2], v0);
slMath::mul(M, points[i2 + 1], v1);
slMath::mul(Mn, points[i2 + 1], v2);
slPolygonCreator pc;
pc.SetPosition(slVec3f((float)v1.x, (float)v1.y, (float)v1.z));
pc.SetUV(slVec2f(UV.x, UV.y + UVstep));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v0.x, (float)v0.y, (float)v0.z));
pc.SetUV(slVec2f(UV.x + (UVstep * 0.5f), UV.y));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v2.x, (float)v2.y, (float)v2.z));
pc.SetUV(slVec2f(UV.x + UVstep, UV.y + UVstep));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
}
else if (i2 == segments - 2) // bottom
{
slVec3 v0 = points[i2];
slVec3 v1 = points[i2 + 1];
slVec3 v2 = points[i2];
slMath::mul(M, points[i2], v0);
slMath::mul(M, points[i2 + 1], v1);
slMath::mul(Mn, points[i2], v2);
slPolygonCreator pc;
pc.SetPosition(slVec3f((float)v1.x, (float)v1.y, (float)v1.z));
pc.SetUV(slVec2f(UV.x + (UVstep * 0.5f), UV.y + UVstep));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v0.x, (float)v0.y, (float)v0.z));
pc.SetUV(slVec2f(UV.x, UV.y));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v2.x, (float)v2.y, (float)v2.z));
pc.SetUV(slVec2f(UV.x + UVstep, UV.y));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
}
else
{
slVec3 v0 = points[i2];
slVec3 v1 = points[i2 + 1];
slVec3 v2 = v0;
slVec3 v3 = v1;
slMath::mul(M, points[i2], v0);
slMath::mul(M, points[i2 + 1], v1);
slMath::mul(Mn, points[i2], v2);
slMath::mul(Mn, points[i2 + 1], v3);
slPolygonCreator pc;
pc.SetPosition(slVec3f((float)v1.x, (float)v1.y, (float)v1.z));
pc.SetUV(slVec2f(UV.x, UV.y + UVstep));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v0.x, (float)v0.y, (float)v0.z));
pc.SetUV(slVec2f(UV.x, UV.y));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v2.x, (float)v2.y, (float)v2.z));
pc.SetUV(slVec2f(UV.x + UVstep, UV.y));
pc.AddVertex();
pc.SetPosition(slVec3f((float)v3.x, (float)v3.y, (float)v3.z));
pc.SetUV(slVec2f(UV.x + UVstep, UV.y + UVstep));
pc.AddVertex();
pc.Mul(m);
AddPolygon(&pc, true);
}
UV.y += UVstep;
}
UV.x += UVstep;
angle += angleStep;
nextAngle += angleStep;
}
}
UV planar
For hand created polygon need to calculate texture coordinates.
First method is this. Later I will add more.
void slPolygonMesh::GenerateUVPlanar(float scale)
{
if (!m_first_polygon)
return;
slVec3f n;
auto cp = m_first_polygon;
auto lp = cp->m_left;
while (true)
{
n += cp->GetFaceNormalCalculateNew();
if (cp == lp)
break;
cp = cp->m_right;
}
n.normalize();
if (n.x == 0.f) n.x = 0.0001f;
if (n.y == 0.f) n.y = 0.0001f;
if (n.z == 0.f) n.z = 0.0001f;
slMat4 V;
slMat4 P;
slMath::lookAtRH(V, n, slVec4(), slVec4(0.f, 1.f, 0.f, 0.f));
slMath::orthoRH(P, 100.f, 100.f, -1000.f, 1000.f);
slMat4 W;
W.m_data[0].x = scale;
W.m_data[1].y = scale;
W.m_data[2].z = scale;
slMat4 VP = P * V * W;
{
auto cp = m_first_polygon;
auto lp = cp->m_left;
while (true)
{
auto cv = cp->GetVertices()->m_head;
auto lv = cv->m_left;
while (true)
{
slVec4 point = cv->m_data->m_data.baseData.Position;// -center3d;
point.w = 1.f;
slMath::mul(VP, slVec4(point), point);
cv->m_data->m_data.baseData.UV.x = (float)(point.x / point.w);
cv->m_data->m_data.baseData.UV.y = (float)(-point.y / point.w);
//aabb2d.add(v3f(cv->m_data.m_uv.x, cv->m_data.m_uv.y, 0.f));
if (cv == lv)
break;
cv = cv->m_right;
}
if (cp == lp)
break;
cp = cp->m_right;
}
}
}
Download
Please enable JavaScript to view the comments powered by Disqus.