Update vector
When I started I wanted to do some experiment - not to use template classes.
When I wrote this page I understood that this is not good for vectors and matrices.
I needed to write a lot of code.
I need to write template class for vector.
Like this
template<typename T>
class slVec3_t
{
public:
slVec3_t() {}
slVec3_t(T X, T Y, T Z) :
x(X),
y(Y),
z(Z)
{}
...
I need new type. User can choose what to use, float or double
Add in slDefs.h
using real_t = double;
And add this for vector
using slVec3 = slVec3_t<real_t>;
using slVec3f = slVec3_t<float>;
using slVec4 = slVec4_t<real_t>;
using slVec4f = slVec4_t<float>;
Matrix
Matrix will be like this
template<typename T>
class slMatrix4_t
{
public:
slMatrix4_t() { identity(); }
...
slVec4_t<T> m_data[4];
T* data() { return &m_data[0].x; }
};
Short version for double
using slMat4 = slMatrix4_t<real_t>;
Quaternion
For rotations I want to use quaternions. Only them. I used them only
together with matrices. Quaternion multiplications are faster than matrix multiplication.
I don't know how all this works...I think, I still need World matrix for drawing.
class slQuaternion
{
public:
slQuaternion();
slQuaternion(const slQuaternion&);
slQuaternion(float x, float y, float z, float w);
void identity();
slQuaternion& operator=(const slQuaternion& o);
slQuaternion operator*(const slQuaternion& q)const;
slQuaternion operator*(float s) const;
void operator*=(const slQuaternion& q);
bool operator!=(const slQuaternion& q)const;
bool operator==(const slQuaternion& q)const;
slQuaternion operator+(const slQuaternion& o) const;
slQuaternion operator-(const slQuaternion& o) const;
slQuaternion operator-();
float operator[](uint32_t index) const;
float& operator[](uint32_t index);
float x, y, z, w;
float* data() { return &x; }
};
In slMath added this methods
static float dot(const slQuaternion& v1, const slQuaternion& v2);
static float length(const slQuaternion& v);
static void lerp1(const slQuaternion& x, const slQuaternion& y, float t, slQuaternion& r);
static void lerp2(const slQuaternion& x, const slQuaternion& y, float t, slQuaternion& r);
static void set_rotation(slQuaternion&, float x, float y, float z);
static void set_rotation(slQuaternion&, const slVec3& axis, const real_t& _angle);
static void set_rotation(slQuaternion&, const slVec3f& axis, const float& _angle);
static void set_rotation(slQuaternion&, const slVec4& axis, const real_t& _angle);
static void set_rotation(slQuaternion&, const slVec4f& axis, const float& _angle);
// from assimp?
static void slerp(slQuaternion& q1, slQuaternion& q2, float time, float threshold, slQuaternion& r);
Set angles
void slMath::set_rotation(slQuaternion& q, float x, float y, float z)
{
x *= 0.5f;
y *= 0.5f;
z *= 0.5f;
float c1 = ::cosf(x);
float c2 = ::cosf(y);
float c3 = ::cosf(z);
float s1 = ::sinf(x);
float s2 = ::sinf(y);
float s3 = ::sinf(z);
q.w = (c1 * c2 * c3) + (s1 * s2 * s3);
q.x = (s1 * c2 * c3) - (c1 * s2 * s3);
q.y = (c1 * s2 * c3) + (s1 * c2 * s3);
q.z = (c1 * c2 * s3) - (s1 * s2 * c3);
}
I need to add other methods for matrices and quaternions.
Create matrix using quaternion
void slMath::set_rotation(slMat4& m, const slQuaternion& q)
{
real_t d = length(q);
real_t s = 2.0f / d;
real_t xs = q.x * s, ys = q.y * s, zs = q.z * s;
real_t wx = q.w * xs, wy = q.w * ys, wz = q.w * zs;
real_t xx = q.x * xs, xy = q.x * ys, xz = q.x * zs;
real_t yy = q.y * ys, yz = q.y * zs, zz = q.z * zs;
m.set(
1.0f - (yy + zz), xy - wz, xz + wy,
xy + wz, 1.0f - (xx + zz), yz - wx,
xz - wy, yz + wx, 1.0f - (xx + yy));
}
3D line
Add new method in GS
virtual void DrawLine3D(const slVec3& p1, const slVec3& p2, const slColor& c) = 0;
Implementation
below
I need to write slFramework::GetMatrix, all matrices for rendering will be located
inside framework.
After this, I need to create shader for drawing lines.
In slFramework.h I add
enum class slMatrixType : uint32_t
{
World,
View,
Projection,
ViewProjection, //For 3d line
WorldViewProjection,
ViewInvert,
//GUIProjection,
_count
};
And method for slFramework
static slMat4* GetMatrix(slMatrixType);
static void SetMatrix(slMatrixType, slMat4*);
It working with pointers. Matrices MUST exists when I need to draw something
There is will be a lot of matrices, and I DON"T want to copy them all the time.
Implementation
In slFrameworkImpl
slMat4* m_matrixPtrs[(uint32_t)slMatrixType::_count];
Methods
slMat4* slFramework::GetMatrix(slMatrixType t)
{
return g_framework->m_matrixPtrs[(uint32_t)t];
}
void slFramework::SetMatrix(slMatrixType t, slMat4* m)
{
g_framework->m_matrixPtrs[(uint32_t)t] = m;
}
I need to create a shader.
In d3d11 library I add new class - base class for all shaders.
class slGSD3D11ShaderBase
{
public:
slGSD3D11ShaderBase() :
m_vShader(0),
m_pShader(0),
m_gShader(0),
m_vLayout(0)
{}
virtual ~slGSD3D11ShaderBase()
{
if (m_vLayout) m_vLayout->Release();
if (m_gShader) m_gShader->Release();
if (m_vShader) m_vShader->Release();
if (m_pShader) m_pShader->Release();
}
ID3D11VertexShader* m_vShader;
ID3D11PixelShader* m_pShader;
ID3D11GeometryShader* m_gShader;
ID3D11InputLayout* m_vLayout;
virtual void SetConstants(/*slMaterial* material*/) = 0;
};
Also I need functions for shader creation (in slGSD3D11)
bool createShaders(
const char* vertexTarget,
const char* pixelTarget,
const char* vertexShader,
const char* pixelShader,
const char* vertexEntryPoint,
const char* pixelEntryPoint,
slMeshVertexType vertexType,
ID3D11VertexShader** vs,
ID3D11PixelShader** ps,
ID3D11InputLayout** il);
bool createConstantBuffer(uint32_t byteSize, ID3D11Buffer**);
bool createGeometryShaders(const char* target,
const char* shaderText,
const char* entryPoint,
ID3D11GeometryShader** gs);
I need slMeshVertexType. Need to create new .h file for this.
For future.
Enum there.
enum class slMeshVertexType : uint32_t
{
Null, // 0
};
Shader creation
bool createShaders(
const char* vertexTarget,
const char* pixelTarget,
const char* vertexShader,
const char* pixelShader,
const char* vertexEntryPoint,
const char* pixelEntryPoint,
slMeshVertexType vertexType,
ID3D11VertexShader** vs,
ID3D11PixelShader** ps,
ID3D11InputLayout** il);
bool createConstantBuffer(uint32_t byteSize, ID3D11Buffer**);
bool createGeometryShaders(const char* target,
const char* shaderText,
const char* entryPoint,
ID3D11GeometryShader** gs);
Implementation
bool slGSD3D11::createConstantBuffer(uint32_t byteSize, ID3D11Buffer** cb)
{
D3D11_BUFFER_DESC mbd;
memset(&mbd, 0, sizeof(mbd));
mbd.Usage = D3D11_USAGE_DYNAMIC;
mbd.ByteWidth = byteSize;
mbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
mbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
mbd.MiscFlags = 0;
mbd.StructureByteStride = 0;
HRESULT hr = m_d3d11Device->CreateBuffer(&mbd, 0, cb);
if (FAILED(hr))
{
slLog::PrintError("Can't create constant buffer. Error code [%u]\n", hr);
return false;
}
return true;
}
bool slGSD3D11::createGeometryShaders(const char* target,
const char* shaderText,
const char* entryPoint,
ID3D11GeometryShader** gs)
{
ID3D10Blob* m_GsBlob = nullptr;
ID3D10Blob* m_errorBlob = nullptr;
HRESULT hr = D3DCompile(
shaderText,
strlen(shaderText),
0, 0, 0,
entryPoint,
target,
0,
0,
&m_GsBlob,
&m_errorBlob
);
if (FAILED(hr))
{
char* message = (char*)m_errorBlob->GetBufferPointer();
slLog::PrintError("Geometry shader compile error: %s\n", message);
return false;
}
hr = m_d3d11Device->CreateGeometryShader(
m_GsBlob->GetBufferPointer(),
m_GsBlob->GetBufferSize(),
0,
gs);
if (FAILED(hr))
{
slLog::PrintError("Can't create geometry shader. Error code [%u]\n", hr);
return false;
}
return true;
}
bool slGSD3D11::createShaders(
const char* vertexTarget,
const char* pixelTarget,
const char* vertexShader,
const char* pixelShader,
const char* vertexEntryPoint,
const char* pixelEntryPoint,
slMeshVertexType vertexType,
ID3D11VertexShader** vs,
ID3D11PixelShader** ps,
ID3D11InputLayout** il)
{
ID3D10Blob* m_VsBlob = nullptr;
ID3D10Blob* m_PsBlob = nullptr;
ID3D10Blob* m_errorBlob = nullptr;
HRESULT hr = D3DCompile(
vertexShader,
strlen(vertexShader),
0, 0, 0,
vertexEntryPoint,
vertexTarget,
0,
0,
&m_VsBlob,
&m_errorBlob
);
if (FAILED(hr))
{
char* message = (char*)m_errorBlob->GetBufferPointer();
slLog::PrintError("Vertex shader compile error: %s\n", message);
return false;
}
hr = D3DCompile(
pixelShader,
strlen(pixelShader),
0, 0, 0,
pixelEntryPoint,
pixelTarget,
0,
0,
&m_PsBlob,
&m_errorBlob
);
if (FAILED(hr))
{
char* message = (char*)m_errorBlob->GetBufferPointer();
slLog::PrintError("Pixel shader compile error: %s\n", message);
return false;
}
hr = m_d3d11Device->CreateVertexShader(
m_VsBlob->GetBufferPointer(),
m_VsBlob->GetBufferSize(),
0,
vs);
if (FAILED(hr))
{
slLog::PrintError("Can't create vertex shader. Error code [%u]\n", hr);
return false;
}
hr = m_d3d11Device->CreatePixelShader(
m_PsBlob->GetBufferPointer(),
m_PsBlob->GetBufferSize(),
0,
ps);
if (FAILED(hr))
{
slLog::PrintError("Can't create pixel shader. Error code [%u]\n", hr);
return false;
}
if (vertexType != slMeshVertexType::Null)
{
D3D11_INPUT_ELEMENT_DESC vertexLayout[8];
uint32_t vertexLayoutSize = 0;
/*
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
*/
int ind = 0;
// for future
/*switch (vertexType)
{
default:
slLog::PrintError("Unsupportex vertex type\n");
return false;
}*/
vertexLayoutSize = ind + 1;
hr = m_d3d11Device->CreateInputLayout(
vertexLayout,
vertexLayoutSize,
m_VsBlob->GetBufferPointer(),
m_VsBlob->GetBufferSize(),
il);
if (FAILED(hr))
{
slLog::PrintError("Can't create input layout. Error code [%u]\n", hr);
return false;
}
}
if (m_VsBlob) m_VsBlob->Release();
if (m_PsBlob) m_PsBlob->Release();
if (m_errorBlob) m_errorBlob->Release();
return true;
}
For D3DCompile I need to include file and link .lib
#include <d3dcompiler.h>
#pragma comment(lib, "d3dcompiler.lib")
Shader for line.
class slD3D11ShaderLine3D : public slGSD3D11ShaderBase
{
public:
slD3D11ShaderLine3D(slGSD3D11* gs);
virtual ~slD3D11ShaderLine3D();
slGSD3D11* m_gs = 0;
ID3D11Buffer* m_cb = 0;
struct cb
{
slMat4 VP;
slVec4 P1;
slVec4 P2;
slColor Color;
}m_cbData;
virtual void SetConstants(/*slMaterial* material*/);
void SetData(const slVec3& p1, const slVec3& p2, const slColor& color, const slMat4& projMat);
bool init();
};
Implementation
slD3D11ShaderLine3D::slD3D11ShaderLine3D(slGSD3D11* gs) : m_gs(gs){}
slD3D11ShaderLine3D::~slD3D11ShaderLine3D() {}
bool slD3D11ShaderLine3D::init(){
const char* text =
"struct VSIn{\n"
" uint vertexID : SV_VertexID;\n"
"};\n"
"cbuffer cbVertex{\n"
" double4x4 VP;\n"
" double4 P1;\n"
" double4 P2;\n"
" float4 Color;\n"
"};\n"
"struct VSOut{\n"
" float4 pos : SV_POSITION;\n"
" float4 color : COLOR0;\n"
"};\n"
"struct PSOut{\n"
" float4 color : SV_Target;\n"
"};\n"
"VSOut VSMain(VSIn input){\n"
"double4 vertices[2] = {\n"
"double4( P1.xyz, 1.0),\n"
"double4( P2.xyz, 1.0)\n"
"};\n"
" VSOut output;\n"
" output.pos = mul(VP, vertices[input.vertexID]);\n"
" output.color = Color;\n"
" return output;\n"
"}\n"
"PSOut PSMain(VSOut input){\n"
" PSOut output;\n"
" output.color = input.color;\n"
" return output;\n"
"}\n";
if (!m_gs->createShaders(
"vs_5_0",
"ps_5_0",
text,
text,
"VSMain",
"PSMain",
slMeshVertexType::Null,
&this->m_vShader,
&this->m_pShader,
&this->m_vLayout))
return false;
if (!m_gs->createConstantBuffer(sizeof(cb), &m_cb))
return false;
return true;
}
void slD3D11ShaderLine3D::SetData(const slVec3& p1, const slVec3& p2, const slColor& color, const slMat4& projMat)
{
m_cbData.P1 = p1;
m_cbData.P2 = p2;
m_cbData.P1.w = 1.f;
m_cbData.P2.w = 1.f;
m_cbData.Color = color;
m_cbData.VP = projMat;
}
void slD3D11ShaderLine3D::SetConstants(/*miMaterial* material*/){
m_gs->m_d3d11DevCon->VSSetConstantBuffers(0, 1, &m_cb);
D3D11_MAPPED_SUBRESOURCE mappedResource;
m_gs->m_d3d11DevCon->Map(m_cb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
D3D11_BUFFER_DESC d;
m_cb->GetDesc(&d);
memcpy(mappedResource.pData, &m_cbData, d.ByteWidth);
m_gs->m_d3d11DevCon->Unmap(m_cb, 0);
}
Create this shader. In slGSD3D11
slD3D11ShaderLine3D* m_shaderLine3D = 0;
Add method
bool CreateShaders();
Implementation
bool slGSD3D11::CreateShaders()
{
m_shaderLine3D = slCreate<slD3D11ShaderLine3D>(this);
if (!m_shaderLine3D->init())
return false;
return true;
}
Call it in Init
if (!CreateShaders())
{
slLog::PrintError("Can't create Direct3D 11 shader\n");
return false;
}
Add SetActiveShader
void slGSD3D11::SetActiveShader(slGSD3D11ShaderBase* shader)
{
m_activeShader = shader;
m_d3d11DevCon->IASetInputLayout(shader->m_vLayout);
m_d3d11DevCon->VSSetShader(shader->m_vShader, 0, 0);
m_d3d11DevCon->GSSetShader(shader->m_gShader, 0, 0);
m_d3d11DevCon->PSSetShader(shader->m_pShader, 0, 0);
}
Now draw 3D line
void slGSD3D11::DrawLine3D(const slVec3& p1, const slVec3& p2, const slColor& c)
{
m_d3d11DevCon->IASetInputLayout(NULL);
m_d3d11DevCon->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
SetActiveShader(m_shaderLine3D);
m_shaderLine3D->SetData(p1, p2, c, *slFramework::GetMatrix(slMatrixType::ViewProjection));
m_shaderLine3D->SetConstants(/*0*/);
m_d3d11DevCon->Draw(2, 0);
}
Camera
Camera is a class for easy creation some matrices and some other data.
For drawing you need view matrix, and projection matrix.
View matrix is just a rotation matrix.
Projection matrix it's like moving point from 3D world space into 2D
screen, with range from -1 to +1.
class slCamera
{
public:
slCamera();
~slCamera();
/*enum class Direction : uint32_t
{
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest
};*/
slMat4 m_projectionMatrix;
slMat4 m_viewMatrix;
slMat4 m_viewMatrixInvert;
slMat4 m_viewProjectionMatrix;
slMat4 m_viewProjectionInvertMatrix;
float m_near = 0.01f;
float m_far = 2500.f;
float m_fov = 0.683264f;
float m_aspect = 1.3333333f;
slCameraFrustum m_frust;
slVec3 m_position;
slVec3 m_target;
slVec3 m_up;
void Update();
};
First version. I add other things like slCameraFrustum later.
Update()
void slCamera::Update()
{
slMath::perspectiveLH(m_projectionMatrix, m_fov, m_aspect, m_near, m_far);
slMath::lookAtLH(m_viewMatrix, m_position, m_target, m_up);
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);
}
Drawing
slVec3 globalPosition;
globalPosition.set(99990000.f, 0.f, 0.f);
slCamera* camera = slFramework::SummonCamera();
camera->m_position = globalPosition + slVec3(10.f, 10.f, 10.f);
camera->m_target = globalPosition;
camera->Update();
slFramework::SetMatrix(slMatrixType::ViewProjection, &camera->m_viewProjectionMatrix);
float* dt = slFramework::GetDeltaTime();
while (g_isRun)
{
slFramework::Update();
camera->Update();
....
if (gs)
{
gs->BeginDraw();
gs->ClearAll();
gs->DrawLine3D(slVec3(globalPosition.x + 1.f, globalPosition.y,
globalPosition.z), slVec3(globalPosition.x -1.f, globalPosition.y,
globalPosition.z), ColorRed);
gs->DrawLine3D(slVec3(globalPosition.x, globalPosition.y + 1.f,
globalPosition.z), slVec3(globalPosition.x, globalPosition .y -1.f,
globalPosition.z), ColorYellow);
gs->DrawLine3D(slVec3(globalPosition.x, globalPosition.y,
globalPosition.z + 1.f), slVec3(globalPosition.x, globalPosition.y,
globalPosition.z -1.f), ColorLime);
gs->EndDraw();
gs->SwapBuffers();
}
}
Using double in shader, I figured out that this is very easy thing for D3D11.
Download
Please enable JavaScript to view the comments powered by Disqus.