History

Ray tests for heightfield spanners.

Andrzej Kapolka committed 12 years ago

Commit b2ac33d1 parent 75e1cf86 files · +175 −184Browse files

Showing the changes to interface/src/MetavoxelSystem.cpp (1 of 6 files). Show all

Unified · Split

interface/src/MetavoxelSystem.cpp+3−179
@@ -171,185 +171,6 @@ void MetavoxelSystem::refreshVoxelData() { · 170 unmodified lines
171171 }
172172 }
173173
174−class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor {
175−public:
176−
177− float intersectionDistance;
178−
179− RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod);
180−
181− virtual int visit(MetavoxelInfo& info, float distance);
182−};
183−
184−RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin,
185− const glm::vec3& direction, const MetavoxelLOD& lod) :
186− RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() <<
187− Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod),
188− intersectionDistance(FLT_MAX) {
189−}
190−
191−static const int EIGHT_BIT_MAXIMUM = 255;
192−static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM;
193−
194−int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
195− if (!info.isLeaf) {
196− return _order;
197− }
198− const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(
199− info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
200− if (!buffer) {
201− return STOP_RECURSION;
202− }
203− const QByteArray& contents = buffer->getHeight();
204− const uchar* src = (const uchar*)contents.constData();
205− int size = glm::sqrt((float)contents.size());
206− int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION;
207− int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize;
208− float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL;
209−
210− // find the initial location in heightfield coordinates
211− glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)unextendedSize / info.size;
212− entry.x += HeightfieldBuffer::HEIGHT_BORDER;
213− entry.z += HeightfieldBuffer::HEIGHT_BORDER;
214− glm::vec3 floors = glm::floor(entry);
215− glm::vec3 ceils = glm::ceil(entry);
216− if (floors.x == ceils.x) {
217− if (_direction.x > 0.0f) {
218− ceils.x += 1.0f;
219− } else {
220− floors.x -= 1.0f;
221− }
222− }
223− if (floors.z == ceils.z) {
224− if (_direction.z > 0.0f) {
225− ceils.z += 1.0f;
226− } else {
227− floors.z -= 1.0f;
228− }
229− }
230−
231− bool withinBounds = true;
232− float accumulatedDistance = 0.0f;
233− while (withinBounds) {
234− // find the heights at the corners of the current cell
235− int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
236− int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
237− int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest);
238− int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest);
239− float upperLeft = src[floorZ * size + floorX] * heightScale;
240− float upperRight = src[floorZ * size + ceilX] * heightScale;
241− float lowerLeft = src[ceilZ * size + floorX] * heightScale;
242− float lowerRight = src[ceilZ * size + ceilX] * heightScale;
243−
244− // find the distance to the next x coordinate
245− float xDistance = FLT_MAX;
246− if (_direction.x > 0.0f) {
247− xDistance = (ceils.x - entry.x) / _direction.x;
248− } else if (_direction.x < 0.0f) {
249− xDistance = (floors.x - entry.x) / _direction.x;
250− }
251−
252− // and the distance to the next z coordinate
253− float zDistance = FLT_MAX;
254− if (_direction.z > 0.0f) {
255− zDistance = (ceils.z - entry.z) / _direction.z;
256− } else if (_direction.z < 0.0f) {
257− zDistance = (floors.z - entry.z) / _direction.z;
258− }
259−
260− // the exit distance is the lower of those two
261− float exitDistance = qMin(xDistance, zDistance);
262− glm::vec3 exit, nextFloors = floors, nextCeils = ceils;
263− if (exitDistance == FLT_MAX) {
264− if (_direction.y > 0.0f) {
265− return SHORT_CIRCUIT; // line points upwards; no collisions possible
266− }
267− withinBounds = false; // line points downwards; check this cell only
268−
269− } else {
270− // find the exit point and the next cell, and determine whether it's still within the bounds
271− exit = entry + exitDistance * _direction;
272− withinBounds = (exit.y >= HeightfieldBuffer::HEIGHT_BORDER && exit.y <= highest);
273− if (exitDistance == xDistance) {
274− if (_direction.x > 0.0f) {
275− nextFloors.x += 1.0f;
276− withinBounds &= (nextCeils.x += 1.0f) <= highest;
277− } else {
278− withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER;
279− nextCeils.x -= 1.0f;
280− }
281− }
282− if (exitDistance == zDistance) {
283− if (_direction.z > 0.0f) {
284− nextFloors.z += 1.0f;
285− withinBounds &= (nextCeils.z += 1.0f) <= highest;
286− } else {
287− withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER;
288− nextCeils.z -= 1.0f;
289− }
290− }
291− // check the vertical range of the ray against the ranges of the cell heights
292− if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) ||
293− qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) {
294− entry = exit;
295− floors = nextFloors;
296− ceils = nextCeils;
297− accumulatedDistance += exitDistance;
298− continue;
299− }
300− }
301− // having passed the bounds check, we must check against the planes
302− glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z);
303−
304− // first check the triangle including the Z+ segment
305− glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft);
306− float lowerProduct = glm::dot(lowerNormal, _direction);
307− if (lowerProduct < 0.0f) {
308− float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct;
309− glm::vec3 intersection = relativeEntry + planeDistance * _direction;
310− if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
311− intersection.z >= intersection.x) {
312− intersectionDistance = qMin(intersectionDistance, distance +
313− (accumulatedDistance + planeDistance) * (info.size / unextendedSize));
314− return SHORT_CIRCUIT;
315− }
316− }
317−
318− // then the one with the X+ segment
319− glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight);
320− float upperProduct = glm::dot(upperNormal, _direction);
321− if (upperProduct < 0.0f) {
322− float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct;
323− glm::vec3 intersection = relativeEntry + planeDistance * _direction;
324− if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f &&
325− intersection.x >= intersection.z) {
326− intersectionDistance = qMin(intersectionDistance, distance +
327− (accumulatedDistance + planeDistance) * (info.size / unextendedSize));
328− return SHORT_CIRCUIT;
329− }
330− }
331−
332− // no joy; continue on our way
333− entry = exit;
334− floors = nextFloors;
335− ceils = nextCeils;
336− accumulatedDistance += exitDistance;
337− }
338−
339− return STOP_RECURSION;
340−}
341−
342−bool MetavoxelSystem::findFirstRayHeightfieldIntersection(const glm::vec3& origin,
343− const glm::vec3& direction, float& distance) {
344− RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD());
345− guideToAugmented(visitor);
346− if (visitor.intersectionDistance == FLT_MAX) {
347− return false;
348− }
349− distance = visitor.intersectionDistance;
350− return true;
351−}
352−
353174 class RayVoxelIntersectionVisitor : public RayIntersectionVisitor {
354175 public:
355176
@@ -917,6 +738,9 @@ public: · 561 unmodified lines
917738 const int SPLAT_COUNT = 4;
918739 const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 };
919740
741+static const int EIGHT_BIT_MAXIMUM = 255;
742+static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM;
743+
920744 void HeightfieldBuffer::render(bool cursor) {
921745 // initialize textures, etc. on first render
922746 if (_heightTextureID == 0) {