org.joml.FrustumRayBuilder Maven / Gradle / Ivy
/*
* The MIT License
*
* Copyright (c) 2015-2020 Kai Burjack
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.joml;
/**
* Provides methods to compute rays through an arbitrary perspective transformation defined by a {@link Matrix4fc}.
*
* This can be used to compute the eye-rays in simple software-based raycasting/raytracing.
*
* To obtain the origin of the rays call {@link #origin(Vector3f)}.
* Then to compute the directions of subsequent rays use {@link #dir(float, float, Vector3f)}.
*
* @author Kai Burjack
*/
public class FrustumRayBuilder {
private float nxnyX, nxnyY, nxnyZ;
private float pxnyX, pxnyY, pxnyZ;
private float pxpyX, pxpyY, pxpyZ;
private float nxpyX, nxpyY, nxpyZ;
private float cx, cy, cz;
/**
* Create a new {@link FrustumRayBuilder} with an undefined frustum.
*
* Before obtaining ray directions, make sure to define the frustum using {@link #set(Matrix4fc)}.
*/
public FrustumRayBuilder() {
}
/**
* Create a new {@link FrustumRayBuilder} from the given {@link Matrix4fc matrix} by extracing the matrix's frustum.
*
* @param m
* the {@link Matrix4fc} to create the frustum from
*/
public FrustumRayBuilder(Matrix4fc m) {
set(m);
}
/**
* Update the stored frustum corner rays and origin of this
{@link FrustumRayBuilder} with the given {@link Matrix4fc matrix}.
*
* Reference:
* Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
*
* Reference: http://geomalgorithms.com
*
* @param m
* the {@link Matrix4fc matrix} to update the frustum corner rays and origin with
* @return this
*/
public FrustumRayBuilder set(Matrix4fc m) {
float nxX = m.m03() + m.m00(), nxY = m.m13() + m.m10(), nxZ = m.m23() + m.m20(), d1 = m.m33() + m.m30();
float pxX = m.m03() - m.m00(), pxY = m.m13() - m.m10(), pxZ = m.m23() - m.m20(), d2 = m.m33() - m.m30();
float nyX = m.m03() + m.m01(), nyY = m.m13() + m.m11(), nyZ = m.m23() + m.m21();
float pyX = m.m03() - m.m01(), pyY = m.m13() - m.m11(), pyZ = m.m23() - m.m21(), d3 = m.m33() - m.m31();
// bottom left
nxnyX = nyY * nxZ - nyZ * nxY;
nxnyY = nyZ * nxX - nyX * nxZ;
nxnyZ = nyX * nxY - nyY * nxX;
// bottom right
pxnyX = pxY * nyZ - pxZ * nyY;
pxnyY = pxZ * nyX - pxX * nyZ;
pxnyZ = pxX * nyY - pxY * nyX;
// top left
nxpyX = nxY * pyZ - nxZ * pyY;
nxpyY = nxZ * pyX - nxX * pyZ;
nxpyZ = nxX * pyY - nxY * pyX;
// top right
pxpyX = pyY * pxZ - pyZ * pxY;
pxpyY = pyZ * pxX - pyX * pxZ;
pxpyZ = pyX * pxY - pyY * pxX;
// compute origin
float pxnxX, pxnxY, pxnxZ;
pxnxX = pxY * nxZ - pxZ * nxY;
pxnxY = pxZ * nxX - pxX * nxZ;
pxnxZ = pxX * nxY - pxY * nxX;
float invDot = 1.0f / (nxX * pxpyX + nxY * pxpyY + nxZ * pxpyZ);
cx = (-pxpyX * d1 - nxpyX * d2 - pxnxX * d3) * invDot;
cy = (-pxpyY * d1 - nxpyY * d2 - pxnxY * d3) * invDot;
cz = (-pxpyZ * d1 - nxpyZ * d2 - pxnxZ * d3) * invDot;
return this;
}
/**
* Store the eye/origin of the perspective frustum in the given origin
.
*
* @param origin
* will hold the perspective origin
* @return the origin
vector
*/
public Vector3fc origin(Vector3f origin) {
origin.x = cx;
origin.y = cy;
origin.z = cz;
return origin;
}
/**
* Obtain the normalized direction of a ray starting at the center of the coordinate system and going
* through the near frustum plane.
*
* The parameters x
and y
are used to interpolate the generated ray direction
* from the bottom-left to the top-right frustum corners.
*
* @param x
* the interpolation factor along the left-to-right frustum planes, within [0..1]
* @param y
* the interpolation factor along the bottom-to-top frustum planes, within [0..1]
* @param dir
* will hold the normalized ray direction
* @return the dir
vector
*/
public Vector3fc dir(float x, float y, Vector3f dir) {
float y1x = nxnyX + (nxpyX - nxnyX) * y;
float y1y = nxnyY + (nxpyY - nxnyY) * y;
float y1z = nxnyZ + (nxpyZ - nxnyZ) * y;
float y2x = pxnyX + (pxpyX - pxnyX) * y;
float y2y = pxnyY + (pxpyY - pxnyY) * y;
float y2z = pxnyZ + (pxpyZ - pxnyZ) * y;
float dx = y1x + (y2x - y1x) * x;
float dy = y1y + (y2y - y1y) * x;
float dz = y1z + (y2z - y1z) * x;
// normalize the vector
float invLen = Math.invsqrt(dx * dx + dy * dy + dz * dz);
dir.x = dx * invLen;
dir.y = dy * invLen;
dir.z = dz * invLen;
return dir;
}
}