-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprepareModel.cpp
More file actions
230 lines (192 loc) · 9.39 KB
/
prepareModel.cpp
File metadata and controls
230 lines (192 loc) · 9.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*!
* @file
* @brief This file contains functions for model rendering
*
* @author Tomáš Milet, imilet@fit.vutbr.cz
*/
#include <studentSolution/prepareModel.hpp>
#include <studentSolution/gpu.hpp>
#include <solutionInterface/uniformLocations.hpp>
#include <studentSolution/shaderFunctions.hpp>
#include <iostream>
static uint32_t drawCallCounter = 0;
void processNode(GPUMemory& mem, CommandBuffer& commandBuffer, Node const& node,
Model const& model, glm::mat4 const& parentMatrix) {
// Combine current node's transformation with parent
glm::mat4 currentMatrix = parentMatrix * node.modelMatrix;
// If this node has a mesh, create draw commands
if (node.mesh >= 0 && node.mesh < (int32_t)model.nofMeshes) {
auto const& mesh = model.meshes[node.mesh];
// Create vertex array for this mesh
VertexArray vao = {};
// Set up indexing if present
if (mesh.indexBufferID >= 0) {
vao.indexBufferID = mesh.indexBufferID;
vao.indexOffset = mesh.indexOffset;
vao.indexType = mesh.indexType;
} else {
vao.indexBufferID = -1;
}
// Set up vertex attributes
if (mesh.position.type != AttribType::EMPTY) {
vao.vertexAttrib[0] = mesh.position;
}
if (mesh.normal.type != AttribType::EMPTY) {
vao.vertexAttrib[1] = mesh.normal;
}
if (mesh.texCoord.type != AttribType::EMPTY) {
vao.vertexAttrib[2] = mesh.texCoord;
}
// Store vertex array in GPU memory
mem.vertexArrays[drawCallCounter] = vao;
// Calculate matrices for uniforms
glm::mat4 modelMatrix = currentMatrix;
glm::mat4 invTransposeModelMatrix = glm::transpose(glm::inverse(modelMatrix));
// Set up uniforms for this draw call
uint32_t modelMatrixLocation = getUniformLocation(drawCallCounter, MODEL_MATRIX);
uint32_t invTransposeLocation = getUniformLocation(drawCallCounter, INVERSE_TRANSPOSE_MODEL_MATRIX);
uint32_t diffuseColorLocation = getUniformLocation(drawCallCounter, DIFFUSE_COLOR);
uint32_t textureIdLocation = getUniformLocation(drawCallCounter, TEXTURE_ID);
uint32_t doubleSidedLocation = getUniformLocation(drawCallCounter, DOUBLE_SIDED);
mem.uniforms[modelMatrixLocation].m4 = modelMatrix;
mem.uniforms[invTransposeLocation].m4 = invTransposeModelMatrix;
mem.uniforms[diffuseColorLocation].v4 = mesh.diffuseColor;
mem.uniforms[textureIdLocation].i1 = mesh.diffuseTexture;
mem.uniforms[doubleSidedLocation].v1 = mesh.doubleSided ? 1.0f : 0.0f;
// Add commands to command buffer
pushBindVertexArrayCommand(commandBuffer, drawCallCounter);
pushSetBackfaceCullingCommand(commandBuffer, !mesh.doubleSided);
pushDrawCommand(commandBuffer, mesh.nofIndices);
drawCallCounter++;
}
// Recursively process children
for (size_t i = 0; i < node.nofChildren; ++i) {
processNode(mem, commandBuffer, node.children[i], model, currentMatrix);
}
}
/**
* @brief This function prepares model into memory and creates command buffer
*
* @param mem gpu memory
* @param commandBuffer command buffer
* @param model model structure
*/
void student_prepareModel(GPUMemory&mem,CommandBuffer&commandBuffer,Model const&model){
drawCallCounter = 0;
// Copy buffers to GPU memory
for (size_t i = 0; i < model.nofBuffers; ++i) {
mem.buffers[i] = model.buffers[i];
}
// Copy textures to GPU memory
for (size_t i = 0; i < model.nofTextures; ++i) {
mem.textures[i] = model.textures[i];
}
// Process all root nodes with identity matrix
glm::mat4 identityMatrix = glm::mat4(1.0f);
for (size_t i = 0; i < model.nofRoots; ++i) {
processNode(mem, commandBuffer, model.roots[i], model, identityMatrix);
}
}
/**
* @brief This function represents vertex shader of texture rendering method.
*
* @param outVertex output vertex
* @param inVertex input vertex
* @param si shader interface
*/
void student_drawModel_vertexShader(OutVertex&outVertex,InVertex const&inVertex,ShaderInterface const&si){
// Get input attributes
glm::vec3 position = inVertex.attributes[0].v3; // position in model space
glm::vec3 normal = inVertex.attributes[1].v3; // normal in model space
glm::vec2 texCoord = inVertex.attributes[2].v2; // texture coordinates
// Get transformation matrices from uniforms
glm::mat4 projectionViewMatrix = si.uniforms[getUniformLocation(si.gl_DrawID, PROJECTION_VIEW_MATRIX)].m4;
glm::mat4 lightProjectionViewMatrix = si.uniforms[getUniformLocation(si.gl_DrawID, USE_SHADOW_MAP_MATRIX)].m4;
glm::mat4 modelMatrix = si.uniforms[getUniformLocation(si.gl_DrawID, MODEL_MATRIX)].m4;
glm::mat4 invTransposeModelMatrix = si.uniforms[getUniformLocation(si.gl_DrawID, INVERSE_TRANSPOSE_MODEL_MATRIX)].m4;
// Transform position to world space
glm::vec4 worldPosition = modelMatrix * glm::vec4(position, 1.0f);
// Transform normal to world space
glm::vec4 worldNormal = invTransposeModelMatrix * glm::vec4(normal, 0.0f);
// Set output attributes
outVertex.attributes[0].v3 = glm::vec3(worldPosition); // world space position
outVertex.attributes[1].v3 = glm::vec3(worldNormal); // world space normal
outVertex.attributes[2].v2 = texCoord; // texture coordinates
outVertex.attributes[3].v4 = lightProjectionViewMatrix * worldPosition; // light space position
// Transform to clip space for rasterization
outVertex.gl_Position = projectionViewMatrix * worldPosition;
}
/**
* @brief This functionrepresents fragment shader of texture rendering method.
*
* @param outFragment output fragment
* @param inFragment input fragment
* @param si shader interface
*/
void student_drawModel_fragmentShader(OutFragment&outFragment,InFragment const&inFragment,ShaderInterface const&si){
// Get fragment attributes
glm::vec3 worldPosition = inFragment.attributes[0].v3;
glm::vec3 worldNormal = inFragment.attributes[1].v3;
glm::vec2 texCoord = inFragment.attributes[2].v2;
glm::vec4 lightSpacePosition = inFragment.attributes[3].v4;
// Get uniforms
glm::vec3 lightPosition = si.uniforms[getUniformLocation(si.gl_DrawID, LIGHT_POSITION)].v3;
glm::vec3 cameraPosition = si.uniforms[getUniformLocation(si.gl_DrawID, CAMERA_POSITION)].v3;
int32_t shadowMapId = si.uniforms[getUniformLocation(si.gl_DrawID, SHADOWMAP_ID)].i1;
glm::vec3 ambientLightColor = si.uniforms[getUniformLocation(si.gl_DrawID, AMBIENT_LIGHT_COLOR)].v3;
glm::vec3 lightColor = si.uniforms[getUniformLocation(si.gl_DrawID, LIGHT_COLOR)].v3;
glm::vec4 diffuseColor = si.uniforms[getUniformLocation(si.gl_DrawID, DIFFUSE_COLOR)].v4;
int32_t textureId = si.uniforms[getUniformLocation(si.gl_DrawID, TEXTURE_ID)].i1;
float doubleSided = si.uniforms[getUniformLocation(si.gl_DrawID, DOUBLE_SIDED)].v1;
// Normalize normal
glm::vec3 normal = glm::normalize(worldNormal);
// Handle double-sided surfaces
if (doubleSided > 0.0f) {
glm::vec3 viewDirection = glm::normalize(cameraPosition - worldPosition);
if (glm::dot(normal, viewDirection) < 0.0f) {
normal = -normal;
}
}
// Get material diffuse color
glm::vec3 materialColor;
if (textureId >= 0) {
// Use texture
glm::vec4 textureColor = student_read_texture(si.textures[textureId], texCoord);
materialColor = glm::vec3(textureColor);
} else {
// Use uniform diffuse color
materialColor = glm::vec3(diffuseColor);
}
// Calculate lighting direction
glm::vec3 lightDirection = glm::normalize(lightPosition - worldPosition);
// Lambert diffuse lighting
float diffuseFactor = std::max(0.0f, glm::dot(normal, lightDirection));
// Shadow mapping
float shadowFactor = 1.0f;
if (shadowMapId >= 0) {
// Perspective divide for light space position
glm::vec3 projCoords = glm::vec3(lightSpacePosition) / lightSpacePosition.w;
// Transform from [-1,1] to [0,1] range (assuming bias matrix is already applied)
// If bias matrix is not applied, uncomment the following lines:
// projCoords = projCoords * 0.5f + 0.5f;
// Check if fragment is in shadow map bounds
if (projCoords.x >= 0.0f && projCoords.x <= 1.0f &&
projCoords.y >= 0.0f && projCoords.y <= 1.0f &&
projCoords.z >= 0.0f && projCoords.z <= 1.0f) {
// Sample shadow map
float shadowMapDepth = student_read_textureClamp(si.textures[shadowMapId], glm::vec2(projCoords.x, projCoords.y)).r;
// Compare depths with bias to prevent shadow acne
float bias = 0.0001f;
if (projCoords.z > shadowMapDepth + bias) {
shadowFactor = 0.5f; // In shadow - reduce lighting by 50%
}
}
}
// Combine lighting
glm::vec3 ambient = ambientLightColor * materialColor;
glm::vec3 diffuse = lightColor * materialColor * diffuseFactor * shadowFactor;
glm::vec3 finalColor = ambient + diffuse;
// Set output
outFragment.gl_FragColor = glm::vec4(finalColor, diffuseColor.a);
outFragment.discard = false;
}