4 Replies - 814 Views - Last Post: 04 June 2015 - 03:34 PM Rate Topic: -----

#1 BradMick   User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 79
  • Joined: 07-July 14

HLSL Help

Posted 03 June 2015 - 06:53 PM

Howdy,

I've been messing around with HLSL and have hit a snag. I've been working through the DirectX Tutorial site (http://www.directxtutorial.com/) and backing it up with Frank Luna's Intro to 3D Game Programming w/ DirectX 9.0c, A Shader Approach and Real-Time Rendering 3rd Edition...Between all of those resources I've managed to write my first simple HLSL shader, but I've hit a small snag when implementing the Specular piece of the shader. I've got the math and code working to the best of my knowledge, but when I implement the Specular portion of the shader, nothing renders. I suspect I may be missing something, or am not correctly passing something to the shader. When I comment out all of the code related to the specular portion the TeaPot renders fine. Any help would be greatly appreciated!

V/R

Brad

main.cpp
//Handles are prefixed with: h_
//Pointers are prefixed with: p_
//Long Pointers are prefixed with: lp_
//Integers are prefixed with: i_
//UINTs are prefixed with: ui_
//DWORDs are prefixed with: dw_
//STRUCTS are prefixed with: st_

#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

LPDIRECT3D9			D3D;		//The pointer to our Direct3D interface.
LPDIRECT3DDEVICE9	D3DDevice;	//The pointer to the device class.

ID3DXMesh*			Teapot;
IDirect3DTexture9*	TeapotTexture;

LPD3DXEFFECT		Effect;
D3DXHANDLE			h_Technique;

D3DXVECTOR3			v_CameraPosition;
D3DXVECTOR3			v_CameraUp;
D3DXVECTOR3			v_CameraLookAt;

//Function prototypes
void InitD3D(HWND h_Wnd);	//Sets up and Initializes Direct3D.
void Render_Frame(void);	//Renders a single frame.
void CleanD3D(void);		//Closes Direct3D and releases memory.
void InitGraphics(void);
void InitLight(void);

//WindowProc fucntion prototype.
LRESULT CALLBACK WindowsProcedure(	HWND h_Wnd,
									UINT ui_message,
									WPARAM w_Param,
									LPARAM l_Param);

//Our Windows program entry point.
int WINAPI WinMain(	HINSTANCE h_Instance, //"Handle to an Instance", how Windows keeps track of a program. It's an integer value.
					HINSTANCE h_PreviousInstance, //For backwards compatibility with older programs. Generally NULL and not used anymore.
					LPSTR lp_CommandLine, //A "Long Pointer to a String" cointaining the name for the Command Line of the application.
					int i_ShowCommand) //Determines how the program appears after it's created. Generally not used in games.
{

	//Create an instance for a "Handle to a Window"
	HWND h_Wnd;
	//Create an instance of the Windows Class.
	WNDCLASSEX WindowClass;

	//Empty our Windows Class Instance to prepare for use.
	ZeroMemory(&WindowClass, sizeof(WNDCLASSEX));

	//Fill our Windows Class with the necessary information.
	WindowClass.cbSize = sizeof(WNDCLASSEX);
	WindowClass.style = CS_HREDRAW | CS_VREDRAW;
	WindowClass.lpfnWndProc = WindowsProcedure;
	WindowClass.hInstance = h_Instance;
	WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WindowClass.hbrBackground = (HBRUSH)COLOR_WINDOW; //We comment this out to ensure the background color is left alone.
	WindowClass.lpszClassName = L"WindowClass1";

	//Register the Window Class.
	RegisterClassEx(&WindowClass);

	//Create our Window and store that data in our Window Handle.
	h_Wnd = CreateWindowEx(	NULL,
							L"WindowClass1", //The name of our Windows Class.
							L"Shader Prototype", //The Window Title.
							WS_OVERLAPPEDWINDOW, //The style of the Window, originally WS_OVERLAPPEDWINDOW and now adjusted for Fullscreen. WS_POPUP gets rid of ALL borders around a window.
							0, 0, //X- and Y-Position of the window.
							SCREEN_WIDTH, SCREEN_HEIGHT, //Width and Height of the window.
							NULL, //There is no parent window, NULL.
							NULL, //We aren't using Menus, NULL.
							h_Instance, //The Application handle.
							NULL); //Used with multiple Windows, NULL.

	//This call will display our window on the screen.
	ShowWindow(h_Wnd, i_ShowCommand);

	//Set up and initialize Direct3D.
	InitD3D(h_Wnd);

	//This begins the main loop:
	MSG message;
	
	while (TRUE)
	{
		//Check to see if there are messages waiting in the queue
		while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
		{
			//Translate the message and dispatch it to the WindowsProcedure()
			TranslateMessage(&message);
			DispatchMessage(&message);
		}

		//If the message is WM_QUIT, exit the while loop
		if (message.message == WM_QUIT)
			break;

		//Run the Game Code Here
		Render_Frame();
	}

	//Clean up DirectX and COM
	CleanD3D();

	//This returns part of the WM_QUIT message to Windows.
	return message.wParam;
}

//This is the main message handler for the program.
LRESULT CALLBACK WindowsProcedure(HWND h_Wnd, UINT ui_message, WPARAM wParam, LPARAM lParam)
{
	//This figures out the code to run based on the given message.
	switch (ui_message)
	{
		case WM_CREATE:
		{
			HMENU h_MenuBar = CreateMenu();

				HMENU h_File = CreateMenu();
				AppendMenu(h_MenuBar, MF_POPUP, (UINT_PTR)h_File, L"File");
					AppendMenu(h_File, MF_STRING, NULL, L"Exit");
			
				AppendMenu(h_MenuBar, MF_POPUP, NULL, L"Edit");

				HMENU h_Options = CreateMenu();
				AppendMenu(h_MenuBar, MF_POPUP, (UINT_PTR)h_Options, L"Options");
					AppendMenu(h_Options, MF_STRING, NULL, L"Fullscreen");

			SetMenu(h_Wnd, h_MenuBar);
		}break;
		//This will be read when the Window is closed.	
		case WM_DESTROY:
		{
			//Closes the Application completely.
			PostQuitMessage(0);
			return 0;
		}break;
	}

	//If there isn't a case covered in the Switch statement above, then do this.
	return DefWindowProc(h_Wnd, ui_message, wParam, lParam);
}

//Thsi function initializes and prepares Direct3D for use.
void InitD3D(HWND h_Wnd)
{
	D3D = Direct3DCreate9(D3D_SDK_VERSION); //Create the Directe3D interface.

	D3DPRESENT_PARAMETERS D3Dpp; //Creates a struct to hold our device information in.

	ZeroMemory(&D3Dpp, sizeof(D3Dpp)); //Empty the struct for use.
	D3Dpp.Windowed = TRUE; //Program is fullscreen, not windowed.
	D3Dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //Discard the old frames.
	D3Dpp.hDeviceWindow = h_Wnd; //Set the window to be used by Direct3D.
	
	//Create a device class using this information and information from the st_D3Dpp struct.
	D3D->CreateDevice(	D3DADAPTER_DEFAULT,
						D3DDEVTYPE_HAL,
						h_Wnd,
						D3DCREATE_SOFTWARE_VERTEXPROCESSING,
						&D3Dpp,
						&D3DDevice);

	v_CameraPosition	= D3DXVECTOR3(0.0f, 4.0f, -6.0f);
	v_CameraLookAt		= D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	v_CameraUp			= D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	InitGraphics();

	LPD3DXBUFFER ErrorLog;

	D3DXCreateEffectFromFile(D3DDevice, L"SimpleFx.fx", 0, 0, D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, 0, &Effect, &ErrorLog);

	Effect->FindNextValidTechnique(NULL, &h_Technique);

	InitLight();
}

void Render_Frame(void)
{
	D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
	D3DDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	D3DDevice->BeginScene(); //Begins the 3D Scene.
	
	D3DXMATRIX m_View;
	D3DXMatrixLookAtLH(	&m_View,
						&v_CameraPosition, //Canera Look Position
						&v_CameraLookAt, //Camera Look-At Position
						&v_CameraUp); //The Camera 'Up' Direction
	D3DDevice->SetTransform(D3DTS_VIEW, &m_View);
	Effect->SetMatrix("View", &m_View);

	D3DXMATRIX m_Projection;
	D3DXMatrixPerspectiveLH(	&m_Projection,
								D3DXToRadian(45),
								(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, //Aspect Ratio
								1.0f,		//Near plane
								100.0f);	//Far plane
	D3DDevice->SetTransform(D3DTS_PROJECTION, &m_Projection);
	Effect->SetMatrix("Projection", &m_Projection);

	//Set the world Transform Matrix
	static float index = 0.0f; index += 0.03f;
	D3DXMATRIX m_RotateY;
	D3DXMatrixRotationY(&m_RotateY, index);
	D3DDevice->SetTransform(D3DTS_WORLD, &(m_RotateY));
	Effect->SetMatrix("World", &m_RotateY);

	Effect->Begin(NULL, NULL);
		Effect->BeginPass(0);
		
		//Render 3D Objects to the Back Buffer here.
		Teapot->DrawSubset(0);

		Effect->EndPass();
	Effect->End();

	D3DDevice->EndScene(); //Ends the 3D Scene.

	D3DDevice->Present(NULL, NULL, NULL, NULL); //Displays the created frame.
}

void CleanD3D(void)
{
	D3DDevice->Release();	//Close and release the 3D device.
	D3D->Release();			//Close and release Direct3D.
	Teapot->Release();		//Close and release the Teapot.
	Effect->Release();		//Close and release the Effect file.
}

void InitGraphics(void)
{
	//Initialize all of the objects we need here
	D3DXCreateTeapot(D3DDevice, &Teapot, NULL);
}

void InitLight(void)
{
	D3DLIGHT9 st_Light;	//Create the Light struct
	ZeroMemory(&st_Light, sizeof(st_Light)); //Clear out the Light Struct for use

	st_Light.Diffuse.r = st_Light.Ambient.r = 0.50f;
	st_Light.Diffuse.g = st_Light.Ambient.g = 0.25f;
	st_Light.Diffuse.b = st_Light.Ambient.b = 0.00f;

	st_Light.Specular.r = 0.75f;
	st_Light.Specular.g = 0.50f;
	st_Light.Specular.b = 0.25f;

	D3DVECTOR v_Position = { 6.0f, 4.0f, -2.0f };
	st_Light.Position = v_Position;

	Effect->SetFloatArray("LightPos", &v_Position.x, 3);
	Effect->SetFloatArray("AmbientColor", &st_Light.Ambient.r, 3);
	Effect->SetFloatArray("DiffuseColor", &st_Light.Diffuse.r, 3);
	Effect->SetFloatArray("SpecularColor", &st_Light.Specular.r, 3);
	Effect->SetFloatArray("CamPos", &v_CameraPosition.x, 3);
}


SimpleFx.fx
float4x4 World;
float4x4 View;
float4x4 Projection;

//The data members to hold our passed lighting information.
float3 LightPos;
float3 AmbientColor;
float3 DiffuseColor;

float3 SpecularColor;
float3 CamPos;

struct VertexOut
{
    float4 Pos : POSITION;
    float4 Color : COLOR;
};

//float3 Normal : NORMAL is required to calculate lighting information. The normal is handled by the Mesh and is passed in by DirectX.
VertexOut VShader(float4 Pos : POSITION, float3 Normal : NORMAL)
{
    VertexOut Vert = (VertexOut)0;
	
	//This is how we define the light within the world. We define Position, Ambient and Diffuse Colors.
	//Float3 is the GPU equivalent of creating an Array of 3 Floats. To initialize the float3, you set the value equal to float3(x.x, x.x, x.x).
	//This is no longer needed because we pass the lighting info from the InitLight function in the program.
	//float3 LightPos = float3(2, 2, 2);
    //float3 AmbientColor = float3(.5, .5, .5);
    //float3 DiffuseColor = float3(.5, .5, .5);

	//Since the light is based on the models position in world space and not model space we have to multiply the Vertex position by the world matrix.
    Pos = mul(Pos, World);
	//Calculate the normal vector and reposition it similar to above.
    Normal = mul(Normal, World);
	//Normalize the vector to ensure its length is always 1. This is a normalized vector between the light position and the vertex position.
    float3 LightVec = normalize(LightPos - Pos);
	
	//Calculate and normal the EyeVector (the vector from the object to the camera position) by taking the position of the camera and the position o fthe object.
	float3 EyeVec = normalize(CamPos - Pos);
	//We need a container to hold our constant and also allow us to modify the value...so that's NewSpecularColor
	float3 NewSpecularColor = SpecularColor;
	NewSpecularColor = pow(dot(Normal, normalize(EyeVec + LightVec)), 32.0f) * SpecularColor;
	return Vert;
	
	//Find the dot product of the Normal and Light vector and multiply it by the Diffuse color.
    DiffuseColor = dot(Normal, LightVec) * DiffuseColor;
	//This will ensure we do not go less than 0. That's what the max intrinsic does. Evidently its bad for color to go below 0.
    //DiffuseColor = max(DiffuseColor, 0);
	float3 NewDiffuseColor = DiffuseColor;
	NewDiffuseColor = dot(Normal, LightVec) * NewDiffuseColor;
	NewDiffuseColor = max(NewDiffuseColor, 0);
	
	//This will return the final color after all of the above is complete.
    Vert.Color.rgb = NewDiffuseColor + AmbientColor;

	//Multiply the view and projection matrices and output the results.
    float4x4 Transform;
    Transform = mul(View, Projection);
    Vert.Pos = mul(Pos, Transform);

    return Vert;
}

technique FirstTechnique
{
    pass FirstPass
    {
        Lighting = TRUE;
        ZEnable = TRUE;

        VertexShader = compile vs_2_0 VShader();
    }
}


Is This A Good Question/Topic? 0
  • +

Replies To: HLSL Help

#2 macosxnerd101   User is online

  • Games, Graphs, and Auctions
  • member icon




Reputation: 12316
  • View blog
  • Posts: 45,416
  • Joined: 27-December 08

Re: HLSL Help

Posted 03 June 2015 - 06:59 PM

Moved to Game Programming. Note that the C/C++ Challenges forum is not the place to ask for help.
Was This Post Helpful? 0
  • +
  • -

#3 BBeck   User is offline

  • Here to help.
  • member icon


Reputation: 792
  • View blog
  • Posts: 1,886
  • Joined: 24-April 12

Re: HLSL Help

Posted 04 June 2015 - 06:07 AM

Take a look at this thread. About my second post I post my DirectX11 HLSL Blinn-Phong shader code. Before that I post my XNA code for the same thing and XNA is DX9 based, so it may be more similar to what you are trying to do.

I remember for certain fully documenting my shader code once, but I can't seem to find that version for some reason.

This has come up a lot lately and I've been meaning to make a tutorial on this stuff, but haven't gotten to it yet.

I'll see if I can't take a closer look at your code this afternoon when I get some time.

On my website I have working DX11 code posted for Visual Studio 2014. That includes a Blinn-Phong shader that does texturing (Blinn-Phong produces the specular highlight).

I had to make a decision on DX9 vs. DX11 and chose to go with DX11. I've heard that DX9 is easier and that it has a lot of built in stuff for models, shaders, and lighting. I've found the primary problem with DX11 is that you have to use HLSL for everything. I got comfortable with the basics of HLSL in XNA and so didn't have a problem with that in DX11. And I've been working on implementing my own rigid animation model class which I'm getting close to finishing and posted the code for on my website.

Anyway, I haven't done any DX9 since about 4 or 5 years ago when I was doing 2D sprite stuff with it. I think the code may be significantly different than DX11. But I'll try and take a look to see if I see anything later when I get some time.
Was This Post Helpful? 0
  • +
  • -

#4 BradMick   User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 79
  • Joined: 07-July 14

Re: HLSL Help

Posted 04 June 2015 - 02:46 PM

macosxnerd101,

Sorry about that!

BBeck,

Good stuff! Appreciate the assist. I sorted out my issue...and it was a...well...simple fix. All I had to do was this:

Vert.Color.rgb = NewDiffuseColor + AmbientColor + NewSpecularColor;

The bolded bit was what was missing...After I added it, it worked perfectly. Renders, have a nice specular highlight...the whole nine. I'm still not 100% that it's correct...but that made it work, and that works for me. It makes sense. I do all the math above, and then add all of the results together...if I do that math and then never assign it, it makes sense that it will result in the thing not rendering. Kind of makes sense.

Do you have any good books for explaining HLSL in depth?

Brad
Was This Post Helpful? 0
  • +
  • -

#5 BBeck   User is offline

  • Here to help.
  • member icon


Reputation: 792
  • View blog
  • Posts: 1,886
  • Joined: 24-April 12

Re: HLSL Help

Posted 04 June 2015 - 03:34 PM

Good to hear it's working!

Good books on HLSL? No not really. There's this book. I have it but have never used it mostly because it's GLSL rather than HLSL and I've found some of my other books more useful.

This is my goto book for Blinn Phong and basic lighting theory and such.

You would be surprised how for a Blinn-Phong shader will take you. After that, the next step is to add a texture sampler to it. Then you can do the same thing but instead of a color map input a normal map. That will allow you to calculate the normals per pixel instead of per vertex.

If you change your shader there to a pixel shader it will do that, but what the normal map does beyond that is allow every pixel on the triangle face to have it's own normal. So, instead of interpolating the normals between vertices you have specific normals for each pixel value that can point in completely different directions making each pixel appear far more 3D.

Then you can add another texture for a specular map so that the specular value is determined per pixel also allowing you to make the character's armor have specular but turning it off for their face, for example.

It all builds on top of Blinn Phong.

Another direction to go with it is Post Processing Effects. Those shaders use render targets instead of the back buffer of the swap chain. You draw the whole scene to the render target. Then the Post Processing Effect HLSL shader modifies the image in the render target to do whatever (bloom, glow, blurr it, make it HDR, make it black & white, or sepia, etc.) and then the modified render target gets written to the back buffer as normal. But the shader is applied to the final image rather than using it to draw the original scene.

I haven't gotten too deep into the PPE stuff, so I'm not sure what books, especially for DX 9 to recommend. (I have an XNA book or two.)

I'm working right now on a "Shaders:HLSL" tutorial. Today I wrote a Gouraud shader, a silhouette shader, and a Blinn shader for the tutorial. I need a tutorial to explain all the math that makes Blinn and Phong work. Then I thought I might as well explain Gouraud while I'm at it since they build on top of Gouraud. And so it should be just a big intro to shaders and HLSL focusing on Blinn Phong.

Another good book when it comes to HLSL for DirectX 11 is Practical Rendering and Computation. Some have given it poor reviews saying the "documentation" (you found some documentation for DX?) covers everything in the book. It's one of my favorite books for DX11 although I've only gotten through the first couple of chapters, but it explains things like how DX interfaces with HLSL. It explains things like Constant Buffers and all sorts of deep technical stuff.

DX9 and DX11 are night and day different from what I've seen and heard. So, books for one may not help much with the other. I think the difference is that DX11 focuses more on HLSL and vertex buffers. There's pretty much nothing "built in" to DX11 and so you have to build just about everything from scratch which means HLSL from day one. If you figure out how to do a Blinn Phong shader though, DX11 isn't all that bad.

The DX Tool Kit is a free download that does some of the things they decided to drop out of DX11 like sprites, fonts, and models and such. I haven't tried it. I decided to go the hard route and just make everything from scratch. I'm almost finished with my model class including a custom Python exporter from Blender. The code (as far as I have it anyway) is available on my website.

I hope to have the HLSL tutorial video up on my YouTube channel at VirtuallyProgramming.com in the next couple of weeks. I seem to be seeing a lot of requests lately for "Introduction to HLSL". So, I think this might help a lot of folks to just build all the different basic shaders up to a textured Blinn-Phong shader and explain every line of the HLSL and the math behind it.

I'm no HLSL expert, but I've at least gotten real comfortable with it. I think it's mostly the vector math that throws everyone not to mention that HLSL and the way it works is just so foreign to C++ or anything else. It's got it's own way of doing things and it's important to understand kind of how the code flows which is not exactly like C++.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1