Originally Posted by KaiserBreath
Hi, can you explain the last 2 line? I tired inputing (0,1,0) and (-1,-1,0) but the reflected vector is not (-1,1,0).
Also, you can multiply the whole struct by a variable?
Do have have any sites or books to recommend to learn such stuffs more in depth?
Thanks!
Yeah sure.
The problem appears to be in the term you are using for NdotL. Notice, it's actually a scalar, not a vector (its 1D, not 3D)
I just added code to print N, L and NdotL. They're:
Code:
N = < 0.000, 1.000, 0.000>
L = <-0.707,-0.707, 0.000>
NdotL = -0.707107
So, this would make the calculation of reflected look something like this:
Code:
R = L - (N * 2.0 * NdotL)
reflected = <-0.707,-0.707,0> - ( <0, 1, 0> * 2 * -0.707 )
= <-0.707,-0.707,0> - ( <0, 1, 0> * -1.414 )
= <-0.707,-0.707,0> - <0, -1.414, 0>
= <-0.707, 0.707,0>
Ah! I just realized that there is something implied but not said - the reflected vector is a unit vector. It's the same direction, but of unit length. To make sure that the reflected vector is <-1, 1, 0>, you have to multiply <-0.707, 0.707, 0> by the length of the original L ( <-1, -1, 0> ), which is sqrt(2), which is 1.414
So VecLen(L) = 1.414
VecLen(L) * Reflected = reflected vector of same length as L
1.414 * <-0.707,0.707,0> = <-1, 1, 0>
And nah, I don't have any books or sites to recommend. I just use google for whatever is presenting itself as a problem at the time. I bought a few books back in the 90s, but technology changes so fast I barely get any use. They'd be good references for vector/matrix math and for some shading equations, but I can get that online, and the books authors were still using PHIGS as a 3d library with their VAX 11/780's
Here's a a quick sampler I whipped up, give it a try. It draws a horizontal line in the middle of the box which acts as the mirror. It then draws a blue line from your mouse cursor to the middle of the mirror and a red line that indicates the reflection of the blue line.
main.cpp
Code:
#include <windows.h>
#include "vec3.h"
// Declare Windows procedure
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK outputWindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
// Make the class name into a global variable
char szClassName[ ] = "vectorReflectionApp";
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd; // This is the handle for our window
MSG messages; // Here messages to the application are saved
WNDCLASSEX wincl; // Data structure for the windowclass
// The Window structure
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; // This function is called by windows
wincl.style = CS_DBLCLKS; // Catch double-clicks
wincl.cbSize = sizeof (WNDCLASSEX);
// Use default icon and mouse-pointer
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_CROSS);
wincl.lpszMenuName = NULL; // No menu
wincl.cbClsExtra = 0; // No extra bytes after the window class
wincl.cbWndExtra = 0; // structure or the window instance
// Use Windows's default colour as the background of the window
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
// Register the window class, and if it fails quit the program
if (!RegisterClassEx (&wincl))
return 0;
RECT mRect = {0,0,276,276};
DWORD dwStyle, dwExStyle;
dwStyle = WS_CAPTION | WS_VISIBLE | WS_SYSMENU;// GetWindowLong(hwnd, GWL_STYLE);
dwExStyle = NULL; //GetWindowLong(hwnd, GWL_EXSTYLE);
AdjustWindowRectEx(&mRect,dwStyle,false,dwExStyle);
// The class is registered, let's create the program
hwnd = CreateWindowEx (
0, // Extended possibilites for variation
szClassName, // Classname
"vectorReflection", // Title Text
WS_CAPTION | WS_VISIBLE | WS_SYSMENU, // default window
CW_USEDEFAULT, // Windows decides the position
CW_USEDEFAULT, // where the window ends up on the screen
mRect.right-mRect.left, //544, // The programs width
mRect.bottom-mRect.top, //375, // and height in pixels
HWND_DESKTOP, // The window is a child-window to desktop
NULL, // No menu
hThisInstance, // Program Instance handler
NULL // No Window Creation data
);
CreateWindow("static","",WS_CHILD|WS_VISIBLE,10,10,256,256,hwnd,(HMENU)1000,hThisInstance,NULL);
SetWindowLong(GetDlgItem(hwnd, 1000), GWL_WNDPROC, (long)outputWindowProcedure);
// Make the window visible on the screen
ShowWindow (hwnd, nCmdShow);
// Run the message loop. It will run until GetMessage() returns 0
while (GetMessage (&messages, NULL, 0, 0))
{
// Translate virtual-key messages into character messages
TranslateMessage(&messages);
// Send message to WindowProcedure
DispatchMessage(&messages);
}
// The program return-value is 0 - The value that PostQuitMessage() gave
return messages.wParam;
}
vec3 makeVec(int posX, int posY, int originX, int originY)
{
return vec3(originX-posX,originY-posY,0);
}
// This function is called by the Windows function DispatchMessage()
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) // handle the messages
{
case WM_CREATE:
return 0;
case WM_DESTROY:
PostQuitMessage (0); // send a WM_QUIT to the message queue
break;
default: // for messages that we don't deal with
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK outputWindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
RECT mRect;
HBRUSH mBrush;
HPEN mPen, oldPen;
static POINT mousePos;
static bool mouseOver = false;
vec3 norm(0,1,0), incoming, reflected;
double len;
switch (message)
{
case WM_ERASEBKGND:
return 0;
case WM_SETCURSOR: // use parent's cursor
return 0;
case WM_MOUSEMOVE:
mouseOver = true;
mousePos.x = LOWORD(lParam);
mousePos.y = HIWORD(lParam);
InvalidateRect(hwnd,NULL,false);
return 0;
case WM_PAINT:
BeginPaint(hwnd, &ps);
mBrush = (HBRUSH)CreateSolidBrush(RGB(255,200,200));
mRect = {0,0,256,256};
FillRect(ps.hdc, &mRect, mBrush);
DeleteObject(mBrush);
MoveToEx(ps.hdc, 0,128,NULL);
LineTo(ps.hdc,256,128);
if (mouseOver)
{
incoming = makeVec(mousePos.x,mousePos.y,128,128);
len = vecLen(incoming);
reflected = reflectVector(norm, incoming) * len;
reflected.x += 128;
reflected.y += 128;
mPen = CreatePen(PS_SOLID,1,RGB(0,0,255));
oldPen = (HPEN)SelectObject(ps.hdc, mPen);
MoveToEx(ps.hdc,mousePos.x,mousePos.y,NULL);
LineTo(ps.hdc,128,128);
SelectObject(ps.hdc,oldPen);
DeleteObject(mPen);
mPen = CreatePen(PS_SOLID,1,RGB(255,0,0));
SelectObject(ps.hdc, mPen);
LineTo(ps.hdc,reflected.x,reflected.y);
SelectObject(ps.hdc,oldPen);
DeleteObject(mPen);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
vec3.h
Code:
#ifndef VEC3_H
#define VEC3_H
class vec3
{
public:
// vec3();
vec3():x(0),y(0),z(0){}
vec3(double initX, double initY, double initZ): x(initX),y(initY),z(initZ) {}
~vec3();
vec3(const vec3& other);
vec3& operator=(const vec3& other);
vec3 operator*(const double &scale);
vec3 operator-(const vec3 &rhs);
void print();
double x; //!< Member variable "x;"
double y; //!< Member variable "y;"
double z; //!< Member variable "z;"
};
vec3 reflectVector(vec3 &surfaceNormal, vec3 &lightDir);
vec3 reflect(vec3 &d, vec3 &n);
vec3 reflect(vec3 &light, vec3 &eye, vec3 &pnt, vec3 &norm);
double dotProduct(vec3 &a, vec3 &b);
vec3 crossProduct(vec3 &a, vec3 &b);
vec3 normalize(vec3 &a);
double vecLen(vec3 &a);
#endif // VEC3_H
vec3.cpp
Code:
#include "vec3.h"
#include <math.h>
#include <stdio.h>
vec3::~vec3()
{
//dtor
}
vec3::vec3(const vec3& other)
{
//copy ctor
x=other.x;
y=other.y;
z=other.z;
}
vec3& vec3::operator=(const vec3& rhs)
{
if (this == &rhs) return *this; // handle self assignment
//assignment operator
x = rhs.x;
y = rhs.y;
z = rhs.z;
return *this;
}
vec3 vec3::operator*(const double &rhs)
{
return vec3(x*rhs,y*rhs,z*rhs);//*this;
}
vec3 vec3::operator-(const vec3 &rhs)
{
return vec3(x-rhs.x,y-rhs.y,z-rhs.z);//*this;
}
double vecLenSq(vec3 &a)
{
return a.x*a.x + a.y*a.y + a.z*a.z;
}
double vecLen(vec3 &a)
{
return sqrt(dotProduct(a,a));
}
vec3 normalize(vec3 &a)
{
vec3 result;
double len = vecLen(a), scale=0;
scale = 1.0 / len;
result = a * scale;
return result;
}
//vec3 reflectVector(vec3 &aroundMe, vec3 &refletMe)
vec3 reflectVector(vec3 &surfaceNormal, vec3 &lightDir)
{
vec3 reflected;
vec3 N, L;
double NdotL;
N = normalize(surfaceNormal);
L = normalize(lightDir);
NdotL = dotProduct(N, L);
reflected = L - (N * 2.0 * NdotL);
return reflected;
}
void vec3::print()
{
printf("<%6.3f,%6.3f,%6.3f>\n", x, y, z);
}
double dotProduct(vec3 &a, vec3 &b)
{
return a.x*b.x + a.y*b.y + a.z*b.z;
}
vec3 crossProduct(vec3 &a, vec3 &b)
{
return vec3(
a.y*b.z - b.y*a.z,
a.z*b.x - b.z*a.x,
a.x*b.y - b.x*a.y
);
}