是否有可能在OpenGL中点击多维数据集的哪个表面?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否有可能在OpenGL中点击多维数据集的哪个表面?相关的知识,希望对你有一定的参考价值。
我已经完全创造了一个立方体和它的旋转。我的任务是你点击哪个旋转立方体。例如,如果你点击立方体表面的红色然后,我会赢,但我无法找到立方体点击的表面视图,
编辑
这是我的渲染器代码:
public void onDrawFrame(GL10 arg0) {
// GLES20.glEnable(GLES20.GL_TEXTURE_CUBE_MAP);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(iProgId);
cubeBuffer.position(0);
GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, cubeBuffer);
GLES20.glEnableVertexAttribArray(iPosition);
texBuffer.position(0);
GLES20.glVertexAttribPointer(iTexCoords, 3, GLES20.GL_FLOAT, false, 0, texBuffer);
GLES20.glEnableVertexAttribArray(iTexCoords);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, iTexId);
GLES20.glUniform1i(iTexLoc, 0);
// Draw a cube.
// Translate the cube into the screen.
Matrix.setIdentityM(m_fIdentity, 0);
// Matrix.translateM(m_fIdentity, 0, 0.0f, 0.8f, -3.5f);
// Set a matrix that contains the current rotation.
Matrix.setIdentityM(mCurrentRotation, 0);
Matrix.rotateM(mCurrentRotation, 0, mDeltaX, 1.0f, 0.0f, 0.0f);
Matrix.rotateM(mCurrentRotation, 0, mDeltaY, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mCurrentRotation, 0, mDeltaZ, 0.0f, 0.0f, 1.0f);
mDeltaX = 0.0f;
mDeltaY = 0.0f;
mDeltaZ = 0.0f;
// Multiply the current rotation by the accumulated rotation, and then set the accumulated
// rotation to the result.
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);
// Rotate the cube taking the overall rotation into account.
Matrix.multiplyMM(mTemporaryMatrix, 0, m_fIdentity, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, m_fIdentity, 0, 16);
Matrix.multiplyMM(m_fVPMatrix, 0, m_fViewMatrix, 0, m_fIdentity, 0);
Matrix.multiplyMM(m_fVPMatrix, 0, m_fProjMatrix, 0, m_fVPMatrix, 0);
Ray ray = null;
if (mDeltaX != -99) {
ray = new Ray(arg0, width, height, mDeltaX, mDeltaY);
}
mDeltaX = -99;
// Matrix.translateM(m_fVPMatrix, 0, 0, 0, 1);
GLES20.glUniformMatrix4fv(iVPMatrix, 1, false, m_fVPMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 36, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
// GLES20.glDisable(GLES20.GL_TEXTURE_CUBE_MAP);
}
是否有可能在OpenGL中点击多维数据集的哪个表面?
在渲染中,场景的每个对象通常由视图矩阵和投影矩阵变换。虽然视图矩阵描述了观察场景的方向和位置,但是投影矩阵描述了从场景的3D点到视口的2D点的映射。投影矩阵从视图空间转换到剪辑空间,剪辑空间中的坐标转换为范围(-1,-1,-1)到(1,1,1)范围内的规范化设备坐标(NDC)通过用剪辑坐标的w分量来划分。 如果必须找到场景表面上的点,通过选择视口上的点,则必须找到相反的方法。 识别物体表面的常用方法是定义具有起始点和方向的射线,并找到首先被射线击中的表面。视线是这样的光线,因为它具有起点和方向,但是如何通过视线定义光线取决于场景的投影类型。
在Orthographic Projection处,眼睛空间中的坐标线性映射到标准化设备坐标,在Perspective Projection处,相机平截头体(截头金字塔)中的眼睛空间坐标被映射到立方体(标准化设备坐标)。 在这两种情况下,首先必须将视口位置转换为标准化(XY)设备坐标,范围从(-1,-1)到(1,1)。这是一个简单的线性映射:
w = with of the viewport
h = height of the viewport
x = X position of the mouse
y = Y position ot the mouse
ndc_x = 2.0 * x/w - 1.0;
ndc_y = 1.0 - 2.0 * y/h; // invert Y axis
Define a line of sight ray at orthographic projection in view space
可以通过使用逆投影矩阵在近平面(z = 0)上的归一化设备坐标中转换视口的点来计算光线的起始点。
R0_view = inverse( projection-matrix ) * (ndc_x, ndc_y, 0.0, 1.0)
视线的方向是进入视口的方向(0,0,-1)。
D_view = (0.0, 0.0, -1.0)
Define a line of sight ray at perspective projection in view space
视线的起点是摄像机位置,在视图空间中为(0,0,0)。
R0_view = (0.0, 0.0, 0.0)
视线的方向可以通过逆投影矩阵变换归一化设备坐标中的光线上的任何点来计算。
D_view = normalize( inverse( projection-matrix ) * (ndc_x, ndc_y, 0.0, 1.0) )
Convert from view coordinates to world coordinates
要从视图空间转换为世界空间,必须通过逆视图矩阵转换视图空间坐标。
R0_world = inverse( view-matrix ) * R0_view
R1_world = inverse( view-matrix ) * (R0_view + D_view)
D_world = normalize(R1_world - R0_world)
Find the intersection point of a ray with a primitive
为了找到被光线击中的表面,必须计算每个表面(基元)与光线的交点和光线起点的距离。具有最低距离(在光线方向上)的表面被击中。
要查找光线与三角形基元的交点距离,必须执行以下步骤:
- 找到由三角形基元的3个点定义的光线和平面的交点。
- 计算交点和光线起点之间的距离。
- 测试交点是否在光线方向(不是相反方向)
- 测试交点是否在三角形轮廓中或上。
找到交点和交点距离:
平面由范数向量(NV
)和平面上的点(P0
)定义。如果3点A
,B
和C
给出一个三角形,则该平面可以如下计算:
P0 = A
NV = normalize( cross( B-A, C-A ) )
通过代入光线的方程来计算光线与平面的交点
P_isect = dist * D + R0
进入飞机dot( P_isect - P0, NV ) == 0
的等式。
它跟随:
P_isect = R0 + D * dist_isect
dist_isect = dot( P0 - R0, NV ) / dot( D, NV )
测试交点是否在光线方向:
如果`dist_isect大于或等于0.0,则交点位于光线的方向上。
测试交点是否在三角形轮廓中或上
要找出,如果一个点位于三角形内部,则必须进行测试,如果从角点到交叉点的直线位于连接到角点的连接点之间:
bool PointInOrOn( P1, P2, A, B )
{
CP1 = cross( B - A, P1 - A )
CP2 = cross( B - A, P2 - A )
return dot( CP1, CP2 ) >= 0
}
bool PointInOrOnTriangle( P, A, B, C )
{
return PointInOrOn( P, A, B, C ) &&
PointInOrOn( P, B, C, A ) &&
PointInOrOn( P, C, A, B )
}
为解决这个问题,以下问题的答案也会引起关注:
- How to recover view space position given view space depth value and ndc xy
- Mouse picking miss
- How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
- Ray Sphere Intersections in OpenGL
请参阅演示算法的WebGL示例:
glArrayType = typeof Float32Array !="undefined" ? Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array );
function IdentityMat44() {
var m = new glArrayType(16);
m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0;
m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
return m;
};
function RotateAxis(matA, angRad, axis) {
var aMap = [ [1, 2], [2, 0], [0, 1] ];
var a0 = aMap[axis][0], a1 = aMap[axis][1];
var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
var matB = new glArrayType(16);
for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i];
for ( var i = 0; i < 3; ++ i ) {
matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
}
return matB;
}
function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
return [ v[0] / len, v[1] / len, v[2] / len ];
}
function PointInOrOn( P1, P2, A, B )
{
CP1 = Cross( [ B[0]-A[0], B[1]-A[1], B[2]-A[2] ], [ P1[0]-A[0], P1[1]-A[1], P1[2]-A[2] ] )
CP2 = Cross( [ B[0]-A[0], B[1]-A[1], B[2]-A[2] ], [ P2[0]-A[0], P2[1]-A[1], P2[2]-A[2] ] )
return Dot( CP1, CP2 ) >= 0;
}
function PointInOrOnTriangle( P, A, B, C )
{
var isInA = PointInOrOn( P, A, B, C );
var isInB = PointInOrOn( P, B, C, A );
var isInC = PointInOrOn( P, C, A, B );
return isInA && isInB && isInC;
}
vec4_add = function( a, b ) { return [ a[0]+b[0], a[1]+b[1], a[2]+b[2], a[3]+b[3] ]; }
vec4_sub = function( a, b ) { return [ a[0]-b[0], a[1]-b[1], a[2]-b[2], a[3]-b[3] ]; }
vec4_mul = function( a, b ) { return [ a[0]*b[0], a[1]*b[1], a[2]*b[2], a[3]*b[3] ]; }
vec4_scale = function( a, s ) { return [ a[0]*s, a[1]*s, a[2]*s, a[3]*s ]; }
mat44_inverse = function( m ) {
var Coef00 = m[2*4+2] * m[3*4+3] - m[3*4+2] * m[2*4+3];
var Coef02 = m[1*4+2] * m[3*4+3] - m[3*4+2] * m[1*4+3];
var Coef03 = m[1*4+2] * m[2*4+3] - m[2*4+2] * m[1*4+3];
var Coef04 = m[2*4+1] * m[3*4+3] - m[3*4+1] * m[2*4+3];
var Coef06 = m[1*4+1] * m[3*4+3] - m[3*4+1] * m[1*4+3];
var Coef07 = m[1*4+1] * m[2*4+3] - m[2*4+1] * m[1*4+3];
var Coef08 = m[2*4+1] * m[3*4+2] - m[3*4+1] * m[2*4+2];
var Coef10 = m[1*4+1] * m[3*4+2] - m[3*4+1] * m[1*4+2];
var Coef11 = m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2];
var Coef12 = m[2*4+0] * m[3*4+3] - m[3*4+0] * m[2*4+3];
var Coef14 = m[1*4+0] * m[3*4+3] - m[3*4+0] * m[1*4+3];
var Coef15 = m[1*4+0] * m[2*4+3] - m[2*4+0] * m[1*4+3];
var Coef16 = m[2*4+0] * m[3*4+2] - m[3*4+0] * m[2*4+2];
var Coef18 = m[1*4+0] * m[3*4+2] - m[3*4+0] * m[1*4+2];
var Coef19 = m[1*4+0] * m[2*4+2] - m[2*4+0] * m[1*4+2];
var Coef20 = m[2*4+0] * m[3*4+1] - m[3*4+0] * m[2*4+1];
var Coef22 = m[1*4+0] * m[3*4+1] - m[3*4+0] * m[1*4+1];
var Coef23 = m[1*4+0] * m[2*4+1] - m[2*4+0] * m[1*4+1];
var Fac0 = [Coef00, Coef00, Coef02, Coef03];
var Fac1 = [Coef04, Coef04, Coef06, Coef07];
var Fac2 = [Coef08, Coef08, Coef10, Co以上是关于是否有可能在OpenGL中点击多维数据集的哪个表面?的主要内容,如果未能解决你的问题,请参考以下文章