Box Example을 Windows Template랑 합치는데 성공하였습니다.

 

 

 

Register 부분이 주요 틀을 합치는데 유효하고, WinProc가 메뉴 버튼 클릭 이벤트를 담당합니다.

 

다만 현재는 Box Example 코드에 Windows 코드가 포함된 형태라 원래 원하던 기능을 구현한 것은 아닙니다.

 

그래도 이 이상 늘어지는 것보다 일단 진행하는 것이 좋다고 판단하여, 

다음에는 코드 분석을 하고 그 뒤의 챕터를 공부하려 합니다.

 

나중에 시간이 남을 때 DirectX 코드와 Windows 코드를 분리하고 이후 다시 한번 코드를 공유하겠습니다.

 

더보기
// DirectX12ExampleCode.cpp : Defines the entry point for the application.
//

#include "framework.h"
#include "DirectX12ExampleCode.h"
#include "Example/BoxApp.h"

// Forward declarations of functions included in this code module:
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    D3DApp* App = new BoxApp(hInstance);

    // Initialize global strings
    //LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    //LoadStringW(hInstance, IDC_DIRECTX12EXAMPLECODE, szWindowClass, MAX_LOADSTRING);

    // Perform application initialization:
    if (!App->Initialize())
    {
        return FALSE;
    }

    // Main message loop:
    try
    {
        return App->run();
    }
    catch (DXException& e)
    {
        MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
        return 0;
    }
}

 

더보기
#include "D3DApp.h"
#include <cassert>

using namespace std;
using namespace Microsoft::WRL;

LRESULT CALLBACK
MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	return D3DApp::GetApp()->MsgProc(hwnd, msg, wParam, lParam);
}

D3DApp* D3DApp::mApp = nullptr;
D3DApp* D3DApp::GetApp()
{
	return mApp;
}

D3DApp::D3DApp(HINSTANCE hInstance) : mhAppInst(hInstance)
{
	assert(mApp == nullptr);
	mApp = this;
}

D3DApp::~D3DApp()
{
	if (md3dDevice != nullptr)
	{
		FlushCommandQueue();
	}
}

HINSTANCE D3DApp::AppInst() const
{
	return mhAppInst;
}

HWND D3DApp::MainWnd() const
{
	return mhMainWnd;
}

float D3DApp::AspectRatio() const
{
	return static_cast<float>(mClientWidth) / mClientHeight;
}

bool D3DApp::Get4xMsaaState() const
{
	return m4xMsaaState;
}

void D3DApp::Set4xMsaaState(bool value)
{
	if (m4xMsaaState != value)
	{
		m4xMsaaState = value;
		CreateSwapChain();
		OnResize();
	}
}

int D3DApp::run()
{
	//HACCEL hAccelTable = LoadAccelerators(mhAppInst, MAKEINTRESOURCE(IDC_DIRECTX12EXAMPLECODE));
	MSG msg{ 0 };
	mTimer.Reset();

	while (msg.message != WM_QUIT)
	{
		//TranslateAccelerator(msg.hwnd, hAccelTable, &msg)
		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			mTimer.Tick();

			if (!mAppPaused)
			{
				CalculateFrameStats();
				Update(mTimer);
				Draw(mTimer);
			}
			else
			{
				Sleep(100);
			}
		}
	}
	return static_cast<int>(msg.wParam);
}

bool D3DApp::Initialize()
{
	if (!InitMainWindow())
	{
		return false;
	}
	if (!InitDirect3D())
	{
		return false;
	}

	OnResize();
	return true;
}

void D3DApp::CreateRtvAndDsvDescriptorHeaps()
{
	D3D12_DESCRIPTOR_HEAP_DESC rtvheapDesc;
	rtvheapDesc.NumDescriptors = SwapChainBufferCount;
	rtvheapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
	rtvheapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
	rtvheapDesc.NodeMask = 0;
	ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&rtvheapDesc, IID_PPV_ARGS(mRtvHeap.GetAddressOf())));

	D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc;
	dsvHeapDesc.NumDescriptors = 1;
	dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
	dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
	dsvHeapDesc.NodeMask = 0;
	ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(mDsvHeap.GetAddressOf())));
}

void D3DApp::OnResize()
{
	assert(md3dDevice);
	assert(mSwapChain);
	assert(mDirectCmdListAlloc);

	FlushCommandQueue();

	ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
	
	for (int i = 0; i < SwapChainBufferCount; ++i)
	{
		mSwapChainbuffer[i].Reset();
	}
	mDepthStencilBuffer.Reset();

	ThrowIfFailed(mSwapChain->ResizeBuffers(
		SwapChainBufferCount, 
		mClientWidth, 
		mClientHeight, 
		mBackBufferFormat, 
		DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH));

	mCurrentBackBuffer = 0;

	D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(mRtvHeap->GetCPUDescriptorHandleForHeapStart());
	for (UINT i = 0; i < SwapChainBufferCount; ++i)
	{
		ThrowIfFailed(mSwapChain->GetBuffer(i, IID_PPV_ARGS(&mSwapChainbuffer[i])));
		md3dDevice->CreateRenderTargetView(mSwapChainbuffer[i].Get(), nullptr, rtvHeapHandle);
		rtvHeapHandle.ptr += mRtvDescriptorSize;
	}

	D3D12_RESOURCE_DESC depthStencilDesc;
	depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
	depthStencilDesc.Alignment = 0;
	depthStencilDesc.Width = mClientWidth;
	depthStencilDesc.Height = mClientHeight;
	depthStencilDesc.DepthOrArraySize = 1;
	depthStencilDesc.MipLevels = 1;
	
	depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
	depthStencilDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
	depthStencilDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
	depthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
	depthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;

	D3D12_CLEAR_VALUE optClear;
	optClear.Format = mDepthStencilFormat;
	optClear.DepthStencil.Depth = 1.f;
	optClear.DepthStencil.Stencil = 0;
	
	D3D12_HEAP_PROPERTIES HeapProperty;
	HeapProperty.Type = D3D12_HEAP_TYPE_DEFAULT;
	HeapProperty.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	HeapProperty.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
	HeapProperty.CreationNodeMask = 1;
	HeapProperty.VisibleNodeMask = 1;

	ThrowIfFailed(md3dDevice->CreateCommittedResource(
		&HeapProperty, D3D12_HEAP_FLAG_NONE, 
		&depthStencilDesc, D3D12_RESOURCE_STATE_COMMON, 
		&optClear, IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf())));

	D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
	dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
	dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
	dsvDesc.Format = mDepthStencilFormat;
	dsvDesc.Texture2D.MipSlice = 0;
	md3dDevice->CreateDepthStencilView(mDepthStencilBuffer.Get(), &dsvDesc, DepthStencilView());

	D3D12_RESOURCE_BARRIER Barrier;
	ZeroMemory(&Barrier, sizeof(Barrier));
	Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
	Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
	Barrier.Transition.pResource = mDepthStencilBuffer.Get();
	Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
	Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_DEPTH_WRITE;
	mCommandList->ResourceBarrier(1, &Barrier);

	ThrowIfFailed(mCommandList->Close());
	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

	FlushCommandQueue();

	mScreenViewport.TopLeftX = 0;
	mScreenViewport.TopLeftY = 0;
	mScreenViewport.Width = static_cast<float>(mClientWidth);
	mScreenViewport.Height = static_cast<float>(mClientHeight);
	mScreenViewport.MinDepth = 0.0f;
	mScreenViewport.MaxDepth = 1.0f;

	mScissorRect = { 0, 0, mClientWidth, mClientHeight };
}

LRESULT D3DApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	//WndProc
	switch (msg)
	{
	case WM_COMMAND:
	{
		int wmId = LOWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			//DialogBox(mhAppInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, About);
			break;
		case ID_EXAMPLE_CHAPTER6:

			break;
		case IDM_EXIT:
			DestroyWindow(hwnd);
			break;
		default:
			return DefWindowProc(hwnd, msg, wParam, lParam);
		}
	}
		break;
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hwnd, &ps);
		// TODO: Add any drawing code that uses hdc here...
		EndPaint(hwnd, &ps);
	}
	break;
	case WM_ACTIVATE:
		if (LOWORD(wParam) == WA_INACTIVE)
		{
			mAppPaused = true;
			mTimer.Stop();
		}
		else
		{
			mAppPaused = false;
			mTimer.Start();
		}
		return 0;
	case WM_SIZE:
		mClientWidth = LOWORD(lParam);
		mClientHeight = HIWORD(lParam);
		if (md3dDevice)
		{
			if (wParam == SIZE_MINIMIZED)
			{
				mAppPaused = true;
				mMinimized = true;
				mMaximized = false;
			}
			else if (wParam == SIZE_MAXIMIZED)
			{
				mAppPaused = false;
				mMinimized = false;
				mMaximized = true;
				OnResize();
			}
			else if (wParam == SIZE_RESTORED)
			{
				if (mMinimized)
				{
					mAppPaused = false;
					mMinimized = false;
					OnResize();
				}
				else if (mMaximized)
				{
					mAppPaused = false;
					mMaximized = false;
					OnResize();
				}
				else if (mResizing)
				{

				}
				else
				{
					OnResize();
				}
			}
		}
		return 0;
	case WM_ENTERSIZEMOVE:
		mAppPaused = true;
		mResizing = true;
		mTimer.Stop();
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_MENUCHAR:
		return MAKELRESULT(0, MNC_CLOSE);
	case WM_GETMINMAXINFO:
		((MINMAXINFO*)lParam)->ptMinTrackSize.x = 200;
		((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200;
		return 0;
	case WM_LBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_RBUTTONDOWN:
		OnMouseDown(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		return 0;
	case WM_LBUTTONUP:
	case WM_MBUTTONUP:
	case WM_RBUTTONUP:
		OnMouseUp(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		return 0;
	case WM_MOUSEMOVE:
		OnMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		return 0;
	case WM_KEYUP:
		if (wParam == VK_ESCAPE)
		{
			PostQuitMessage(0);
		}
		else if (static_cast<int>(wParam) == VK_F2)
		{
			Set4xMsaaState(!m4xMsaaState);
		}
		return 0;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}

bool D3DApp::InitMainWindow()
{
	WNDCLASSEXW wc;
	if (!MyRegisterClass(wc))
	{
		MessageBox(0, L"RegisterClass Failed.", 0, 0);
		return false;
	}
	return InitInstance(SW_SHOW);
}

bool D3DApp::InitDirect3D()
{
#if defined(DEBUG) || defined(_DEBUG)
	{
		ComPtr<ID3D12Debug> debugController;
		ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));
		debugController->EnableDebugLayer();
	}
#endif

	ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&mdxgiFactory)));

	HRESULT hardwareResult = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&md3dDevice));

	if (FAILED(hardwareResult))
	{
		ComPtr<IDXGIAdapter4> pWarpAdapter;
		ThrowIfFailed(mdxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter)));

		ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(), D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&md3dDevice)));
	}

	ThrowIfFailed(md3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)));

	mRtvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
	mDsvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
	mCbvSrvUavDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

	D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
	msQualityLevels.Format = mBackBufferFormat;
	msQualityLevels.SampleCount = 4;
	msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
	msQualityLevels.NumQualityLevels = 0;
	ThrowIfFailed(md3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msQualityLevels, sizeof(msQualityLevels)));

	m4xMsaaQuality = msQualityLevels.NumQualityLevels;
	assert(m4xMsaaQuality > 0 && "Unexpected Msaa quality level.");

#ifdef _DEBUG
	LogAdpaters();
#endif
	
	CreateCommandObjects();
	CreateSwapChain();
	CreateRtvAndDsvDescriptorHeaps();

	return true;
}

void D3DApp::CreateCommandObjects()
{
	D3D12_COMMAND_QUEUE_DESC queueDesc = {};
	queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
	queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
	ThrowIfFailed(md3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)));

	ThrowIfFailed(md3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mDirectCmdListAlloc.GetAddressOf())));

	ThrowIfFailed(md3dDevice->CreateCommandList(
		0, 
		D3D12_COMMAND_LIST_TYPE_DIRECT, 
		mDirectCmdListAlloc.Get(), 
		nullptr, 
		IID_PPV_ARGS(mCommandList.GetAddressOf())));

	mCommandList->Close();
}

void D3DApp::CreateSwapChain()
{
	mSwapChain.Reset();
	
	DXGI_SWAP_CHAIN_DESC sd;
	sd.BufferDesc.Width = mClientWidth;
	sd.BufferDesc.Height = mClientHeight;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferDesc.Format = mBackBufferFormat;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	sd.SampleDesc.Count = m4xMsaaState ? 4 : 1;
	sd.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount = SwapChainBufferCount;
	sd.OutputWindow = mhMainWnd;
	sd.Windowed = true;
	sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
	

	ThrowIfFailed(mdxgiFactory->CreateSwapChain(mCommandQueue.Get(), &sd, mSwapChain.GetAddressOf()));
	//ThrowIfFailed(mdxgiFactory->CreateSwapChainForHwnd(mCommandQueue.Get(), mhMainWnd, &sd1, &swapChainFSDesc, nullptr, &mSwapChain));
	//not recommand to use CreateSwapChain
}

void D3DApp::FlushCommandQueue()
{
	++mCurrentFence;
	
	ThrowIfFailed(mCommandQueue->Signal(mFence.Get(), mCurrentFence));

	if (mFence->GetCompletedValue() < mCurrentFence)
	{
		HANDLE eventHandle = CreateEvent(nullptr, false, false, nullptr);
		//HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
		//https://github.com/microsoft/DirectX-Graphics-Samples/issues/15

		ThrowIfFailed(mFence->SetEventOnCompletion(mCurrentFence, eventHandle));

		WaitForSingleObject(eventHandle, INFINITE);
		CloseHandle(eventHandle);
	}
}

ID3D12Resource* D3DApp::CurrentBackBuffer() const
{
	return mSwapChainbuffer[mCurrentBackBuffer].Get();
}

D3D12_CPU_DESCRIPTOR_HANDLE D3DApp::CurrentBackBufferView() const
{
	D3D12_CPU_DESCRIPTOR_HANDLE result(mRtvHeap->GetCPUDescriptorHandleForHeapStart());
	result.ptr += mCurrentBackBuffer * mRtvDescriptorSize;
	return result;
}

D3D12_CPU_DESCRIPTOR_HANDLE D3DApp::DepthStencilView() const
{
	return mDsvHeap->GetCPUDescriptorHandleForHeapStart();
}

void D3DApp::CalculateFrameStats()
{
	static int frameCnt = 0;
	static float timeElapse = 0.f;

	++frameCnt;

	if ((mTimer.TotalTime() - timeElapse) >= 1.f)
	{
		float fps = static_cast<float>(frameCnt);
		float mspf = 1000.f / fps;
		
		wstring fpsStr = to_wstring(fps);
		wstring mspStr = to_wstring(mspf);

		wstring windowText = mMainWndCaption + L",    fps: " + fpsStr + L"ms,    pf: " + mspStr;

		SetWindowText(mhMainWnd, windowText.c_str());
		frameCnt = 0;
		timeElapse += 1.f;
	}
}

void D3DApp::LogAdpaters()
{
	UINT i = 0;
	IDXGIAdapter* adapter = nullptr;
	std::vector<IDXGIAdapter*> adapterList;
	while (mdxgiFactory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND)
	{
		DXGI_ADAPTER_DESC desc;
		adapter->GetDesc(&desc);

		std::wstring text = L"***Adpater: ";
		text += desc.Description;
		text += L"\n";

		OutputDebugString(text.c_str());

		adapterList.push_back(adapter);

		++i;
	}

	for (size_t i = 0; i < adapterList.size(); ++i)
	{
		LogAdpaterOutputs(adapterList[i]);
		if (adapterList[i])
		{
			adapterList[i]->Release();
			adapterList[i] = 0;
		}
	}
}

void D3DApp::LogAdpaterOutputs(IDXGIAdapter* adapter)
{
	UINT i = 0;
	IDXGIOutput* output = nullptr;
	while (adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND)
	{
		DXGI_OUTPUT_DESC desc;
		output->GetDesc(&desc);

		std::wstring text = L"***Output: ";
		text += desc.DeviceName;
		text += L"\n";
		OutputDebugString(text.c_str());

		LogOutputDisplayModes(output, mBackBufferFormat);

		if (output)
		{
			output->Release();
			output = 0;
		}

		++i;
	}
}

void D3DApp::LogOutputDisplayModes(IDXGIOutput* output, DXGI_FORMAT format)
{
	UINT count = 0;
	UINT flags = 0;

	output->GetDisplayModeList(format, flags, &count, nullptr);

	std::vector<DXGI_MODE_DESC> modeList(count);
	output->GetDisplayModeList(format, flags, &count, &modeList[0]);

	for (const auto& x : modeList)
	{
		UINT n = x.RefreshRate.Numerator;
		UINT d = x.RefreshRate.Denominator;
		std::wstring text =
			L"Width = " + to_wstring(x.Width) + L" " +
			L"Height = " + to_wstring(x.Height) + L" " +
			L"Refresh = " + to_wstring(n) + L"/" + to_wstring(d) + L"\n";

		::OutputDebugString(text.c_str());
	}
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM D3DApp::MyRegisterClass(WNDCLASSEXW& wc)
{
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = MainWndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = mhAppInst;
	wc.hIcon = LoadIcon(mhAppInst, MAKEINTRESOURCE(IDI_DIRECTX12EXAMPLECODE));
	wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = MAKEINTRESOURCEW(IDC_DIRECTX12EXAMPLECODE);
	wc.lpszClassName = L"MainWnd";
	wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(IDI_SMALL));
	return RegisterClassExW(&wc);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL D3DApp::InitInstance(int nCmdShow)
{
	RECT R = { 0, 0, mClientWidth, mClientHeight };
	AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
	int width = R.right - R.left;
	int height = R.bottom - R.top;
	mhMainWnd = CreateWindow(L"MainWnd", mMainWndCaption.c_str(),
		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, nullptr, nullptr, mhAppInst, nullptr);
	if (!mhMainWnd)
	{
		MessageBox(0, L"CreateWindow Failed.", 0, 0);
		return false;
	}

	ShowWindow(mhMainWnd, nCmdShow);
	UpdateWindow(mhMainWnd);

	return true;
}

INT_PTR CALLBACK D3DApp::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

'내용정리 > DirectX12' 카테고리의 다른 글

10. Box Example 2 - D3DApp  (0) 2020.09.08
10. Box Example 1  (0) 2020.09.04
20.08.21 개발일지  (0) 2020.08.21
20.08.18 개발일지  (0) 2020.08.18
20.08.14 일지  (0) 2020.08.14

오늘은 간만에 좀 오래 개발한 것 같습니다.

아침에도 일찍 일어났고, 운동도 안하는 날이고.

물론 다음 달부터는 아침 저녁으로 운동하면 개발하는 시간을 8시간을 맞추기 힘들 수도 있겠죠.

그래도 오늘 제가 할 수 있는 시간의 대부분은 개발에 투자했습니다.

 

처음 시작 할 때는 Host에서 Spawned Character의 Collision과 Visibility가 정상적으로 작동하지 않았고,

Spawned Projectile Trap이 발동 할 때 Host가 마지막에 들어가면 제대로 Trap이 발동하지 않으며,

Client는 Projectile로부터 데미지를 2번 받았습니다.

 

여기서 저는 Visibility를 SetHideInGame 외에 Mesh나 Object마다 SetVisibility를 따로 처리해줬습니다.

그러자 모든 Spawned Object의 Visibility가 모든 Client에서 비정상적이었고,
Host에서는 Spawned Character와의 Collision이 여전히 비정상적이었습니다.

 

그 뒤에는 Trap BP에 부착된 InitializeSpawnedActor의 Spawned Object 활성화 RPC 함수를

Multicast에서 Server로 교체했습니다.

하지만 문제를 해결하지 못했습니다.

 

그 다음에는 ActivateTrap이 호출하는 RPC 함수를 Multicast로 교체해보았습니다.

여전히 문제를 해결하지 못했습니다.

 

그 뒤에 검색을 해본 결과 다음 답을 얻었습니다.

https://answers.unrealengine.com/questions/881032/child-actor-components-dont-spawn-on-clients.html

 

Child actor components don't spawn on clients - UE4 AnswerHub

Hi, In my project I did some mecanism like padlocks or keypad locks. I used an actor to represent a button and this buttons are child components in my locks BP. Everything is fine in the editor, I can push the buttons on every clients but when I launch in

answers.unrealengine.com

즉 Child Actor나 Component는 원본에 Replicate되고, 각각의 Component나 Actor가 Replicate 되도록 설정 하면

각각의 Script 내에서는 Replicate를 지정하면 안된다는 것입니다.

이에 대해 생각을 해보았는데 Parent Object가 Replicate 될 때 부속품들의 Replicate를 같이 처리하거나, 

이들은 Client가 따로 처리를 해야 한다고 생각됩니다.

 

그래서 IObjectActivity에서 ChildActor에서의 Initialize, Activate, InActivate, Reset 함수를 따로 생성했습니다.

그리고 Trap에서 Projectile과 Character의 ChildActor 함수들을 호출하고, 내부에서도 RPC 함수 호출을 하지 않았습니다.

그러자 Spawned Character의 Visibility와 Collision이 Host에서 비정상적인 것을 제외하고 모든 문제가 해결되었습니다.

 

아무래도 Character와 일반 Actor의 차이 때문에 발생한 문제 같습니다.

다음에는 이부분만 집중적으로 수정할 예정입니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.08.21 개발일지  (0) 2020.08.31
20.08.27 개발일지  (0) 2020.08.27
20.08.22 개발일지  (0) 2020.08.22
20.08.20 개발일지  (0) 2020.08.20
20.08.19 개발일지  (0) 2020.08.19

아무래도 Spawn Trap 기능 구현이 꼬인 것 같습니다.

초기 문제는 Spawn Object 이후 bHidden이 제대로 처리가 되지 않았습니다.

그리고 멀쩡하다고 생각했던 Spawn Character에서는 Collision이 처리가 되지 않았습니다.

 

그래서 Object의 Collision을 SetCollisionEnable 함수로 변경을 하고,
SpawnedObject의 함수가 Server RPC 함수가 아닌 Multicast RPC 함수를 호출하도록 하였습니다.

그러자 위의 문제는 해결이 되었는데, 다른 문제가 발생하였습니다.

 

Projectile이 두 Client에서 눈에 보이기는 하나, Collision이 켜지지 않고, 여전히 발사되지 않습니다.

또한 Character는 Host에서는 가시화 되지 않습니다.

 

몇가지 예상되는 이유는 있는데 확실한지는 판단이 안섭니다.

child actor의 replicate를 좀 더 알아보고 움직여야 할 것 같습니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.08.27 개발일지  (0) 2020.08.27
20.08.24 개발일지  (0) 2020.08.24
20.08.20 개발일지  (0) 2020.08.20
20.08.19 개발일지  (0) 2020.08.19
20.08.17 개발일지  (0) 2020.08.17

드디어 아기다리고 어기다리던 Box 예제를 제대로 출력을 했습니다.

ExcuteCommandList에서 문제가 있어 이를 호출하는 Draw쪽 함수만 계속 보고 있었는데,
우연히 이 링크에서 해답을 찾을 수 있었습니다.

 

https://stackoverflow.com/questions/38888268/updating-a-vertex-buffer-causes-a-debug-layer-error

 

Updating a vertex buffer causes a debug layer error

I updated my Windows 10 to version 1607 which includes additional D3D debug layer checking. My vertex buffer updating code worked without warnings/errors before the update, but now I'm getting an e...

stackoverflow.com

저와 동일한 문제는 아니나,

해답 부분을 읽다가 d3dUtill 예제 코드로의 링크를 타고 들어가 봤더니 CreateDefaultBuffer 부분이 나왔습니다.

이 부분을 찾아보니 구현이 덜되어 있었습니다.

누락된 부분도 있고, 안 된 부분도 있었던 것입니다.

이 부분을 채우자 정상 작동을 하게 되었습니다.

 

이제 남은건 화면 출력을 예제 프로젝트의 프레임에 나오도록 하고, 버튼 클릭으로 변경 할 수 있게 하는 것입니다.

그리고 코드 리뷰를 진행 하면 됩니다.

원래 계획대로라면 말이죠.

 

하지만 개발을 하면서 느낀 점이 있는데, 순정 개발을 해야 하는가? 입니다.

좀 더 적어보자면 예시 코드들은 MS에서 제공하는 DirectX의 기능들을 확장한 확장 라이브러리들을 사용합니다.

물론 이것들이 어떠한 오버헤드를 야기하는 것은 아니고,
이론적으로 요구되지만 기능이 따로 구현되지 않는 것들을 제공합니다. 

즉, 사용성이 매우 올라간다는 것이죠.

 

처음의 저는 그래도 공부하는 것이기에 구조나 흐름 파악이 가능하도록 이러한 것들을 배제하고 개발 했으나,

실제 개발해보니 사용을 권장해야 할 정도로 너무 불편했습니다.

그래서 프레임을 옮겨놓고 나면 d3dUtill이나 d3dx12 같은 확장 코드를 적용하고자 합니다.

물론 이렇게 된다면 책에 있는 코드를 그대로 타이핑 하는것과 큰 차이가 없을 것입니다.

하지만 그렇기에 비교해서 공부하기에는 더 좋다고 생각합니다.

'내용정리 > DirectX12' 카테고리의 다른 글

10. Box Example 1  (0) 2020.09.04
20.08.25 개발일지  (0) 2020.08.25
20.08.18 개발일지  (0) 2020.08.18
20.08.14 일지  (0) 2020.08.14
20.08.07 개발일지  (0) 2020.08.07

오늘 유의미한 개발을 한건지는 잘 모르겠습니다.

어제 확인을 했을 때는 Projectile이 정상적으로 작동하지 않아서 Trap 구현이 안된것이라 판단하고 넘겼기 때문입니다.

 

오늘 Trap 부분에서 RPC가 제대로 되는지 확인하다가 Spawn Character Trap과 비교하려고
Trap을 실행했더니 이건 또 정상 작동을 합디다.

 

결국 Spawn Character는 되고 Projectile은 안되는데 그 차이는 Fire 함수 호출이었습니다.

이쯤되면 Fire 함수에서 뭔가 문제가 있겠거니 하겠는데 물론 여기에 문제가 있지만,

다른 곳에서도 문제가 있었습니다.

 

Projectile들은 Compile 하기 전에 미리 Child Actor로 되어 있고, 조건을 만족하면 가시성, Collision을 활성화 합니다.

이 기능을 하나의 RPC 함수로 묶어서 호출하는데, 이 중 가시성 부분만 정상작동하지 않습니다.

Collision은 정상 작동합니다. 활성화 된 후 보이든 보이지 않든 데미지는 계산이 됩니다.

하지만 가시성만은 정상작동하지 않습니다.

 

정확히는 Server까지는 어떻게 되는데 Multicast가 Broadcast가 안되는 느낌입니다.

Host가 Trap을 발동시키면 모든 Client가 작동하지만, Client가 Trap을 발동시키면 Host에게만 보입니다.

그렇기에 우선은 이 문제를 해결해보려 합니다.

 

요즘 컴퓨터가 더 늙었는지 가끔 Host 움직임을 Client가 제대로 반영 못하고 렉먹은 것처럼 움직이는데

이 부분이 원인인지도 봐야 할 것 같습니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.08.24 개발일지  (0) 2020.08.24
20.08.22 개발일지  (0) 2020.08.22
20.08.19 개발일지  (0) 2020.08.19
20.08.17 개발일지  (0) 2020.08.17
20.08.15 개발일지  (0) 2020.08.15

오늘은 Spawn Trap의 기본적인 SpawnedActor 부분을 처리하고, 두가지 BP Trap을 만들어놓았습니다.

구현을 하면서 잠깐 고민을 한 부분이 있습니다.

일반 Actor를 Spawn 할 때는 Activate만 하면 되지만, Projectile은 Activate가 되면 곧바로 Fire가 호출되어야 합니다.

이 때 Fire 방향을 지정해야 하는데,
이 부분이 기획에 따라 매번 바뀔 수도 있고 아무튼 처리하는데 선택지가 많았습니다.

하지만 발사 때마다 바뀌려면 Activate가 파라미터를 받도록 Overload를 만들어줘야 하고, 

그렇다면 결국 상세한 Type을 받아야 했습니다.

 

그래서 저는 Fire Direction을 미리 지정하고, 매번 같은 방향으로만 발사되도록 하였습니다.

디테일한 부분보다는 기능 위주로 구현해야 할 것 같다고 최근 생각이 바뀌게 되면서 결정한 사항이었습니다.

 

일단 정상 작동을 하고 있지는 않은데 그 이유를 알아보는건 내일로 미루었습니다.

실내에 환기 중임에도 기온이 38도를 육박하고, 슬슬 3개의 모니터가 4개로 보이기 시작했습니다.

쉬어야겠습니다...

 

내일 열심히 하면 이번주 내로 4개의 Trap을 완성할 수 있을 것 같습니다.

그렇다면 뒤이어 Teleport를 시도해보고 가능하면 이번주 안에 Teleport Trap까지 완성을 해보겠습니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.08.22 개발일지  (0) 2020.08.22
20.08.20 개발일지  (0) 2020.08.20
20.08.17 개발일지  (0) 2020.08.17
20.08.15 개발일지  (0) 2020.08.15
20.08.13 개발일지  (0) 2020.08.13

오늘은 크러시가 나는 부분을 고치고,
그 뒤에 새로운 문제를 직면하고 이를 고치다가 뛰쳐나갈것만 같은 정신을 붙잡고 있습니다.

 

우선 크러시 부분.

이 코드를 짜면서 몇몇 Class는 상위버전이 나와서 이를 가져다 썼는데, 그 중 하나가 SwapChain이었습니다.

하지만 이 부분이 문제임은 알겠는데 새로 나온 SwapChain1이 어떻게 하면 정상적으로 사용할 수 있는지
알 수 없어 그냥 SwapChain으로 원상복구했습니다.

 

대부분의 문제들은 오타들로 인한 것이거나, 이처럼 최신 코드를 사용하는 방법을 알지 못해서 발생했습니다.

답답한건 라이브러리 코드 구현체를 보면 대충 어느부분을 주의해야하는지 감이 잡히는데.

DirectX12는 특정 헤더만 열려있고 구현체는 닫혀있어 구현체를 알 수가 없습니다.

 

다음 문제가 이런 종류였습니다.

이제 크러시는 나지 않는데, DXError가 발생하면서 Model Shading이 출력되지 않고 있습니다.

에로 코드는 다음과 같습니다.

 

D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: 
Using ClearDepthStencilView on Command List (0x0A75BC28:'Unnamed ID3D12GraphicsCommandList Object'): 
Resource state (0x0: D3D12_RESOURCE_STATE_[COMMON|PRESENT]) of resource (0x0A6DE398:'Unnamed ID3D12Resource Object') (subresource: 1) 
is invalid for use as a depth buffer.  

Expected State Bits (all): 0x10: D3D12_RESOURCE_STATE_DEPTH_WRITE, 
\Actual State: 0x0: D3D12_RESOURCE_STATE_[COMMON|PRESENT], 
Missing State: 0x10: D3D12_RESOURCE_STATE_DEPTH_WRITE. 
[ EXECUTION ERROR #538: INVALID_SUBRESOURCE_STATE]

즉 CommandLists에 담겨있는 Comaand 중 ClearDepthStencilView를 호출하면서 사용하는 resource의
Resource State의 값이 적절치 못하다는 것입니다.

 

여기서 좀 머리가 복잡해졌습니다. 우선 문제가 발생된다고 예상되는 코드 부분을 발췌했습니다.

void BoxApp::Draw(const GameTimer& gt)
{
	ThrowIfFailed(mDirectCmdListAlloc->Reset());
	ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), mPSO.Get()));

	// Set CommandList
	mCommandList->RSSetViewports(1, &mScreenViewport);
	mCommandList->RSSetScissorRects(1, &mScissorRect);

	// Set CommandList - not problem
	D3D12_RESOURCE_BARRIER BeforeBarrier;
	ZeroMemory(&BeforeBarrier, sizeof(BeforeBarrier));
	BeforeBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
	BeforeBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
	BeforeBarrier.Transition.pResource = CurrentBackBuffer();
	BeforeBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
	BeforeBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
	BeforeBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;

	mCommandList->ResourceBarrier(1, &BeforeBarrier);

	mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
	mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);

	// Specify the buffers we are going to render to.
	// Set CommandList
	mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());

	ID3D12DescriptorHeap* descriptorHeaps[] = { mCbvHeap.Get() };
	mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);

	// Set CommandList
	mCommandList->SetGraphicsRootSignature(mRootSignature.Get());

	// Set CommandList
	mCommandList->IASetVertexBuffers(0, 1, &mBoxGeo->VertexBufferView());
	mCommandList->IASetIndexBuffer(&mBoxGeo->IndexBufferView());
	mCommandList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	// Set CommandList
	mCommandList->SetGraphicsRootDescriptorTable(0, mCbvHeap->GetGPUDescriptorHandleForHeapStart());

	mCommandList->DrawIndexedInstanced(mBoxGeo->DrawArgs["box"].IndexCount, 1, 0, 0, 0);

	// Set CommandList - not problem
	D3D12_RESOURCE_BARRIER AfterBarrier;
	ZeroMemory(&AfterBarrier, sizeof(AfterBarrier));
	AfterBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
	AfterBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
	AfterBarrier.Transition.pResource = CurrentBackBuffer();
	AfterBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
	AfterBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
	AfterBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
	
	mCommandList->ResourceBarrier(1, &AfterBarrier);
	ThrowIfFailed(mCommandList->Close());

	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

	ThrowIfFailed(mSwapChain->Present(0, 0));
	mCurrentBackBuffer = (mCurrentBackBuffer + 1) % SwapChainBufferCount;

	FlushCommandQueue();
}

 

1. Resource State를 가져다 쓰는 것은 Resource_Barrier 선언 두번 뿐입니다.
둘의 StateBefore와 StateAfter가 대칭인 것으로 보아 아마 고친다면 둘 다 고쳐야 할것입니다.

2. 로그에 찍힌대로만 하면 Resource_State_Present를 Resource_State_Depth_Write로 고치면 될 것입니다. 
하지만 그렇게 되면 그 사이 함수들 부분에서 에러가 발생합니다.

3. 로그에 찍힌 또 다른 요소인 ClearDepthStencilView 부분을 직접 수정해야 하나
원래 코드와 다른 부분이 없어 무엇이 문제인지 파악할 수 없습니다.

 

이 상태에서 Resource_Barrier 사이에 선언된 모든 함수나 파라미터를 건드려 보았으나
유의미한 성과를 얻지 못했습니다.

 

 

정말 참... 정신 나갈 것 같습니다.

거의 문제 하나를 일주일동안 붙들고 있으니 진행도 안되고 미쳐버릴 것 같습니다.

빨리 빌드를 완성했으면 좋겠습니다.

그래야 코드 하나하나 뜯어서 구조를 머릿속에 박아넣을텐데...

'내용정리 > DirectX12' 카테고리의 다른 글

20.08.25 개발일지  (0) 2020.08.25
20.08.21 개발일지  (0) 2020.08.21
20.08.14 일지  (0) 2020.08.14
20.08.07 개발일지  (0) 2020.08.07
20.08.04 일지  (0) 2020.08.04

2개의 Block Trap을 Multiplay상에서 구현을 했습니다.

 

 

구현을 하긴 했는데... 솔직히 아직 이 기능의 핵심인 InterpToMovementComponent에 대해 적을 자신이 없습니다.

더 효율적이고 적절한 사용 방식이 있을 것 같긴 한데...

뭔가 이해도가 떨어진다는 느낌이 듭니다.

 

아무튼 구현을 했는데, 크러시가 난 이유는 ControlPoints를 초기화 하지 않았기 때문이었습니다.

그 다음 문제는 벽이 잘못된 위치에서 소환된 것인데 무엇이 문제고, 무엇이 해결법인지 모르겠습니다.

Reset 위치를 조금 바꾼 것과 rebuild 몇번 했는데 해결되어버렸습니다.

참... 찜찜하지 않을 수 없습니다.

 

우선 빠른 목표 달성을 위해 일단은 남겨두지만,

언젠간 좀 더 알아보고 InterpToMovementComponent의 사용방법을 정리해보겠습니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.08.20 개발일지  (0) 2020.08.20
20.08.19 개발일지  (0) 2020.08.19
20.08.15 개발일지  (0) 2020.08.15
20.08.13 개발일지  (0) 2020.08.13
20.08.10 개발일지  (0) 2020.08.10

오늘은 Block Trap을 먼저 구현을 해보았습니다.

개발을 하면서 Projectile 부분이 구현이 미흡하다는 점과,

Trap에서 InRange 관리 부분이 호출이 안되어 있음을 발견하고 이 부분을 수정했습니다.

 

이렇다 보니 구현된 부분이 정확한지 잘 안그려져 좀 느리게 개발한 것 같습니다.

하지만 기능이 완벽히 구현되지는 못했는데, RepNotify가 작동하지 않고 있습니다.

https://docs.unrealengine.com/ko/Gameplay/Networking/QuickStart/index.html

 

Multiplayer Programming Quickstart Guide

Create a simple multiplayer game in C++.

docs.unrealengine.com

오류가 나지 않는 것으로 보아 문법은 문제가 없는 것 같은데 이유를 잘 모르겠습니다.

 

혹시나 하여 RepNotify를 그대로 두고 Overlap마다 호출을 해보았는데

장해물을 이동시키는 함수에서 크래시가 발생합니다.

원래는 휴일도 하고 있었지만 내일은 자기소개서와 포트폴리오를 좀 더 다듬기 위해 모래 개발을 이어갈 것 같습니다.

 

고민이 좀 되는데 우선 repNotify가 되지 않는다면 그냥 Overlap 이벤트마다 값을 체크해볼 것 같습니다.

그리고 장해물 이동 부분을 수정을 해보려 합니다.

 

이제는 더도말고 덜도말고 일주일에 2개씩만 구현했으면 좋겠습니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.08.19 개발일지  (0) 2020.08.19
20.08.17 개발일지  (0) 2020.08.17
20.08.13 개발일지  (0) 2020.08.13
20.08.10 개발일지  (0) 2020.08.10
20.08.09 개발일지  (0) 2020.08.09

이번에 면접 본 곳들도 대부분 다 떨어졌습니다.

아직 한군데가 남았는데 근무 환경이 고민이 좀 됩니다.

 

늘 고민 했던 거지만 다시 한번 고민이 됩니다.

되야 하는 거지만 일단 탐탁찮더라도 입사를 해서 2년을 이악물고 버텨 경력을 쌓을 것인가.

아니면 연봉 테이블을 위해 1년 정도 더 공부를 하더라도 대기업 계열로 첫 입사를 노릴것인가.

 

전자는 입사를 한 뒤에 경력을 쌓더라도 이직 후 연봉이 변변찮거나 계속해서 중소기업을 전전긍긍할수 있습니다.

그리고 불러주는 회사들이 연봉이 썩 만족스러운 편은 아닙니다.

 

후자는 반대로 1년 후에 대기업에 입사한다는, 아니 어느 기업이라도 입사를 한다는 보장이 없습니다.

그리고 제 정신이 멀쩡할거라는 보장도 없구요.

 

이래저래 그래서 고민이 됩니다.

그리고 지금 뭘 준비해야 할지도 고민이 됩니다.

공부는 계속 해왔지만 결과가 없다는 것에 조금씩 면접관이 안좋게 본다는 것이 느껴지는 것 같습니다.

그렇다고 출시를 위해 빠르게 무언가를 만들자니 하던 것이 거의 올스탑이 되고.

팀을 구하기는 하늘의 별따기고.

 

아무것도 안하고 있다면 오히려 속 편히 뭐든 해볼텐데.

하고 있는 일이 있는데 그것 외에 해야 할 일이 이렇게 눈에 띄니까 미쳐버릴 지경입니다.

+ Recent posts