アフィリエイト広告を利用しています

広告

この広告は30日以上更新がないブログに表示されております。
新規記事の投稿を行うことで、非表示にすることが可能です。
posted by fanblog

2018年08月05日

《その432》面法線ベクトル,頂点法線ベクトル


 面法線ベクトル,頂点法線ベクトル

 面に垂直な直線を法線と呼びます。法線方向のベクトルを法線ベクトルといいますが、面から遠ざかる向きが正の向きです。
下図において、メッシュを構成する三角形の中の、例えば三角形576の法線ベクトル(面法線ベクトル)は薄紫色で表される右向き(x軸の正の向き)の矢印です。
したがって、 三角形576の面法線ベクトルは(1.0f, 0.0f, 0.0f)です。
※通常、法線ベクトルは、大きさ(長さ)が 1 になるように決めます。

 頂点法線ベクトルというのは、頂点を始点とするベクトルです。三角形576のように独立した平面の場合、3つの頂点法線ベクトルは全て面に垂直になります。
よって、各頂点における頂点法線ベクトルは下図の薄オレンジ色で表される右向き矢印です。
この場合の頂点法線ベクトルは、面法線ベクトルと同じで、(1.0f, 0.0f, 0.0f)ということになります。

add_e051.png


 面法線ベクトルは、光線の向きを表すベクトルとのなす角度を計算することによって面の明るさを決定する ために利用されます。
 前回《431》の Sample3DSceneRenderer.cpp 内にある下記のコードが、各頂点の座標と頂点法線ベクトルです。
三角形576のように独立した平面の場合には、面法線ベクトルは 頂点法線ベクトルと同じになります。

static VertexPositionColor verticesPosNrm[24];

// 頂点の座標
verticesPosNrm[ 0].pos = XMFLOAT3(-0.5f, -0.5f, -0.5f);
verticesPosNrm[ 1].pos = XMFLOAT3(-0.5f, -0.5f, 0.5f);
verticesPosNrm[ 2].pos = XMFLOAT3(-0.5f, 0.5f, -0.5f);
verticesPosNrm[ 3].pos = XMFLOAT3(-0.5f, 0.5f, 0.5f);
verticesPosNrm[ 4].pos = XMFLOAT3( 0.5f, -0.5f, -0.5f);
verticesPosNrm[ 5].pos = XMFLOAT3( 0.5f, -0.5f, 0.5f);
verticesPosNrm[ 6].pos = XMFLOAT3( 0.5f, 0.5f, -0.5f);
verticesPosNrm[ 7].pos = XMFLOAT3( 0.5f, 0.5f, 0.5f);


verticesPosNrm[ 8].pos = XMFLOAT3(-0.5f, -0.5f, -0.5f);
verticesPosNrm[ 9].pos = XMFLOAT3(-0.5f, -0.5f, 0.5f);
verticesPosNrm[10].pos = XMFLOAT3(-0.5f, 0.5f, -0.5f);
verticesPosNrm[11].pos = XMFLOAT3(-0.5f, 0.5f, 0.5f);
verticesPosNrm[12].pos = XMFLOAT3( 0.5f, -0.5f, -0.5f);
verticesPosNrm[13].pos = XMFLOAT3( 0.5f, -0.5f, 0.5f);
verticesPosNrm[14].pos = XMFLOAT3( 0.5f, 0.5f, -0.5f);
verticesPosNrm[15].pos = XMFLOAT3( 0.5f, 0.5f, 0.5f);

verticesPosNrm[16].pos = XMFLOAT3(-0.5f, -0.5f, -0.5f);
verticesPosNrm[17].pos = XMFLOAT3(-0.5f, -0.5f, 0.5f);
verticesPosNrm[18].pos = XMFLOAT3(-0.5f, 0.5f, -0.5f);
verticesPosNrm[19].pos = XMFLOAT3(-0.5f, 0.5f, 0.5f);
verticesPosNrm[20].pos = XMFLOAT3( 0.5f, -0.5f, -0.5f);
verticesPosNrm[21].pos = XMFLOAT3( 0.5f, -0.5f, 0.5f);
verticesPosNrm[22].pos = XMFLOAT3( 0.5f, 0.5f, -0.5f);
verticesPosNrm[23].pos = XMFLOAT3( 0.5f, 0.5f, 0.5f);

// 頂点法線ベクトル
verticesPosNrm[ 0].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 1].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 2].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 3].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 4].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);
verticesPosNrm[ 5].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);
verticesPosNrm[ 6].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);
verticesPosNrm[ 7].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);


verticesPosNrm[ 8].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[ 9].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);
verticesPosNrm[10].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[11].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);
verticesPosNrm[12].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[13].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);
verticesPosNrm[14].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[15].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);

verticesPosNrm[16].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[17].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[18].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);
verticesPosNrm[19].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);
verticesPosNrm[20].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[21].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[22].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);
verticesPosNrm[23].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);




《その431》シェーダ(平行光線の場合)(1)


 シェーダ(平行光線の場合)

 ウィキペディアによると、「シェーダー(英: shader)とは、3次元コンピュータグラフィックスにおいて、シェーディング(陰影処理)を行うコンピュータプログラムのこと」だそうです。

 本ブログの《427》~《429》では立方体を描画しましたが、今回は立方体に平行光線による陰影処理をしてみたいと思います。
次の画像は、陰影処理した立方体です。

 回転角度が 0度のとき
add_e041.png


 回転角度が 30度のとき
add_e043.png


 回転角度が 45度のとき
add_e044.png


 回転角度が 60度のとき
add_e045.png


 下記はプログラムですが、分量が多いので今回と次回は Sample3DSceneRenderer.cpp のコードについて のみです。
 ※次の3つのプログラムに関しては、《433》以降になります。
   ShaderStructures.h
   SamplePixelShader.hlsl
   SampleVertexShader.hlsl


 以下は、Sample3DSceneRenderer.cpp のコードです。
 ※コードは長いですが、陰影処理に関する箇所以外はデフォルトのサンプルアプリのままです。
(枠から右にはみだした部分のコードを見る際は、最下部のスクロールバーをご利用ください。)

#include "pch.h"
#include "Sample3DSceneRenderer.h"

#include "..\Common\DirectXHelper.h"

using namespace App20;

using namespace DirectX;
using namespace Windows::Foundation;

// ファイルから頂点とピクセルシェーダを読み込み、キューブのジオメトリをインスタンス化します。
Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
m_loadingComplete(false),
m_degreesPerSecond(45),
m_indexCount(0),
m_tracking(false),
m_deviceResources(deviceResources)
{
CreateDeviceDependentResources();
CreateWindowSizeDependentResources();
}

// ウィンドウのサイズが変更されたときに、ビューのパラメータを初期化します。
void Sample3DSceneRenderer::CreateWindowSizeDependentResources()
{
Size outputSize = m_deviceResources->GetOutputSize();
float aspectRatio = outputSize.Width / outputSize.Height;
float fovAngleY = 70.0f * XM_PI / 180.0f;

// これは、アプリケーションが縦向きビューまたはスナップビュー内にあるときに行うことのできる変更の簡単な例です。
if (aspectRatio < 1.0f)
{
fovAngleY *= 2.0f;
}

// OrientationTransform3D マトリックスは、シーンの方向を表示方向と正しく一致させるため、ここで事後乗算されます。
// この事後乗算ステップは、スワップチェーンのターゲットビットマップに対して行われるすべての描画呼び出しで実行する必要があります。
// 他のターゲットに対する呼び出しでは、適用する必要はありません。

// このサンプルでは、行優先のマトリックスを使用した右辺座標系を使用しています。

XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH(
fovAngleY,
aspectRatio,
0.01f,
100.0f
);

XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D();

XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);

XMStoreFloat4x4(
&m_constantBufferData.projection,
XMMatrixTranspose(perspectiveMatrix * orientationMatrix)
);

// 視点は (0,0.7,1.5) の位置にあり、y軸に沿って上方向のポイント (0,-0.1,0) を見ています。
static const XMVECTORF32 eye = { 0.0f, 0.7f, 1.5f, 0.0f };
static const XMVECTORF32 at = { 0.0f, -0.1f, 0.0f, 0.0f };
static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };

XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
}

// フレームごとに 1回呼び出し、キューブを回転させてから、モデルおよびビューのマトリックスを計算します。
void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
{
if (!m_tracking)
{
// 度をラジアンに変換し、秒を回転角度に変換します。
float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
double totalRotation = timer.GetTotalSeconds() * radiansPerSecond;
float radians = static_cast<float>(fmod(totalRotation, XM_2PI));

Rotate(radians);
}
}

// 3Dキューブモデルを、ラジアン単位で設定された大きさだけ回転させます。
void Sample3DSceneRenderer::Rotate(float radians)
{
// 更新されたモデルマトリックスをシェーダに渡す準備をします。
XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(radians)));
}

void Sample3DSceneRenderer::StartTracking()
{
m_tracking = true;
}

// 追跡時に、出力画面の幅方向を基準としてポインタの位置を追跡することにより、3Dキューブを Y軸に沿って回転させることができます。
void Sample3DSceneRenderer::TrackingUpdate(float positionX)
{
if (m_tracking)
{
float radians = XM_2PI * 2.0f * positionX / m_deviceResources->GetOutputSize().Width;
Rotate(radians);
}
}

void Sample3DSceneRenderer::StopTracking()
{
m_tracking = false;
}

// 頂点とピクセルシェーダを使用して、1つのフレームを描画します。
void Sample3DSceneRenderer::Render()
{
// 読み込みは非同期です。読み込みが完了した後にのみ描画してください。
if (!m_loadingComplete)
{
return;
}

auto context = m_deviceResources->GetD3DDeviceContext();

// 定数バッファを準備して、グラフィックスデバイスに送信します。
context->UpdateSubresource1(
m_constantBuffer.Get(),
0,
NULL,
&m_constantBufferData,
0,
0,
0
);

// 各頂点は、VertexPositionColor構造体の 1つのインスタンスです。
UINT stride = sizeof(VertexPositionColor);
UINT offset = 0;
context->IASetVertexBuffers(
0,
1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset
);

context->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT, // 各インデックスは、1つの 16ビット符号なし整数(short) です。
0
);

context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

context->IASetInputLayout(m_inputLayout.Get());

// 頂点シェーダをアタッチします。
context->VSSetShader(
m_vertexShader.Get(),
nullptr,
0
);

// 定数バッファをグラフィックスデバイスに送信します。
context->VSSetConstantBuffers1(
0,
1,
m_constantBuffer.GetAddressOf(),
nullptr,
nullptr
);

// ピクセルシェーダをアタッチします。
context->PSSetShader(
m_pixelShader.Get(),
nullptr,
0
);

// オブジェクトを描画します。
context->DrawIndexed(
m_indexCount,
0,
0
);
}

void Sample3DSceneRenderer::CreateDeviceDependentResources()
{
// シェーダを非同期で読み込みます。
auto loadVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso");
auto loadPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso");

// 頂点シェーダファイルを読み込んだ後、シェーダと入力レイアウトを作成します。
auto createVSTask = loadVSTask.then([this](const std::vector<byte>& fileData) {
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateVertexShader(
&fileData[0],
fileData.size(),
nullptr,
&m_vertexShader
)
);

static const D3D11_INPUT_ELEMENT_DESC vertexDesc [] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateInputLayout(
vertexDesc,
ARRAYSIZE(vertexDesc),
&fileData[0],
fileData.size(),
&m_inputLayout
)
);
});

// ピクセルシェーダファイルを読み込んだ後、シェーダと定数バッファを作成します。
auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) {
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreatePixelShader(
&fileData[0],
fileData.size(),
nullptr,
&m_pixelShader
)
);

CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer) , D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateBuffer(
&constantBufferDesc,
nullptr,
&m_constantBuffer
)
);
});

// 両方のシェーダの読み込みが完了したら、メッシュを作成します。
auto createCubeTask = (createPSTask && createVSTask).then([this] () {

// メッシュの頂点座標と頂点法線ベクトルを読み込みます。
static VertexPositionColor verticesPosNrm[24];
verticesPosNrm[ 0].pos = XMFLOAT3(-0.5f, -0.5f, -0.5f);
verticesPosNrm[ 1].pos = XMFLOAT3(-0.5f, -0.5f, 0.5f);
verticesPosNrm[ 2].pos = XMFLOAT3(-0.5f, 0.5f, -0.5f);
verticesPosNrm[ 3].pos = XMFLOAT3(-0.5f, 0.5f, 0.5f);
verticesPosNrm[ 4].pos = XMFLOAT3( 0.5f, -0.5f, -0.5f);
verticesPosNrm[ 5].pos = XMFLOAT3( 0.5f, -0.5f, 0.5f);
verticesPosNrm[ 6].pos = XMFLOAT3( 0.5f, 0.5f, -0.5f);
verticesPosNrm[ 7].pos = XMFLOAT3( 0.5f, 0.5f, 0.5f);

verticesPosNrm[ 8].pos = XMFLOAT3(-0.5f, -0.5f, -0.5f);
verticesPosNrm[ 9].pos = XMFLOAT3(-0.5f, -0.5f, 0.5f);
verticesPosNrm[10].pos = XMFLOAT3(-0.5f, 0.5f, -0.5f);
verticesPosNrm[11].pos = XMFLOAT3(-0.5f, 0.5f, 0.5f);
verticesPosNrm[12].pos = XMFLOAT3( 0.5f, -0.5f, -0.5f);
verticesPosNrm[13].pos = XMFLOAT3( 0.5f, -0.5f, 0.5f);
verticesPosNrm[14].pos = XMFLOAT3( 0.5f, 0.5f, -0.5f);
verticesPosNrm[15].pos = XMFLOAT3( 0.5f, 0.5f, 0.5f);

verticesPosNrm[16].pos = XMFLOAT3(-0.5f, -0.5f, -0.5f);
verticesPosNrm[17].pos = XMFLOAT3(-0.5f, -0.5f, 0.5f);
verticesPosNrm[18].pos = XMFLOAT3(-0.5f, 0.5f, -0.5f);
verticesPosNrm[19].pos = XMFLOAT3(-0.5f, 0.5f, 0.5f);
verticesPosNrm[20].pos = XMFLOAT3( 0.5f, -0.5f, -0.5f);
verticesPosNrm[21].pos = XMFLOAT3( 0.5f, -0.5f, 0.5f);
verticesPosNrm[22].pos = XMFLOAT3( 0.5f, 0.5f, -0.5f);
verticesPosNrm[23].pos = XMFLOAT3( 0.5f, 0.5f, 0.5f);

verticesPosNrm[ 0].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 1].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 2].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 3].nrm = XMFLOAT3(-1.0f, 0.0f, 0.0f);
verticesPosNrm[ 4].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);
verticesPosNrm[ 5].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);
verticesPosNrm[ 6].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);
verticesPosNrm[ 7].nrm = XMFLOAT3( 1.0f, 0.0f, 0.0f);

verticesPosNrm[ 8].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[ 9].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);
verticesPosNrm[10].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[11].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);
verticesPosNrm[12].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[13].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);
verticesPosNrm[14].nrm = XMFLOAT3( 0.0f, 0.0f, -1.0f);
verticesPosNrm[15].nrm = XMFLOAT3( 0.0f, 0.0f, 1.0f);

verticesPosNrm[16].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[17].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[18].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);
verticesPosNrm[19].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);
verticesPosNrm[20].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[21].nrm = XMFLOAT3( 0.0f, -1.0f, 0.0f);
verticesPosNrm[22].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);
verticesPosNrm[23].nrm = XMFLOAT3( 0.0f, 1.0f, 0.0f);


D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
vertexBufferData.pSysMem = verticesPosNrm;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(verticesPosNrm), D3D11_BIND_VERTEX_BUFFER);
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateBuffer(
&vertexBufferDesc,
&vertexBufferData,
&m_vertexBuffer
)
);

// メッシュのインデックスを読み込みます。インデックスの 3つ 1組の値のそれぞれは、画面上に描画される三角形を表します。
// たとえば、0,2,1 とは、頂点バッファのインデックス 0, 2, 1 にある頂点が、このメッシュの最初の三角形を構成することを意味します。

static const unsigned short cubeIndices [] =
{
0,2,1, // -x
1,2,3,

4,5,6, // +x
5,7,6,

16,17,21, // -y
16,21,20,

18,22,23, // +y
18,23,19,

8,12,10, // -z
10,12,14,

9,11,15, // +z
9,15,13,

};

m_indexCount = ARRAYSIZE(cubeIndices);

D3D11_SUBRESOURCE_DATA indexBufferData = {0};
indexBufferData.pSysMem = cubeIndices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateBuffer(
&indexBufferDesc,
&indexBufferData,
&m_indexBuffer
)
);
});

// キューブが読み込まれたら、オブジェクトを描画する準備が完了します。
createCubeTask.then([this] () {
m_loadingComplete = true;
});
}

void Sample3DSceneRenderer::ReleaseDeviceDependentResources()
{
m_loadingComplete = false;
m_vertexShader.Reset();
m_inputLayout.Reset();
m_pixelShader.Reset();
m_constantBuffer.Reset();
m_vertexBuffer.Reset();
m_indexBuffer.Reset();
}





 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


検索
<< 2018年08月 >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
プロフィール
こうすけさんの画像
こうすけ

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


×

この広告は30日以上新しい記事の更新がないブログに表示されております。