Boom exam done!

This commit is contained in:
2024-12-25 03:14:05 +01:00
parent 28c27a8706
commit 9f90739b90
66 changed files with 9992 additions and 8378 deletions

View File

@@ -9,6 +9,7 @@ set(SOURCES
"src/Texture.cpp" "src/Texture.cpp"
"src/GamePadController.cpp" "src/GamePadController.cpp"
"src/Utils.cpp" "src/Utils.cpp"
"src/HitTest.cpp"
"src/Material.cpp" "src/Material.cpp"
"src/Math/Vector2.cpp" "src/Math/Vector2.cpp"
"src/Math/Vector3.cpp" "src/Math/Vector3.cpp"
@@ -50,6 +51,7 @@ file(GLOB_RECURSE RESOURCE_FILES
"${RESOURCES_SOURCE_DIR}/*.png" "${RESOURCES_SOURCE_DIR}/*.png"
"${RESOURCES_SOURCE_DIR}/*.obj" "${RESOURCES_SOURCE_DIR}/*.obj"
"${RESOURCES_SOURCE_DIR}/*.fx" "${RESOURCES_SOURCE_DIR}/*.fx"
"${RESOURCES_SOURCE_DIR}/*.mtl"
) )
set(RESOURCES_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources/") set(RESOURCES_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources/")
file(MAKE_DIRECTORY ${RESOURCES_OUT_DIR}) file(MAKE_DIRECTORY ${RESOURCES_OUT_DIR})

View File

@@ -1,4 +1,5 @@
SamplerState gSampleState : SampleState; SamplerState gSampleState : SampleState;
RasterizerState gRasterizerState : RasState;
float4x4 gWorldViewProj : WorldViewProjection; float4x4 gWorldViewProj : WorldViewProjection;
float4x4 gWorldMatrix : WorldMatrix; float4x4 gWorldMatrix : WorldMatrix;
@@ -39,12 +40,12 @@ struct VS_OUTPUT {
//---------------------- //----------------------
// Rasterizer state // Rasterizer state
//---------------------- // //----------------------
RasterizerState gRasterizerState // RasterizerState gRasterizerState
{ // {
CullMode = none; // CullMode = none;
FrontCounterClockwise = false; //default // FrontCounterClockwise = false; //default
}; // };
//Vertex shader //Vertex shader

View File

@@ -0,0 +1,141 @@
SamplerState gSampleState : SampleState;
RasterizerState gRasterizerState : RastState;
float4x4 gWorldViewProj : WorldViewProjection;
float4x4 gWorldMatrix : WorldMatrix;
texture2D gDiffuseMap : DiffuseMap;
texture2D gNormalMap : Normal;
texture2D gSpecularMap : Specular;
texture2D gGlossMap : Gloss;
float3 gLightDirection : LightDirection;
float3 gLightColor : LightColor;
float3 gCameraPosition : CameraPosition;
bool gUseNormal : UseNormal;
static const float3 gAmbient = float3(.03f, .03f, .03f);
static const float gLightIntensity = 7.f;
static const float PI = 3.14159f;
static const float gSpecularReflectance = 1.f;
static const float gShininess = 25.f;
//Input output
struct VS_INPUT {
float3 Position : POSITION;
float2 TexCoord : TEXCOORD;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
};
struct VS_OUTPUT {
float4 Position : SV_POSITION;
float4 WorldPosition : WORLDPOSITION;
float2 TexCoord : TEXCOORD;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
};
//----------------------
// Rasterizer state
//----------------------
// RasterizerState gRasterizerState
// {
// CullMode = none;
// FrontCounterClockwise = false; //default
// };
//Vertex shader
VS_OUTPUT VS(VS_INPUT input){
VS_OUTPUT output = (VS_OUTPUT)0;
output.Position = mul(float4(input.Position, 1.f), gWorldViewProj);
output.WorldPosition = mul(float4(input.Position, 1.f), gWorldMatrix);
output.TexCoord = input.TexCoord;
output.Normal = mul(input.Normal, (float3x3) gWorldMatrix);
output.Tangent = mul(input.Tangent, (float3x3) gWorldMatrix);
return output;
}
float3 Phong(float ks, float exp, float3 l, float3 v, float3 n)
{
float3 reflected = reflect(l, n);
float cosAngle = dot(reflected, v);
return ks * pow(max(0.f, cosAngle), exp) * gLightColor;
}
float3 Lambert(float kd, float3 cd)
{
return (kd * cd) / PI;
}
float3 Shade(VS_OUTPUT input)
{
// Sample diffuse, specular, and gloss maps
float3 diffuseSample = gDiffuseMap.Sample(gSampleState, input.TexCoord).rgb;
float3 specularSample = gSpecularMap.Sample(gSampleState, input.TexCoord).rgb;
float glossSample = gGlossMap.Sample(gSampleState, input.TexCoord).x;
float3 normalSample = gNormalMap.Sample(gSampleState, input.TexCoord).rgb;
// Compute inversed view and light directions
float3 invViewDirection = normalize(gCameraPosition - input.WorldPosition.xyz);
float3 invLightDirection = -gLightDirection;
// Compute tangent space axes if normal mapping is used
float3 normal = input.Normal;
if (gUseNormal) {
float3 binormal = cross(input.Normal, input.Tangent);
float3x3 tangentSpaceAxis = float3x3(input.Tangent, binormal, input.Normal);
// Sample and transform normal map
normal = float3(2.f * normalSample.x - 1.f,
2.f * normalSample.y - 1.f,
2.f * normalSample.z - 1.f);
normal = mul(normal, tangentSpaceAxis);
}
// Compute Lambert diffuse lighting
float3 diffuse = Lambert(gLightIntensity, diffuseSample);
// Compute Phong specular lighting
float ks = (specularSample.x + specularSample.y + specularSample.z) / 3.f;
float3 specular = Phong(ks, glossSample * gShininess, invLightDirection, invViewDirection, normal);
// Compute observed area based on the cosine of the light angle
float cosAngle = dot(invLightDirection, normal);
float3 observedArea = float3(cosAngle, cosAngle, cosAngle);
// Combine lighting components
float3 color = saturate(diffuse * observedArea + specular + gAmbient * cosAngle);
return color;
}
float4 PS(VS_OUTPUT input) : SV_TARGET{
return gDiffuseMap.Sample(gSampleState, input.TexCoord);
}
DepthStencilState gDepthStencilState
{
//enable
DepthEnable = true;
DepthWriteMask = ALL;
DepthFunc = LESS;
//stencil
StencilEnable = true;
};
technique11 DefaultTechnique{
pass P0 {
SetDepthStencilState(gDepthStencilState, 0);
SetRasterizerState(gRasterizerState);
SetVertexShader( CompileShader( vs_5_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_5_0, PS() ) );
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

View File

@@ -0,0 +1,39 @@
from PIL import Image
import os
import pprint
# Set the folder containing images
folder_path = 'converted' # Replace with your folder path
output_folder = os.path.join(folder_path, 'dingus')
# Create the 'dingus' folder if it doesn't exist
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# Initialize a pretty printer
pp = pprint.PrettyPrinter(indent=4)
# Iterate through all files in the folder
for filename in os.listdir(folder_path):
if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff')): # Add more formats if needed
file_path = os.path.join(folder_path, filename)
# Open the image
try:
with Image.open(file_path) as img:
# Ensure the image is in 'RGBA' mode (32-bit with 4 channels: R, G, B, A)
img = img.convert('RGBA')
# Create the save path as a PNG in the 'dingus' folder
save_path = os.path.join(output_folder, f'{os.path.splitext(filename)[0]}.png')
# Save the image as PNG
img.save(save_path, 'PNG')
# Pretty-print the successful conversion
pp.pprint(f"Successfully converted and saved: {save_path}")
except Exception as e:
pp.pprint(f"Error processing {filename}: {e}")
print("Conversion complete!")

352
project/resources/scene.mtl Normal file
View File

@@ -0,0 +1,352 @@
# Blender 4.3.2 MTL File: '1GD16E_Verhulst_Bram_Diorama.blend'
# www.blender.org
newmtl M_Baksteen
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_SingleBrick_C.png
newmtl M_Brick
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Brick_C.png
newmtl M_Car
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Car_C.png
newmtl M_Chicken
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_Chicken_C.png
map_d T_Chicken_O.png
newmtl M_ChickenRoof
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_ChickenCoopRoof_C.png
newmtl M_ChickenWireFence
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_ChickenWire_C.png
map_d T_ChickenWire_O.png
newmtl M_Cliff
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_BrickWall_C.png
newmtl M_ClothesLine
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_ClothesLine_C.png
newmtl M_Dirt
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Dirt_C.png
newmtl M_DirtTrimm
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_DirtTrim_C.png
newmtl M_Fountain
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Fountain_C.png
newmtl M_GardenFlowers
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_GardenFlowers_Grass_C.png
map_d T_GardenFlowers_Grass_O.png
newmtl M_GlassPane
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.376859
illum 1
map_Kd T_GlassPane_C.png
newmtl M_Grass
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_GroundGrass_C.png
newmtl M_GrassFlowers
Ns 1000.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_Flowers_C.png
map_d T_Flowers_wheel_O.png
newmtl M_Hay
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Hay_C.png
newmtl M_HouseTrim
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_HouseTrim_C.png
newmtl M_HouseUnique
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_HouseUnique_C.png
newmtl M_IndoorChickenWire
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_ChickenWireInside_C.png
newmtl M_LawnMower_Ladder_pots
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Kd 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
newmtl M_Path
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Path_C.png
newmtl M_PlantPot
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 1
map_Kd T_Vase_C.png
newmtl M_Plants
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_Flowers_C.png
map_d T_Flowers_wheel_O.png
newmtl M_Rocks_Wall
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Rocks_Wall_C.png
newmtl M_RoofTiles
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Roof_C.png
newmtl M_Sand
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_Sand_C.png
newmtl M_SwingChair
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_ChainBench_C.png
map_d T_ChainBench_O.png
newmtl M_TableCloth
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_TableCloth_C.png
newmtl M_TableUnique
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_TableUnique_c.png
newmtl M_TreeBark
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_LocustBark_C.png
newmtl M_TreeLeaf
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_Leaf_C.png
map_d T_Leaf_O.png
newmtl M_Vines
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 1
map_Kd T_Vines_C.png
map_d T_Vines_O.png
newmtl M_Water
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.269091
illum 1
map_Kd T_Water_C.png
newmtl M_WoodPlanks
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_WoodSeamless_C.png
newmtl M_WorldTrimm
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
map_Kd T_WorldTrimm_C.png

File diff suppressed because it is too large Load Diff

View File

@@ -163,7 +163,7 @@ void dae::Camera::Update(const dae::Timer *pTimer) {
mousePosChange = true; mousePosChange = true;
} else if (mouseState == SDL_BUTTON_X2) //lmb + rmb } else if (mouseState == SDL_BUTTON_X2) //lmb + rmb
{ {
origin.y += static_cast<float>(mouseY) / 2; origin.y -= static_cast<float>(mouseY) / 2;
mousePosChange = true; mousePosChange = true;
} }

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include "Math/MathHelpers.h" #include "Math/MathHelpers.h"
#include <algorithm>
#include <cmath>
namespace dae namespace dae
{ {
@@ -11,8 +13,8 @@ namespace dae
void MaxToOne() void MaxToOne()
{ {
const float maxValue = std::max(r, std::max(g, b)); const float maxValue = (r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b);
if (maxValue > 1.f) if (maxValue > 1.f)
*this /= maxValue; *this /= maxValue;
} }

View File

@@ -53,7 +53,6 @@ ID3DX11Effect *BaseEffect::LoadEffect(ID3D11Device *devicePtr, const std::wstrin
std::wstringstream ss; std::wstringstream ss;
for (UINT i{}; i < errorBlobPtr->GetBufferSize(); i++) for (UINT i{}; i < errorBlobPtr->GetBufferSize(); i++)
ss << errorsPtr[i]; ss << errorsPtr[i];
OutputDebugStringW(ss.str().c_str()); OutputDebugStringW(ss.str().c_str());
errorBlobPtr->Release(); errorBlobPtr->Release();
@@ -66,7 +65,6 @@ ID3DX11Effect *BaseEffect::LoadEffect(ID3D11Device *devicePtr, const std::wstrin
return nullptr; return nullptr;
} }
} }
std::cout << "Effect loaded" << std::endl;
return effectPtr; return effectPtr;
} }
@@ -93,3 +91,7 @@ void BaseEffect::SetWorldMatrix(const dae::Matrix& matrix) const {
void BaseEffect::ToggleNormals() { void BaseEffect::ToggleNormals() {
} }
void BaseEffect::NextCullMode() {
}

View File

@@ -25,6 +25,8 @@ public:
virtual void NextSamplingState(); virtual void NextSamplingState();
virtual void NextCullMode();
virtual void SetCameraPos(const dae::Vector3 &vector3) const; virtual void SetCameraPos(const dae::Vector3 &vector3) const;
virtual void SetMaterial(Material *material); virtual void SetMaterial(Material *material);

View File

@@ -10,9 +10,9 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
if(!m_LightPosVariablePtr->IsValid()) if(!m_LightPosVariablePtr->IsValid())
std::wcout << L"gLightDirection Vector is not valid" << std::endl; std::wcout << L"gLightDirection Vector is not valid" << std::endl;
m_SamplerVariablePtr = m_EffectPtr->GetVariableByName("gSampler")->AsSampler(); m_SamplerVariablePtr = m_EffectPtr->GetVariableByName("gSampleState")->AsSampler();
if(!m_SamplerVariablePtr->IsValid()) if(!m_SamplerVariablePtr->IsValid())
std::wcout << L"gSampler Sampler is not valid" << std::endl; std::wcout << L"gSampleState Sampler is not valid" << std::endl;
m_MatWorldVariablePtr = m_EffectPtr->GetVariableByName("gWorldMatrix")->AsMatrix(); m_MatWorldVariablePtr = m_EffectPtr->GetVariableByName("gWorldMatrix")->AsMatrix();
if(!m_MatWorldVariablePtr->IsValid()) if(!m_MatWorldVariablePtr->IsValid())
@@ -46,9 +46,15 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
if(!m_UseNormalMapVariablePtr->IsValid()) if(!m_UseNormalMapVariablePtr->IsValid())
std::wcout << L"gUseNormalMap Scalar is not valid" << std::endl; std::wcout << L"gUseNormalMap Scalar is not valid" << std::endl;
m_RasterizerVariablePtr = m_EffectPtr->GetVariableByName("gRasterizerState")->AsRasterizer();
if(!m_RasterizerVariablePtr->IsValid())
std::wcout << L"gRasterizerState Rasterizer is not valid" << std::endl;
m_UseNormalMapVariablePtr->SetBool(m_UseNormalMap); m_UseNormalMapVariablePtr->SetBool(m_UseNormalMap);
constexpr int vectorSize{ 4 }; constexpr int vectorSize{ 4 };
constexpr float lightDirection[vectorSize]{ .577f, -.577f, .577f, 0.f }; constexpr float lightDirection[vectorSize]{ .577f, -.577f, .577f, 0.f };
m_LightPosVariablePtr->SetFloatVector(lightDirection); m_LightPosVariablePtr->SetFloatVector(lightDirection);
@@ -57,6 +63,10 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
m_LightColorVariablePtr->SetFloatVector(lightColor); m_LightColorVariablePtr->SetFloatVector(lightColor);
this->InitSamplers(devicePtr); this->InitSamplers(devicePtr);
this->InitRasterizer(devicePtr);
m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
m_RasterizerVariablePtr->SetRasterizerState(0,m_RasterizerStates[static_cast<int>(m_CullMode)]);
} }
Effect::~Effect() { Effect::~Effect() {
@@ -90,6 +100,9 @@ Effect::~Effect() {
m_SamplerVariablePtr->Release(); m_SamplerVariablePtr->Release();
m_SamplerVariablePtr = nullptr; m_SamplerVariablePtr = nullptr;
m_RasterizerVariablePtr->Release();
m_RasterizerVariablePtr = nullptr;
for(auto sampler : m_SamplerStates){ for(auto sampler : m_SamplerStates){
sampler->Release(); sampler->Release();
} }
@@ -156,3 +169,32 @@ void Effect::InitSamplers(ID3D11Device *devicePtr) {
m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]); m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
} }
void Effect::NextCullMode() {
m_CullMode = static_cast<CullMode>((static_cast<int>(m_CullMode) + 1) % 3);
m_RasterizerVariablePtr->SetRasterizerState(0,m_RasterizerStates[static_cast<int>(m_CullMode)]);
}
void Effect::InitRasterizer(ID3D11Device *devicePtr) {
D3D11_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D11_FILL_SOLID; // Solid fill
rasterDesc.FrontCounterClockwise = FALSE;
rasterDesc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS;
rasterDesc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
rasterDesc.DepthClipEnable = TRUE;
rasterDesc.ScissorEnable = FALSE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;
rasterDesc.CullMode = D3D11_CULL_BACK; // Cull back faces
devicePtr->CreateRasterizerState(&rasterDesc, &m_RasterizerStates[static_cast<int>(CullMode::Back)]);
rasterDesc.CullMode = D3D11_CULL_FRONT;
devicePtr->CreateRasterizerState(&rasterDesc, &m_RasterizerStates[static_cast<int>(CullMode::Front)]);
rasterDesc.CullMode = D3D11_CULL_NONE;
devicePtr->CreateRasterizerState(&rasterDesc, &m_RasterizerStates[static_cast<int>(CullMode::None)]);
}

View File

@@ -9,6 +9,12 @@ enum class TechniqueType {
Anisotropic = 2 Anisotropic = 2
}; };
enum class CullMode {
None = 0,
Front = 1,
Back = 2
};
class Effect: public BaseEffect { class Effect: public BaseEffect {
public: public:
@@ -20,15 +26,18 @@ public:
void SetCameraPos(const dae::Vector3 &pos) const override; void SetCameraPos(const dae::Vector3 &pos) const override;
void SetMaterial(Material *material); void SetMaterial(Material *material) override;
void ToggleNormals() override; void ToggleNormals() override;
void NextSamplingState() override; void NextSamplingState() override;
void NextCullMode() override;
private: private:
void InitSamplers(ID3D11Device* devicePtr); void InitSamplers(ID3D11Device* devicePtr);
void InitRasterizer(ID3D11Device* devicePtr);
ID3DX11EffectMatrixVariable *m_MatWorldVariablePtr{}; ID3DX11EffectMatrixVariable *m_MatWorldVariablePtr{};
@@ -45,9 +54,14 @@ private:
ID3DX11EffectSamplerVariable *m_SamplerVariablePtr{}; ID3DX11EffectSamplerVariable *m_SamplerVariablePtr{};
ID3DX11EffectRasterizerVariable* m_RasterizerVariablePtr{};
TechniqueType m_TechniqueType{TechniqueType::Linear}; TechniqueType m_TechniqueType{TechniqueType::Linear};
std::array<ID3D11SamplerState*, 3> m_SamplerStates{}; std::array<ID3D11SamplerState*, 3> m_SamplerStates{};
std::array<ID3D11RasterizerState*, 3> m_RasterizerStates{};
CullMode m_CullMode{ CullMode::Back };
bool m_UseNormalMap{true}; bool m_UseNormalMap{true};
}; };

72
project/src/HitTest.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "HitTest.h"
float CrossZ(const Vector3& p0, const Vector3& p1, const Vector3& point)
{
return (p1.x - p0.x) * (point.y - p0.y)
- (p1.y - p0.y) * (point.x - p0.x);
}
std::optional<Sample> TriangleHitTest(const Vector3& fragPos, const VertexOut& v0, const VertexOut& v1, const VertexOut& v2)
{
Vector3 weights;
weights.x = CrossZ(v2.position, v1.position, fragPos);
if ( weights.x > 0 )
return std::nullopt;
weights.y = CrossZ(v0.position, v2.position, fragPos);
if ( weights.y > 0 )
return std::nullopt;
weights.z = CrossZ(v1.position, v0.position, fragPos);
if ( weights.z > 0 )
return std::nullopt;
const float totalWeight{ weights.x + weights.y + weights.z };
const float invTotalWeight{ 1.0f / totalWeight };
const Vector3 normWeights{
weights.x * invTotalWeight,
weights.y * invTotalWeight,
weights.z * invTotalWeight
};
const float depth =
1 / (normWeights.x / v0.position.w +
normWeights.y / v1.position.w +
normWeights.z / v2.position.w);
const Vector2 uv =
v0.uv * depth * normWeights.x / v0.position.w +
v1.uv * depth * normWeights.y / v1.position.w +
v2.uv * depth * normWeights.z / v2.position.w;
const float interpolatedDepth = 1 / (normWeights.x / v0.position.w + normWeights.y / v1.position.w + normWeights.z / v2.position.w);
auto interpolate =
[&]<typename Type>(const Type& val0, const Type& val1, const Type& val2) -> Type
{
return (val0 / v0.position.w * normWeights.x +
val1 / v1.position.w * normWeights.y +
val2 / v2.position.w * normWeights.z) * interpolatedDepth;
};
//Invert the normal
const Vector3 normal = interpolate(v0.normal, v1.normal, v2.normal).Normalized();
const Vector3 tangent = interpolate(v0.tangent, v1.tangent, v2.tangent).Normalized();
const Vector3 viewDir = interpolate(v0.viewDir, v1.viewDir, v2.viewDir).Normalized();
return Sample{
.uv = uv,
.normal = normal,
.tangent = tangent,
.viewDirection = viewDir,
.depth = depth,
.weight = normWeights,
.mesh = v0.mesh
};
}

28
project/src/HitTest.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef GP1_DIRECTX_HITTEST_H
#define GP1_DIRECTX_HITTEST_H
#include <algorithm>
#include <optional>
#include "ColorRGB.h"
#include "Math/Vector3.h"
#include "Math/Vector2.h"
#include "Mesh.h"
using namespace dae;
struct Sample
{
Vector2 uv{};
Vector3 normal{};
Vector3 tangent{};
Vector3 viewDirection{};
float depth{};
Vector3 weight{};
Mesh* mesh{};
};
std::optional<Sample> TriangleHitTest(const Vector3& fragPos, const VertexOut& v0, const VertexOut& v1, const VertexOut& v2);
#endif //GP1_DIRECTX_HITTEST_H

View File

@@ -164,5 +164,10 @@ namespace dae {
if (index == 1) return y; if (index == 1) return y;
return z; return z;
} }
bool Vector3::operator==(const Vector3 &v) const {
return (x - v.x) < FLT_EPSILON && (y - v.y) < FLT_EPSILON && (z - v.z) < FLT_EPSILON;
}
#pragma endregion #pragma endregion
} }

View File

@@ -44,6 +44,8 @@ namespace dae
Vector3& operator*=(float scale); Vector3& operator*=(float scale);
float& operator[](int index); float& operator[](int index);
float operator[](int index) const; float operator[](int index) const;
bool operator==(const Vector3& v) const;
static const Vector3 UnitX; static const Vector3 UnitX;
static const Vector3 UnitY; static const Vector3 UnitY;

View File

@@ -98,5 +98,14 @@ namespace dae
if (index == 2)return z; if (index == 2)return z;
return w; return w;
} }
bool Vector4::operator==(const Vector4 &v) const {
return
std::abs(x - v.x) <= FLT_EPSILON &&
std::abs(y - v.y) <= FLT_EPSILON &&
std::abs(z - v.z) <= FLT_EPSILON &&
std::abs(w - v.w) <= FLT_EPSILON;
}
#pragma endregion #pragma endregion
} }

View File

@@ -32,5 +32,6 @@ namespace dae
Vector4& operator+=(const Vector4& v); Vector4& operator+=(const Vector4& v);
float& operator[](int index); float& operator[](int index);
float operator[](int index) const; float operator[](int index) const;
bool operator==(const Vector4& v) const;
}; };
} }

View File

@@ -136,3 +136,12 @@ void Mesh::SetWorldMatrix(const Matrix &matrix) {
void Mesh::ToggleNormals() { void Mesh::ToggleNormals() {
m_EffectPtr->ToggleNormals(); m_EffectPtr->ToggleNormals();
} }
void Mesh::SetMaterial(Material *pMaterial) {
m_Material.reset(pMaterial);
m_EffectPtr->SetMaterial(pMaterial);
}
void Mesh::CycleCullMode() {
m_EffectPtr->NextCullMode();
}

View File

@@ -13,6 +13,11 @@ using namespace dae;
struct VertexIn; struct VertexIn;
struct VertexOut; struct VertexOut;
enum class PrimitiveTopology {
TriangleList,
TriangleStrip
};
@@ -33,8 +38,21 @@ public:
void NextSamplingState(); void NextSamplingState();
Material* GetMaterial() const { return m_Material.get(); }
void SetWorldMatrix(const Matrix &matrix); void SetWorldMatrix(const Matrix &matrix);
std::vector<VertexIn>& GetVertices() { return m_VerticesIn; }
std::vector<Uint32>& GetIndices() { return m_Indices; }
PrimitiveTopology GetPrimitiveTopology() const { return m_PrimitiveTopology; }
void SetMaterial(Material *pMaterial);
void CycleCullMode();
void SetShouldRender(bool shouldRender) { m_ShouldRender = shouldRender; }
bool GetShouldRender() const { return m_ShouldRender; }
private: private:
BaseEffect *m_EffectPtr; BaseEffect *m_EffectPtr;
@@ -49,6 +67,10 @@ private:
UINT m_IndicesCount; UINT m_IndicesCount;
std::shared_ptr<Material> m_Material{}; std::shared_ptr<Material> m_Material{};
PrimitiveTopology m_PrimitiveTopology{PrimitiveTopology::TriangleList};
bool m_ShouldRender{ true };
}; };
struct VertexIn { struct VertexIn {
@@ -65,5 +87,7 @@ struct VertexOut {
Vector3 normal{}; Vector3 normal{};
Vector3 tangent{}; Vector3 tangent{};
Vector3 viewDir{}; Vector3 viewDir{};
Mesh* mesh{};
bool valid{ true };
}; };

View File

@@ -5,6 +5,7 @@
#include "Texture.h" #include "Texture.h"
#include "Effects/Effect.h" #include "Effects/Effect.h"
#include "Effects/FireEffect.h" #include "Effects/FireEffect.h"
#include "HitTest.h"
namespace dae { namespace dae {
@@ -63,6 +64,23 @@ namespace dae {
FireEffect* fireEffect = new FireEffect(m_DevicePtr, L"resources/Fire.fx"); FireEffect* fireEffect = new FireEffect(m_DevicePtr, L"resources/Fire.fx");
m_meshes.push_back(new Mesh(m_DevicePtr, vertices, indices, FireMaterial, fireEffect)); m_meshes.push_back(new Mesh(m_DevicePtr, vertices, indices, FireMaterial, fireEffect));
m_pFireMesh = m_meshes.back();
//
// std::vector<std::unique_ptr<Utils::MaterialMesh>> materialMeshes;
// Utils::LoadObjWithMaterials("resources/scene.obj", materialMeshes, true, m_DevicePtr);
// for (const auto &mesh: materialMeshes) {
// if(mesh->vertices.size() > 0) {
// Effect *effect = new Effect(m_DevicePtr, L"resources/SimpleDiffuse.fx");
// std::shared_ptr<Material> material = std::make_shared<Material>();
// material->diffuseTexturePtr = Texture::LoadFromFile("./resources/" + mesh->diffuse_texture, m_DevicePtr);
// m_meshes.push_back(new Mesh(m_DevicePtr, mesh->vertices, mesh->indices, material, effect));
// Matrix worldMatrix = m_meshes.back()->GetWorldMatrix();
// worldMatrix *= Matrix::CreateScale(2.f, 2.f, 2.f);
// m_meshes.back()->SetWorldMatrix(worldMatrix);
// }
// }
float aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height); float aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height);
m_Camera = Camera({.0f, 5.0f, -64.f}, 45.f); m_Camera = Camera({.0f, 5.0f, -64.f}, 45.f);
@@ -90,6 +108,12 @@ namespace dae {
delete mesh; delete mesh;
} }
//SDL
SDL_FreeSurface(m_pBackBuffer);
SDL_FreeSurface(m_pFrontBuffer);
delete[] m_pDepthBufferPixels;
} }
@@ -108,40 +132,189 @@ namespace dae {
} }
} }
void Renderer::Render() const { void Renderer::Render() {
if (!m_IsInitialized) if (!m_IsInitialized)
return; return;
if (m_backendType == Backendtype::DirectX) { if (m_backendType == Backendtype::DirectX) {
this->RenderDirectX();
} else {
this->RenderSDL();
}
//Clear back buffer }
void Renderer::RenderDirectX() const {
//Clear back buffer
if(m_UniformClearColor){
const float clearColor[] = {static_cast<float>(r) / 255.f, static_cast<float>(g) / 255.f, static_cast<float>(b) / 255.f, 1.f};
m_DeviceContextPtr->ClearRenderTargetView(m_RenderTargetViewPtr, clearColor);
} else {
const float clearColor[] = {1.f / 255.f, 0.f / 255.f, 76.f / 255.f, 1.f}; const float clearColor[] = {1.f / 255.f, 0.f / 255.f, 76.f / 255.f, 1.f};
m_DeviceContextPtr->ClearRenderTargetView(m_RenderTargetViewPtr, clearColor); m_DeviceContextPtr->ClearRenderTargetView(m_RenderTargetViewPtr, clearColor);
m_DeviceContextPtr->ClearDepthStencilView(m_DepthStencilViewPtr, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); }
Matrix viewProjMatrix = m_Camera.GetViewProjectionMatrix(); m_DeviceContextPtr->ClearDepthStencilView(m_DepthStencilViewPtr, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
for (auto mesh: m_meshes) {
Matrix viewProjMatrix = m_Camera.GetViewProjectionMatrix();
for (auto mesh: m_meshes) {
if(mesh->GetShouldRender()){
Matrix modelMatrix = mesh->GetWorldMatrix(); Matrix modelMatrix = mesh->GetWorldMatrix();
Matrix worldViewProjMatrix = modelMatrix * viewProjMatrix; Matrix worldViewProjMatrix = modelMatrix * viewProjMatrix;
mesh->Render(m_DeviceContextPtr, worldViewProjMatrix); mesh->Render(m_DeviceContextPtr, worldViewProjMatrix);
} }
//Present
m_SwapChainPtr->Present(0, 0);
} else {
SDL_FillRect(m_pBackBuffer, nullptr, Uint32(255 << 24) + Uint32(100 << 16) + Uint32(100 << 8) + Uint32(100));
//Lock BackBuffer
for (int x = 0; x < 100; ++x) {
for (int y = 0; y < 100; ++y) {
m_pBackBufferPixels[(x + 100) + (y + 150) * m_Width] = SDL_MapRGB(m_pBackBuffer->format, 255, 0, 0);
}
}
SDL_BlitSurface(m_pBackBuffer, nullptr, m_pFrontBuffer, nullptr);
SDL_UpdateWindowSurface(m_pWindow);
} }
//Present
m_SwapChainPtr->Present(0, 0);
}
void Renderer::RenderSDL() {
SDL_FillRect(m_pBackBuffer, nullptr, m_ClearColor);
SDL_LockSurface(m_pBackBuffer);
std::fill_n(m_pDepthBufferPixels, m_Width * m_Height, std::numeric_limits<float>::max());
SDL_FillRect(m_pBackBuffer, nullptr, m_ClearColor);
ColorRGB finalColor{};
constexpr int numVerticies = 3;
m_VerticiesScreenSpace.clear();
for (auto* currentMesh: m_meshes) {
if(!currentMesh->GetShouldRender()){
continue;
}
const Matrix worldViewProjectionMatrix{ currentMesh->GetWorldMatrix() * m_Camera.GetViewProjectionMatrix() };
VertexTransformationFunction(worldViewProjectionMatrix, currentMesh, currentMesh->GetVertices(), m_VerticiesScreenSpace);
int numTriangles{};
switch (currentMesh->GetPrimitiveTopology()) {
case PrimitiveTopology::TriangleList:
numTriangles = static_cast<int>(currentMesh->GetIndices().size()) / numVerticies;
break;
case PrimitiveTopology::TriangleStrip:
numTriangles = static_cast<int>(currentMesh->GetIndices().size()) - 2;
break;
}
for (int triangleIndex{}; triangleIndex < numTriangles; ++triangleIndex) {
VertexOut vertex0, vertex1, vertex2;
switch (currentMesh->GetPrimitiveTopology()) {
case PrimitiveTopology::TriangleList:
vertex0 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex * numVerticies + 0]];
vertex1 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex * numVerticies + 1]];
vertex2 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex * numVerticies + 2]];
break;
case PrimitiveTopology::TriangleStrip:
vertex0 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex + 0]];
vertex1 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex + 1]];
vertex2 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex + 2]];
if (triangleIndex % 2 == 1) {
std::swap(vertex1, vertex2);
}
if (vertex0.position == vertex1.position ||
vertex0.position == vertex2.position ||
vertex1.position == vertex2.position) {
continue;
}
break;
}
if (!vertex0.valid and !vertex1.valid and !vertex2.valid) {
continue;
}
const float minX{std::min(vertex0.position.x, std::min(vertex1.position.x, vertex2.position.x))};
const float minY{std::min(vertex0.position.y, std::min(vertex1.position.y, vertex2.position.y))};
const float maxX{std::max(vertex0.position.x, std::max(vertex1.position.x, vertex2.position.x))};
const float maxY{std::max(vertex0.position.y, std::max(vertex1.position.y, vertex2.position.y))};
const Vector3 side1{vertex1.position - vertex0.position};
const Vector3 side2{vertex2.position - vertex0.position};
const float totalArea{Vector3::Cross(side1, side2).z};
const int startX = std::max(0, static_cast<int>(minX)) - 1;
const int endX = std::min(m_Width - 1, static_cast<int>(maxX)) + 1;
const int startY = std::max(0, static_cast<int>(minY)) - 1;
const int endY = std::min(m_Height - 1, static_cast<int>(maxY)) + 1;
for (int px{startX}; px < endX; ++px) {
for (int py{startY}; py < endY; ++py) {
if(m_isHitbox){
//Hitboxes
m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
static_cast<uint8_t>(255),
static_cast<uint8_t>(255),
static_cast<uint8_t>(255));
continue;
}
if (px < 0 || px >= m_Width || py < 0 || py >= m_Height) {
//TEMP fix for out of bounds
//This is to remove triangles having an incorrect edge on their bounding box
continue;
}
Vector3 P{static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f};
auto sample{ TriangleHitTest(P, vertex0, vertex1, vertex2) };
if (!sample.has_value()) {
continue;
}
const Vector3 fragPos{ static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f };
int depthBufferIndex{ px + (py * m_Width) };
float min{.985f};
float max{1.f};
float depthBuffer{(sample.value().depth - min) * (max - min)};
float currentDepth = sample.value().depth;
if (m_pDepthBufferPixels[depthBufferIndex] > currentDepth) {
m_pDepthBufferPixels[depthBufferIndex] = currentDepth;
if (m_isDepthBuffer) {
finalColor = ColorRGB{depthBuffer, depthBuffer, depthBuffer};
} else {
finalColor = ShadePixel(sample.value());
}
finalColor.MaxToOne();
m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
static_cast<uint8_t>(finalColor.r * 255),
static_cast<uint8_t>(finalColor.g * 255),
static_cast<uint8_t>(finalColor.b * 255));
}
}
}
}
}
SDL_UnlockSurface(m_pBackBuffer);
SDL_BlitSurface(m_pBackBuffer,nullptr, m_pFrontBuffer, nullptr);
SDL_UpdateWindowSurface(m_pWindow);
} }
HRESULT Renderer::InitializeDirectX() { HRESULT Renderer::InitializeDirectX() {
@@ -259,10 +432,163 @@ namespace dae {
m_pBackBuffer = SDL_CreateRGBSurface(0, m_Width, m_Height, 32, 0, 0, 0, 0); m_pBackBuffer = SDL_CreateRGBSurface(0, m_Width, m_Height, 32, 0, 0, 0, 0);
m_pBackBufferPixels = (uint32_t *) m_pBackBuffer->pixels; m_pBackBufferPixels = (uint32_t *) m_pBackBuffer->pixels;
// m_pDepthBufferPixels = new float[m_Width * m_Height]; m_pDepthBufferPixels = new float[m_Width * m_Height];
}
void Renderer::VertexTransformationFunction(const Matrix &WorldViewProjectionMatrix, Mesh* mesh,
std::vector<VertexIn> &vertices_in, std::vector<VertexOut> &vertices_out) const {
for (const VertexIn& vert : vertices_in)
{
VertexOut vertex_out{};
Vector4 vertPos{ WorldViewProjectionMatrix.TransformPoint({vert.position, 1}) };
const Vector3 normal{ mesh->GetWorldMatrix().TransformVector(vert.normal) };
const Vector3 tangent{ mesh->GetWorldMatrix().TransformVector(vert.tangent) };
vertPos.x /= vertPos.w;
vertPos.y /= vertPos.w;
vertPos.z /= vertPos.w;
bool isValid{ true };
//Check if the vertex is inside the screen
if (vertPos.x < -1.f || vertPos.x > 1.f ||
vertPos.y < -1.f || vertPos.y > 1.f ||
vertPos.z < 0.f || vertPos.z > 1.f)
isValid = false;
vertPos.x = ((vertPos.x + 1.f) / 2.f) * static_cast<float>(m_Width);
vertPos.y = ((1.f - vertPos.y) / 2.f) * static_cast<float>(m_Height);
vertex_out.position = vertPos;
vertex_out.uv = vert.uv;
vertex_out.normal = normal;
vertex_out.tangent = tangent;
vertex_out.mesh = mesh;
// vertex_out.viewDir = WorldViewProjectionMatrix.TransformVector(vert.viewDir);
vertex_out.valid = isValid;
vertices_out.push_back(vertex_out);
}
} }
void Renderer::ToggleDepthBuffer() {
m_isDepthBuffer = !m_isDepthBuffer;
}
ColorRGB Renderer::ShadePixel(const Sample &sample) {
Material* currentMaterial = sample.mesh->GetMaterial();
if(currentMaterial->normalTexturePtr == nullptr && currentMaterial->specularTexturePtr == nullptr && currentMaterial->glossTexturePtr == nullptr){
return currentMaterial->diffuseTexturePtr->Sample(sample.uv);
}
Vector3 lightDirection = { .577f, -.577f, .577f};
Vector3 normal = sample.normal.Normalized();
constexpr float lightIntensity{ 7.f };
ColorRGB color{ 1, 1, 1 };
constexpr ColorRGB ambient{ .03f, .03f, .03f};
if(m_useNormals){
const ColorRGB normalSample{ sample.mesh->GetMaterial()->normalTexturePtr->Sample(sample.uv) };
const Vector4 normalMapSample{
2.f * normalSample.r - 1.f,
2.f * normalSample.g - 1.f,
2.f * normalSample.b - 1.f,
0.f
};
const Vector3 biNormal{ Vector3::Cross(normal, sample.tangent) };
const Matrix tangentToWorld{
Vector4{ sample.tangent, 0.f },
Vector4{ biNormal, 0.f },
Vector4{ normal, 0.f },
Vector4{ 0.f, 0.f, 0.f, 1.f }
};
normal = tangentToWorld.TransformVector(normalMapSample).Normalized();
}
const ColorRGB diffuseSample{ currentMaterial->diffuseTexturePtr->Sample(sample.uv) };
double invPi = 1.0 / PI;
const ColorRGB lambert{ diffuseSample * lightIntensity * invPi };
//TODO: ask why deviding by PI causses Segmentation fault
// const ColorRGB lambert{ diffuseSample * lightIntensity / PI };
float specularReflectance{ 1.f };
float shininess{ 25.f };
specularReflectance *= currentMaterial->glossTexturePtr->Sample(sample.uv).r;
shininess *= currentMaterial->specularTexturePtr->Sample(sample.uv).r;
const float cosAngle = Vector3::Dot(normal, -lightDirection);
const ColorRGB specular = specularReflectance * powf(cosAngle, shininess) * colors::White;
if (cosAngle < 0) {
return ambient;
}
switch(m_ShadeMode){
case ShadeMode::ObservedArea:
break;
case ShadeMode::Diffuse:
color = lambert;
break;
case ShadeMode::Specular:
color = specular;
break;
case ShadeMode::Combined:
color = lambert + specular + ambient;
break;
}
color *= ColorRGB{ cosAngle, cosAngle, cosAngle };
return color;
}
void Renderer::CycleCullMode() {
for(auto mesh: m_meshes){
mesh->CycleCullMode();
}
}
void Renderer::ToggleBoundingBox() {
m_isHitbox = !m_isHitbox;
}
void Renderer::CycleRenderingMode() {
switch (m_ShadeMode) {
case ShadeMode::ObservedArea:
m_ShadeMode = ShadeMode::Diffuse;
std::cout << "Diffuse" << std::endl;
break;
case ShadeMode::Diffuse:
m_ShadeMode = ShadeMode::Specular;
std::cout << "Specular" << std::endl;
break;
case ShadeMode::Specular:
m_ShadeMode = ShadeMode::Combined;
std::cout << "Combined" << std::endl;
break;
case ShadeMode::Combined:
m_ShadeMode = ShadeMode::ObservedArea;
std::cout << "Observed Area" << std::endl;
break;
}
}
void Renderer::SwitchBackend() { void Renderer::SwitchBackend() {
if (m_backendType == Backendtype::DirectX) { if (m_backendType == Backendtype::DirectX) {
m_backendType = Backendtype::SDL; m_backendType = Backendtype::SDL;
@@ -278,6 +604,7 @@ namespace dae {
} }
void Renderer::ToggleNormals() { void Renderer::ToggleNormals() {
m_useNormals = !m_useNormals;
for(auto mesh: m_meshes){ for(auto mesh: m_meshes){
mesh->ToggleNormals(); mesh->ToggleNormals();
} }
@@ -290,4 +617,10 @@ namespace dae {
void Renderer::ToggleUniformClearColor() { void Renderer::ToggleUniformClearColor() {
m_UniformClearColor = !m_UniformClearColor; m_UniformClearColor = !m_UniformClearColor;
} }
void Renderer::ToggleFireFX() {
m_pFireMesh->SetShouldRender(!m_pFireMesh->GetShouldRender());
}
} }

View File

@@ -2,6 +2,7 @@
#include "Mesh.h" #include "Mesh.h"
#include "Camera.h" #include "Camera.h"
#include "HitTest.h"
struct SDL_Window; struct SDL_Window;
struct SDL_Surface; struct SDL_Surface;
@@ -11,12 +12,19 @@ enum class Backendtype {
SDL SDL
}; };
enum class ShadeMode{
ObservedArea,
Diffuse,
Specular,
Combined
};
namespace dae namespace dae
{ {
class Renderer final class Renderer final
{ {
public: public:
Renderer(SDL_Window* pWindow); explicit Renderer(SDL_Window* pWindow);
~Renderer(); ~Renderer();
Renderer(const Renderer&) = delete; Renderer(const Renderer&) = delete;
@@ -25,7 +33,7 @@ namespace dae
Renderer& operator=(Renderer&&) noexcept = delete; Renderer& operator=(Renderer&&) noexcept = delete;
void Update(const Timer* pTimer); void Update(const Timer* pTimer);
void Render() const; void Render();
//Switching Functions //Switching Functions
void NextSamplingState(); void NextSamplingState();
@@ -37,31 +45,23 @@ namespace dae
void ToggleUniformClearColor(); void ToggleUniformClearColor();
void ToggleDepthBuffer();
void CycleCullMode();
void ToggleBoundingBox();
void CycleRenderingMode();
void ToggleFireFX();
private: private:
// Common vars
SDL_Window* m_pWindow{}; SDL_Window* m_pWindow{};
int m_Width{}; int m_Width{};
int m_Height{}; int m_Height{};
bool m_IsInitialized{ false };
//DIRECTX
HRESULT InitializeDirectX();
void InitializeSDLRasterizer();
ID3D11Device* m_DevicePtr{};
ID3D11DeviceContext* m_DeviceContextPtr{};
IDXGISwapChain* m_SwapChainPtr{};
ID3D11Texture2D* m_DepthStencilBufferPtr{};
ID3D11DepthStencilView* m_DepthStencilViewPtr{};
ID3D11Resource* m_RenderTargetBufferPtr{};
ID3D11RenderTargetView* m_RenderTargetViewPtr{};
SDL_Surface* m_pFrontBuffer{ nullptr };
SDL_Surface* m_pBackBuffer{ nullptr };
uint32_t* m_pBackBufferPixels{};
std::vector<Mesh*> m_meshes{}; std::vector<Mesh*> m_meshes{};
std::vector<std::shared_ptr<Material>> m_materials{}; std::vector<std::shared_ptr<Material>> m_materials{};
@@ -73,5 +73,51 @@ namespace dae
float m_currentRotation{}; float m_currentRotation{};
bool m_UniformClearColor{ false }; bool m_UniformClearColor{ false };
//DirectX vars
bool m_IsInitialized{ false };
HRESULT InitializeDirectX();
void RenderDirectX() const;
//Storing the mesh so i can deactivate it;
Mesh* m_pFireMesh{};
ID3D11Device* m_DevicePtr{};
ID3D11DeviceContext* m_DeviceContextPtr{};
IDXGISwapChain* m_SwapChainPtr{};
ID3D11Texture2D* m_DepthStencilBufferPtr{};
ID3D11DepthStencilView* m_DepthStencilViewPtr{};
ID3D11Resource* m_RenderTargetBufferPtr{};
ID3D11RenderTargetView* m_RenderTargetViewPtr{};
//SDL vars
void InitializeSDLRasterizer();
void RenderSDL();
void VertexTransformationFunction(const Matrix& WorldViewProjectionMatrix, Mesh* mesh, std::vector<VertexIn> &vertices_in, std::vector<VertexOut> &vertices_out) const;
ColorRGB ShadePixel(const Sample& sample);
SDL_Surface* m_pFrontBuffer{ nullptr };
SDL_Surface* m_pBackBuffer{ nullptr };
uint32_t* m_pBackBufferPixels{};
bool m_useNormals{ true };
bool m_isHitbox{ false };
ShadeMode m_ShadeMode{ ShadeMode::Combined };
bool m_isDepthBuffer{ false };
Uint8 r{100};
Uint8 g{100};
Uint8 b{100};
Uint32 m_ClearColor{ Uint32(255 << 24) + Uint32(r << 16) + Uint32(g << 8) + Uint32(b) };
float* m_pDepthBufferPixels{};
std::vector<VertexOut> m_VerticiesScreenSpace{};
}; };
} }

View File

@@ -1,3 +1,4 @@
#include <algorithm>
#include "Texture.h" #include "Texture.h"
Texture::~Texture() { Texture::~Texture() {
@@ -11,6 +12,11 @@ Texture *Texture::LoadFromFile(const std::string &path, ID3D11Device *devicePtr)
std::cerr << "Failed to load texture: " << path << std::endl; std::cerr << "Failed to load texture: " << path << std::endl;
return nullptr; return nullptr;
} }
if (surface->format->BytesPerPixel != 4)
{
std::cerr << "Texture::LoadFromFile > Texture is not in the right format: " << path << std::endl;
// throw std::runtime_error("Texture is not in the right format");
}
auto *texture = new Texture(surface, devicePtr); auto *texture = new Texture(surface, devicePtr);
@@ -46,6 +52,22 @@ Texture::Texture(SDL_Surface *surfacePtr, ID3D11Device *devicePtr) {
hr = devicePtr->CreateShaderResourceView(m_TexturePtr, &SRVDesc, &m_TextureResourceViewPtr); hr = devicePtr->CreateShaderResourceView(m_TexturePtr, &SRVDesc, &m_TextureResourceViewPtr);
SDL_FreeSurface(surfacePtr); m_SurfacePtr = surfacePtr;
m_pSurfacePixels = static_cast<Uint32 *>(surfacePtr->pixels);
}
ColorRGB Texture::Sample(const Vector2 &uv) const {
Uint8 red, green, blue;
Vector2 wrapped = {fmod(uv.x, 1.0f), fmod(uv.y, 1.0f)};
if (wrapped.x < 0.0f) wrapped.x += 1.0f;
if (wrapped.y < 0.0f) wrapped.y += 1.0f;
SDL_GetRGB(m_pSurfacePixels[
static_cast<int>(wrapped.x * static_cast<float>(m_SurfacePtr->w - 1)) +
static_cast<int>(wrapped.y * static_cast<float>(m_SurfacePtr->h - 1)) * (m_SurfacePtr->w)
], m_SurfacePtr->format, &red, &green, &blue);
return ColorRGB{static_cast<float>(red) / 255.0f, static_cast<float>(green) / 255.0f, static_cast<float>(blue) / 255.0f};
} }

View File

@@ -7,7 +7,10 @@
#include "Texture.h" #include "Texture.h"
#include "SDL_surface.h" #include "SDL_surface.h"
#include "SDL_image.h" #include "SDL_image.h"
#include "ColorRGB.h"
#include "Math/Vector2.h"
using namespace dae;
class Texture { class Texture {
public: public:
@@ -17,11 +20,16 @@ public:
inline ID3D11ShaderResourceView* GetSrv() const { return m_TextureResourceViewPtr; } inline ID3D11ShaderResourceView* GetSrv() const { return m_TextureResourceViewPtr; }
ColorRGB Sample(const Vector2& uv) const;
private: private:
Texture(SDL_Surface* surfacePtr, ID3D11Device* devicePtr); Texture(SDL_Surface* surfacePtr, ID3D11Device* devicePtr);
ID3D11ShaderResourceView* m_TextureResourceViewPtr{}; ID3D11ShaderResourceView* m_TextureResourceViewPtr{};
ID3D11Texture2D* m_TexturePtr{}; ID3D11Texture2D* m_TexturePtr{};
SDL_Surface* m_SurfacePtr{ nullptr };
uint32_t* m_pSurfacePixels{ nullptr };
}; };

View File

@@ -256,5 +256,118 @@ namespace dae {
return true; return true;
} }
struct MaterialMesh {
std::vector<VertexIn> vertices;
std::vector<uint32_t> indices;
int material_id = -1; // Material ID associated with this mesh
std::string diffuse_texture; // Path to the diffuse texture
};
static bool LoadObjWithMaterials(const std::string &fileName, std::vector<std::unique_ptr<MaterialMesh>> &meshes,
bool flipAxisAndWinding = true, ID3D11Device* device = nullptr) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn, err;
std::string basepath = "resources/";
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, fileName.c_str(), basepath.c_str())) {
if (!warn.empty()) {
std::cerr << "Warning: " << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "Error: " << err << std::endl;
}
return false;
}
// Clear and prepare the meshes array
meshes.clear();
// Create Mesh objects for each material
meshes.resize(materials.size());
for (size_t i = 0; i < materials.size(); ++i) {
meshes[i] = std::make_unique<MaterialMesh>();
meshes[i]->material_id = static_cast<int>(i);
meshes[i]->diffuse_texture = materials[i].diffuse_texname;
}
// Default Mesh for faces with no material
auto defaultMesh = std::make_unique<MaterialMesh>();
defaultMesh->material_id = -1;
defaultMesh->diffuse_texture = "";
meshes.push_back(std::move(defaultMesh));
for (const auto &shape : shapes) {
size_t index_offset = 0;
for (size_t f = 0; f < shape.mesh.num_face_vertices.size(); f++) {
auto fv = size_t(shape.mesh.num_face_vertices[f]);
if (fv != 3) {
std::cerr << "Error: Only triangular faces are supported." << std::endl;
return false;
}
int material_id = (f < shape.mesh.material_ids.size()) ? shape.mesh.material_ids[f] : -1;
if (material_id < 0 || material_id >= static_cast<int>(materials.size())) {
material_id = -1;
}
auto* targetMesh = (material_id >= 0 && material_id < static_cast<int>(materials.size()))
? meshes[material_id].get()
: meshes.back().get(); // Use default mesh
uint32_t tempIndices[3];
VertexIn tempVertices[3];
for (size_t v = 0; v < fv; v++) {
tinyobj::index_t idx = shape.mesh.indices[index_offset + v];
VertexIn vertex;
if (idx.vertex_index >= 0) {
vertex.position = Vector3(
attrib.vertices[3 * idx.vertex_index + 0],
attrib.vertices[3 * idx.vertex_index + 1],
attrib.vertices[3 * idx.vertex_index + 2]
);
}
if (idx.texcoord_index >= 0) {
vertex.uv = Vector2(
attrib.texcoords[2 * idx.texcoord_index + 0],
1.0f - attrib.texcoords[2 * idx.texcoord_index + 1] // Flip V
);
}
if (idx.normal_index >= 0) {
vertex.normal = Vector3(
attrib.normals[3 * idx.normal_index + 0],
attrib.normals[3 * idx.normal_index + 1],
attrib.normals[3 * idx.normal_index + 2]
);
}
tempVertices[v] = vertex;
tempIndices[v] = static_cast<uint32_t>(targetMesh->vertices.size());
targetMesh->vertices.push_back(vertex);
}
// Push indices in the default order
targetMesh->indices.push_back(tempIndices[0]);
targetMesh->indices.push_back(tempIndices[1]);
targetMesh->indices.push_back(tempIndices[2]);
index_offset += fv;
}
}
return true;
}
} }
} }

View File

@@ -29,6 +29,7 @@ int main(int argc, char *args[]) {
const uint32_t width = 640; const uint32_t width = 640;
const uint32_t height = 480; const uint32_t height = 480;
SDL_Window *pWindow = SDL_CreateWindow( SDL_Window *pWindow = SDL_CreateWindow(
"DirectX - Bram Verhulst - 2GD11E", "DirectX - Bram Verhulst - 2GD11E",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
@@ -49,6 +50,8 @@ int main(int argc, char *args[]) {
const auto pTimer = new Timer(); const auto pTimer = new Timer();
const auto pRenderer = new Renderer(pWindow); const auto pRenderer = new Renderer(pWindow);
bool printFPS = false;
//Start loop //Start loop
pTimer->Start(); pTimer->Start();
float printTimer = 0.f; float printTimer = 0.f;
@@ -73,6 +76,7 @@ int main(int argc, char *args[]) {
} }
if(scancode == SDL_SCANCODE_F9){ if(scancode == SDL_SCANCODE_F9){
// Cycle Cull mode // Cycle Cull mode
pRenderer->CycleCullMode();
} }
if(scancode == SDL_SCANCODE_F10){ if(scancode == SDL_SCANCODE_F10){
// Toggle Uniform Clear Color // Toggle Uniform Clear Color
@@ -80,11 +84,13 @@ int main(int argc, char *args[]) {
} }
if(scancode == SDL_SCANCODE_F11){ if(scancode == SDL_SCANCODE_F11){
// toggle Print fps // toggle Print fps
printFPS = !printFPS;
} }
//Hardware //Hardware
if (scancode == SDL_SCANCODE_F3){ if (scancode == SDL_SCANCODE_F3){
// Toggle FireFX mesh // Toggle FireFX mesh
pRenderer->ToggleFireFX();
} }
if (scancode == SDL_SCANCODE_F4){ if (scancode == SDL_SCANCODE_F4){
//Toggle texture sampling states //Toggle texture sampling states
@@ -93,25 +99,21 @@ int main(int argc, char *args[]) {
//Software //Software
if(scancode == SDL_SCANCODE_F5){ if(scancode == SDL_SCANCODE_F5){
//Cycle shading mode //Cycle shading mode
pRenderer->CycleRenderingMode();
} }
if(scancode == SDL_SCANCODE_F6){ if(scancode == SDL_SCANCODE_F6){
//Toggle normal mapping //Toggle normal mapping
pRenderer->ToggleNormals();
} }
if(scancode == SDL_SCANCODE_F7){ if(scancode == SDL_SCANCODE_F7){
//Toggle Depth Buffer //Toggle Depth Buffer
pRenderer->ToggleDepthBuffer();
} }
if(scancode == SDL_SCANCODE_F8) { if(scancode == SDL_SCANCODE_F8) {
//Toggle BoundingBox //Toggle BoundingBox
pRenderer->ToggleBoundingBox();
} }
if (e.key.keysym.scancode == SDL_SCANCODE_F2) {
}
if (e.key.keysym.scancode == SDL_SCANCODE_F3) {
}
if (e.key.keysym.scancode == SDL_SCANCODE_F4) {
pRenderer->ToggleNormals();
}
break; break;
} }
default: default:
@@ -129,7 +131,7 @@ int main(int argc, char *args[]) {
//--------- Timer --------- //--------- Timer ---------
pTimer->Update(); pTimer->Update();
printTimer += pTimer->GetElapsed(); printTimer += pTimer->GetElapsed();
if (printTimer >= 1.f) { if (printTimer >= 1.f && printFPS) {
printTimer = 0.f; printTimer = 0.f;
std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl; std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl;
} }