/src/ogre/OgreMain/src/OgreDefaultDebugDrawer.cpp
Line | Count | Source |
1 | | // This file is part of the OGRE project. |
2 | | // It is subject to the license terms in the LICENSE file found in the top-level directory |
3 | | // of this distribution and at https://www.ogre3d.org/licensing. |
4 | | |
5 | | #include "OgreMatrix3.h" |
6 | | #include "OgreStableHeaders.h" |
7 | | #include "OgreDefaultDebugDrawer.h" |
8 | | #include "OgreTagPoint.h" |
9 | | #include "OgreViewport.h" |
10 | | |
11 | | namespace Ogre |
12 | | { |
13 | | |
14 | 0 | DefaultDebugDrawer::DefaultDebugDrawer() : mCameraNode(nullptr), mLines(""), mAxes(""), mDrawType(0), mStatic(false), mBoneAxesSize(1.0f) {} |
15 | | |
16 | | void DefaultDebugDrawer::preFindVisibleObjects(SceneManager* source, |
17 | | SceneManager::IlluminationRenderStage irs, Viewport* v) |
18 | 0 | { |
19 | 0 | mDrawType = 0; |
20 | |
|
21 | 0 | if (source->getDisplaySceneNodes()) |
22 | 0 | mDrawType |= DT_AXES; |
23 | 0 | if (source->getShowBoundingBoxes()) |
24 | 0 | mDrawType |= DT_WIREBOX; |
25 | |
|
26 | 0 | mCameraNode = v->getCamera()->getParentSceneNode(); |
27 | 0 | } |
28 | | void DefaultDebugDrawer::beginLines() |
29 | 0 | { |
30 | 0 | if (mLines.getSections().empty()) |
31 | 0 | { |
32 | 0 | const char* matName = "Ogre/Debug/LinesMat"; |
33 | 0 | auto mat = MaterialManager::getSingleton().getByName(matName, RGN_INTERNAL); |
34 | 0 | if (!mat) |
35 | 0 | { |
36 | 0 | mat = MaterialManager::getSingleton().create(matName, RGN_INTERNAL); |
37 | 0 | Pass* p = mat->getTechnique(0)->getPass(0); |
38 | 0 | p->setLightingEnabled(false); |
39 | 0 | p->setVertexColourTracking(TVC_AMBIENT); |
40 | 0 | } |
41 | 0 | mLines.setBufferUsage(HBU_CPU_TO_GPU); |
42 | 0 | mLines.begin(mat, RenderOperation::OT_LINE_LIST); |
43 | 0 | } |
44 | 0 | else if (mLines.getCurrentVertexCount() == 0) |
45 | 0 | mLines.beginUpdate(0); |
46 | 0 | } |
47 | | void DefaultDebugDrawer::beginAxes() |
48 | 0 | { |
49 | 0 | if (mAxes.getSections().empty()) |
50 | 0 | { |
51 | 0 | const char* matName = "Ogre/Debug/AxesMat"; |
52 | 0 | auto mat = MaterialManager::getSingleton().getByName(matName, RGN_INTERNAL); |
53 | 0 | if (!mat) |
54 | 0 | { |
55 | 0 | mat = MaterialManager::getSingleton().create(matName, RGN_INTERNAL); |
56 | 0 | Pass* p = mat->getTechnique(0)->getPass(0); |
57 | 0 | p->setLightingEnabled(false); |
58 | 0 | p->setPolygonModeOverrideable(false); |
59 | 0 | p->setVertexColourTracking(TVC_AMBIENT); |
60 | 0 | p->setSceneBlending(SBT_TRANSPARENT_ALPHA); |
61 | 0 | p->setCullingMode(CULL_NONE); |
62 | 0 | p->setDepthWriteEnabled(false); |
63 | 0 | p->setDepthCheckEnabled(false); |
64 | 0 | } |
65 | |
|
66 | 0 | mAxes.setBufferUsage(HBU_CPU_TO_GPU); |
67 | 0 | mAxes.begin(mat); |
68 | 0 | } |
69 | 0 | else if (mAxes.getCurrentVertexCount() == 0) |
70 | 0 | mAxes.beginUpdate(0); |
71 | 0 | } |
72 | | void DefaultDebugDrawer::drawWireBox(const AxisAlignedBox& aabb, const ColourValue& colour) |
73 | 0 | { |
74 | 0 | beginLines(); |
75 | |
|
76 | 0 | int base = mLines.getCurrentVertexCount(); |
77 | 0 | for (const auto& corner : aabb.getAllCorners()) |
78 | 0 | { |
79 | 0 | mLines.position(corner); |
80 | 0 | mLines.colour(colour); |
81 | 0 | } |
82 | | // see AxisAlignedBox::getAllCorners |
83 | 0 | int idx[] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 6, 1, 5, 2, 4, 3, 7}; |
84 | 0 | for (int i : idx) |
85 | 0 | mLines.index(base + i); |
86 | 0 | } |
87 | | void DefaultDebugDrawer::drawFrustum(const Frustum* frust) |
88 | 0 | { |
89 | 0 | beginLines(); |
90 | |
|
91 | 0 | int base = mLines.getCurrentVertexCount(); |
92 | 0 | for (const auto& corner : frust->getWorldSpaceCorners()) |
93 | 0 | { |
94 | 0 | mLines.position(corner); |
95 | 0 | mLines.colour(frust->getDebugColour()); |
96 | 0 | } |
97 | | // see ConvexBody::define |
98 | 0 | int idx[] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 2, 6, 1, 5, 0, 4, 3, 7}; |
99 | 0 | for (int i : idx) |
100 | 0 | mLines.index(base + i); |
101 | 0 | } |
102 | | void DefaultDebugDrawer::drawSphere(const Sphere & sphere) |
103 | 0 | { |
104 | 0 | if (!mCameraNode) |
105 | 0 | { |
106 | 0 | return; |
107 | 0 | } |
108 | | |
109 | 0 | const Vector3 & center = sphere.getCenter(); |
110 | 0 | float radius = sphere.getRadius(); |
111 | |
|
112 | 0 | const Vector3 & camPos = mCameraNode->_getDerivedPosition(); |
113 | 0 | Vector3 axis = camPos - center; |
114 | 0 | float distance = axis.normalise(); |
115 | | |
116 | | // Unlike std's, Ogre's ACos tolerates domain errors |
117 | 0 | const Radian facetAngle = 2 * Math::ACos(1.0f - (0.001f * distance / radius)); |
118 | 0 | int facetCount = (int)std::ceil(Math::TWO_PI / facetAngle.valueRadians()); |
119 | | |
120 | | // TODO: figure out how this works with non-perspective projection and custom matrices |
121 | | // TODO: only draw visible arcs (very big or close spheres could have very many facets) |
122 | | |
123 | | // Calculate an arbitrary radial orthogonal to the axis |
124 | 0 | Vector3 notParallel = mCameraNode->_getDerivedOrientation().xAxis(); |
125 | 0 | Vector3 radial = radius * notParallel.crossProduct(axis).normalisedCopy(); |
126 | |
|
127 | 0 | beginLines(); |
128 | 0 | int base = mLines.getCurrentVertexCount(); |
129 | |
|
130 | 0 | for (int i = 0; i < facetCount; ++i) |
131 | 0 | { |
132 | 0 | Radian angle(Math::TWO_PI * i / (float)facetCount); |
133 | 0 | mLines.position(center + Quaternion(angle , axis) * radial); |
134 | 0 | mLines.colour(ColourValue::White); |
135 | 0 | mLines.index(base + i); |
136 | 0 | mLines.index(base + ((i + 1) % facetCount)); |
137 | 0 | } |
138 | 0 | } |
139 | | void DefaultDebugDrawer::drawAxis2D(const Affine3& pose, const Matrix3& rot, float scale, const ColourValue& col) |
140 | 0 | { |
141 | | /* each made up of 2 of these (base plane = XY) |
142 | | * .------------|\ |
143 | | * '------------|/ |
144 | | */ |
145 | 0 | static Vector3 basepos[7] = |
146 | 0 | { |
147 | | // stalk |
148 | 0 | Vector3(0, 0.05, 0), |
149 | 0 | Vector3(0, -0.05, 0), |
150 | 0 | Vector3(0.7, -0.05, 0), |
151 | 0 | Vector3(0.7, 0.05, 0), |
152 | | // head |
153 | 0 | Vector3(0.7, -0.15, 0), |
154 | 0 | Vector3(1, 0, 0), |
155 | 0 | Vector3(0.7, 0.15, 0) |
156 | 0 | }; |
157 | |
|
158 | 0 | uint32 base = mAxes.getCurrentVertexCount(); |
159 | | // vertices |
160 | 0 | for (const auto& p : basepos) |
161 | 0 | { |
162 | 0 | mAxes.position(pose * (rot * p * scale)); |
163 | 0 | mAxes.colour(col); |
164 | 0 | } |
165 | | |
166 | | // indices |
167 | 0 | mAxes.quad(base + 0, base + 1, base + 2, base + 3); |
168 | 0 | mAxes.triangle(base + 4, base + 5, base + 6); |
169 | 0 | } |
170 | | void DefaultDebugDrawer::drawAxes(const Affine3& pose, float size) |
171 | 0 | { |
172 | 0 | beginAxes(); |
173 | |
|
174 | 0 | ColourValue col[3] = {ColourValue(1, 0, 0, 0.8), ColourValue(0, 1, 0, 0.8), ColourValue(0, 0, 1, 0.8)}; |
175 | |
|
176 | 0 | Matrix3 rot[6]; |
177 | | |
178 | | // x-axis |
179 | 0 | rot[0] = Matrix3::IDENTITY; |
180 | 0 | rot[1].FromAxes(Vector3::UNIT_X, Vector3::NEGATIVE_UNIT_Z, Vector3::UNIT_Y); |
181 | | // y-axis |
182 | 0 | rot[2].FromAxes(Vector3::UNIT_Y, Vector3::NEGATIVE_UNIT_X, Vector3::UNIT_Z); |
183 | 0 | rot[3].FromAxes(Vector3::UNIT_Y, Vector3::UNIT_Z, Vector3::UNIT_X); |
184 | | // z-axis |
185 | 0 | rot[4].FromAxes(Vector3::UNIT_Z, Vector3::UNIT_Y, Vector3::NEGATIVE_UNIT_X); |
186 | 0 | rot[5].FromAxes(Vector3::UNIT_Z, Vector3::UNIT_X, Vector3::UNIT_Y); |
187 | | |
188 | | // 6 arrows |
189 | 0 | for (size_t i = 0; i < 6; ++i) |
190 | 0 | { |
191 | 0 | drawAxis2D(pose, rot[i], size, col[i / 2]); |
192 | 0 | } |
193 | 0 | } |
194 | | void DefaultDebugDrawer::setBoneAxesSize(float size) |
195 | 0 | { |
196 | 0 | mBoneAxesSize = size; |
197 | 0 | } |
198 | | void DefaultDebugDrawer::drawBone(const Node* node, const Affine3& transform) |
199 | 0 | { |
200 | 0 | beginAxes(); |
201 | |
|
202 | 0 | ColourValue col(0.5, 0, 1, 0.9); |
203 | 0 | Affine3 pose = transform * node->_getFullTransform(); |
204 | |
|
205 | 0 | Matrix3 rot[2]; |
206 | | // x-axis |
207 | 0 | rot[0] = Matrix3::IDENTITY; |
208 | 0 | rot[1].FromAxes(Vector3::UNIT_X, Vector3::NEGATIVE_UNIT_Z, Vector3::UNIT_Y); |
209 | |
|
210 | 0 | for(const auto* child : node->getChildren()) |
211 | 0 | { |
212 | 0 | if(dynamic_cast<const TagPoint*>(child)) |
213 | 0 | continue; |
214 | | |
215 | 0 | float size = child->getPosition().length(); // we can assume relative to parent position |
216 | |
|
217 | 0 | Matrix3 crot; |
218 | 0 | Vector3::UNIT_X.getRotationTo(child->getPosition()).ToRotationMatrix(crot); |
219 | |
|
220 | 0 | for (const auto& r : rot) |
221 | 0 | { |
222 | 0 | drawAxis2D(pose, crot * r, size, col); |
223 | 0 | } |
224 | 0 | } |
225 | |
|
226 | 0 | if(node->getChildren().empty()) |
227 | 0 | { |
228 | 0 | Matrix3 crot; |
229 | 0 | Vector3::UNIT_X.getRotationTo(node->getPosition()).ToRotationMatrix(crot); |
230 | | // draw the axes of the node itself |
231 | 0 | for (const auto& r : rot) |
232 | 0 | { |
233 | 0 | drawAxis2D(pose, crot * r, mBoneAxesSize, col); |
234 | 0 | } |
235 | 0 | } |
236 | 0 | } |
237 | | void DefaultDebugDrawer::drawSceneNode(const SceneNode* node) |
238 | 0 | { |
239 | | // skip drawing root scene node as it contains the camera frustum |
240 | 0 | if(!node->getParent()) |
241 | 0 | return; |
242 | | |
243 | 0 | const auto& aabb = node->_getWorldAABB(); |
244 | | //Skip all bounding boxes that are infinite. |
245 | 0 | if (aabb.isInfinite()) { |
246 | 0 | return; |
247 | 0 | } |
248 | 0 | if (node->getDisplaySceneNode() || (mDrawType & DT_AXES)) |
249 | 0 | { |
250 | | // remove scale here as it will be in full transform below too |
251 | 0 | Vector3f hs(aabb.getHalfSize() / node->_getDerivedScale()); |
252 | 0 | float sz = std::min(hs[0], hs[1]); |
253 | 0 | sz = std::min(sz, hs[2]); |
254 | 0 | sz = std::max(sz, 1.0f); |
255 | 0 | drawAxes(node->_getFullTransform(), sz); |
256 | 0 | } |
257 | |
|
258 | 0 | if (node->getShowBoundingBox() || (mDrawType & DT_WIREBOX)) |
259 | 0 | { |
260 | 0 | drawWireBox(aabb); |
261 | 0 | } |
262 | 0 | } |
263 | | void DefaultDebugDrawer::postFindVisibleObjects(SceneManager* source, |
264 | | SceneManager::IlluminationRenderStage irs, Viewport* v) |
265 | 0 | { |
266 | 0 | auto queue = source->getRenderQueue(); |
267 | 0 | if (mLines.getCurrentVertexCount()) |
268 | 0 | { |
269 | 0 | mLines.end(); |
270 | 0 | mLines._updateRenderQueue(queue); |
271 | 0 | } |
272 | 0 | if (mAxes.getCurrentVertexCount()) |
273 | 0 | { |
274 | 0 | mAxes.end(); |
275 | 0 | mAxes._updateRenderQueue(queue); |
276 | 0 | } |
277 | |
|
278 | 0 | if (mStatic) |
279 | 0 | { |
280 | 0 | mLines._updateRenderQueue(queue); |
281 | 0 | mAxes._updateRenderQueue(queue); |
282 | 0 | } |
283 | 0 | } |
284 | | |
285 | | } /* namespace Ogre */ |