-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mesh.cpp
211 lines (175 loc) · 4.73 KB
/
Mesh.cpp
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
#include "Mesh.h"
#include <QGLBuffer>
#include "Renderer.h"
Mesh::Mesh(Node *parent) : Node(parent)
{
_GLVertices = new QGLBuffer(QGLBuffer::VertexBuffer);
_GLFaces = new QGLBuffer(QGLBuffer::IndexBuffer);
_material = new Material(this);
setType("Mesh");
}
Mesh::~Mesh()
{
delete _GLVertices;
delete _GLFaces;
}
void Mesh::init()
{
Node::init();
_GLVertices->create();
_GLFaces->create();
}
void Mesh::draw()
{
if (visible())
renderer->draw(this);
Node::draw();
}
void Mesh::setVertices(const QVector<float>& vertices)
{
_vertices = vertices;
_updateVerticesNormalsBuffer();
}
const QVector<float> Mesh::vertices() const
{
return _vertices;
}
float Mesh::vertex(int i) const
{
return _vertices.at(i);
}
void Mesh::setNormals(const QVector<float> &normals)
{
_normals = normals;
_updateVerticesNormalsBuffer();
}
const QVector<float> Mesh::normals() const
{
return _normals;
}
float Mesh::normal(int i) const
{
return _normals[i];
}
void Mesh::setTexCoords(const QVector<float> &texCoords)
{
_texCoords = texCoords;
_updateVerticesNormalsBuffer();
}
const QVector<float> Mesh::texCoords() const
{
return _texCoords;
}
float Mesh::texCoord(int i) const
{
return _texCoords[i];
}
QGLBuffer* Mesh::GLVertices() const
{
return _GLVertices;
}
void Mesh::setFaces(const QVector<int>& faces)
{
_GLFaces->bind();
_GLFaces->allocate(faces.data(), faces.size() * sizeof(int));
_faces = faces;
}
const QVector<int> Mesh::faces() const
{
return _faces;
}
int Mesh::face(int i) const
{
return _faces[i];
}
QGLBuffer* Mesh::GLFaces() const
{
return _GLFaces;
}
Material *Mesh::material() const
{
return _material;
}
void Mesh::setMaterial(Material *material)
{
_material = material;
}
float Mesh::intersects(const QVector3D &pos, const QVector3D &direction) const
{
float res = -1;
QMatrix4x4 inv = world().inverted();
QVector3D invPos = inv.map(pos);
inv.setColumn(3, QVector4D(0, 0, 0, 1));
QVector3D invDir = inv.map(direction);
for (int i = 0; i < _faces.size(); ++i) {
int p0Idx = _faces[i] * 3,
p1Idx = _faces[++i] * 3,
p2Idx = _faces[++i] * 3;
QVector3D p0(_vertices[p0Idx], _vertices[p0Idx + 1], _vertices[p0Idx + 2]),
p1(_vertices[p1Idx], _vertices[p1Idx + 1], _vertices[p1Idx + 2]),
p2(_vertices[p2Idx], _vertices[p2Idx + 1], _vertices[p2Idx + 2]);
float current = _triangleIntersection(invPos, invDir, p0, p1, p2);
if (current > 0 && (res == -1 || current < res))
res = current;
}
return res;
}
float Mesh::_triangleIntersection(const QVector3D &pos, const QVector3D &direction, const QVector3D &p0, const QVector3D &p1, const QVector3D &p2) const
{
float u, v, t;
QVector3D edge1, edge2, tvec, pvec, qvec;
float det, inv_det;
// find vectors for two edges sharing vert0
edge1 = p1 - p0;
edge2 = p2 - p0;
// Begin calculating determinant - also used to calculate U parameter
pvec = QVector3D::crossProduct(direction, edge2);
// If determinant is near zero, ray lies in plane of triangle
det = QVector3D::dotProduct(edge1, pvec);
if (det > -Renderer::Epsilon && det < Renderer::Epsilon)
return -1.0f;
inv_det = 1.0 / det;
// Calculate distance from point 0 to ray origin
tvec = pos - p0;
// Calculate U parameter and test bounds
u = QVector3D::dotProduct(tvec, pvec) * inv_det;
if (u < 0.0f || u > 1.0f)
return -1.0f;
// Prepare to test V parameter
qvec = QVector3D::crossProduct(tvec, edge1);
// Calculate V parameter and test bounds
v = QVector3D::dotProduct(direction, qvec) * inv_det;
if (v < 0.0f || u + v > 1.0f)
return -1.0f;
// Calculate t, ray intersects triangle
t = QVector3D::dotProduct(edge2, qvec) * inv_det;
return t;
}
void Mesh::_updateVerticesNormalsBuffer()
{
_buffer.resize(8 * (_vertices.size() / 3));
int vId = 0, nId = 0, tId = 0;
for (int i = 0; i < _buffer.size();) {
_buffer[i++] = _vertices[vId++];
_buffer[i++] = _vertices[vId++];
_buffer[i++] = _vertices[vId++];
if (nId + 2 < _normals.size()) {
_buffer[i++] = _normals[nId++];
_buffer[i++] = _normals[nId++];
_buffer[i++] = _normals[nId++];
} else {
_buffer[i++] = 0;
_buffer[i++] = 0;
_buffer[i++] = 0;
}
if (tId + 1 < _texCoords.size()) {
_buffer[i++] = _texCoords[tId++];
_buffer[i++] = _texCoords[tId++];
} else {
_buffer[i++] = 0;
_buffer[i++] = 0;
}
}
_GLVertices->bind();
_GLVertices->allocate(_buffer.data(), _buffer.size() * sizeof(float));
}