是否有可能在OpenGL中点击多维数据集的哪个表面?

时间:2017-08-26 07:59:37

标签: android opengl-es coordinate-transformation

我已经完美地创建了一个立方体和它的旋转。我的任务是你点击哪个旋转立方体。例如,如果你点击立方体表面的红色然后,我会赢,但我找不到立方体点击的表面视图,

被修改

enter image description here
我想要触摸的表面。

这是我的渲染器代码:

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);
}

2 个答案:

答案 0 :(得分:3)

  

是否可以在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

在视图空间中的正投影中定义视线射线

Orthographic projection

可以通过使用逆投影矩阵变换近平面(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)

在视图空间中的透视投影中定义视线光线

Perspective projection

视线的起点是摄像机位置,在视图空间中为(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) )

从视图坐标转换为世界坐标

要从视图空间转换为世界空间,必须通过逆视图矩阵转换视图空间坐标。

R0_world = inverse( view-matrix ) * R0_view
R1_world = inverse( view-matrix ) * (R0_view + D_view)
D_world  = normalize(R1_world - R0_world)

找到光线与原始

的交点

要找到被光线击中的曲面,必须计算每个曲面(基元)与光线的交点和光线起点的距离。具有最低距离(在光线方向上)的表面被击中。

要查找光线与三角形基元的交点距离,必须执行以下步骤:

  1. 找到由三角形基元的3个点定义的光线和平面的交点。
  2. 计算交点与光线起点之间的距离。
  3. 测试交点是否在光线方向(不是相反方向)
  4. 测试交点是否在三角形轮廓中或上。
  5. 找到交叉点和交叉点距离:

    平面由范数向量(NV)和平面上的点(P0)定义。如果3点ABC给出三角形,则可以按如下方式计算平面:

    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 )
    } 
    


    为解决这个问题,以下问题的答案也会引起人们的兴趣:

    请参阅演示算法的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, Coef11];
        var Fac3 = [Coef12, Coef12, Coef14, Coef15];
        var Fac4 = [Coef16, Coef16, Coef18, Coef19];
        var Fac5 = [Coef20, Coef20, Coef22, Coef23];
          
        var Vec0 = [ m[1*4+0], m[0*4+0], m[0*4+0], m[0*4+0] ];
        var Vec1 = [ m[1*4+1], m[0*4+1], m[0*4+1], m[0*4+1] ];
        var Vec2 = [ m[1*4+2], m[0*4+2], m[0*4+2], m[0*4+2] ];
        var Vec3 = [ m[1*4+3], m[0*4+3], m[0*4+3], m[0*4+3] ];
          
        var Inv0 = vec4_add( vec4_sub( vec4_mul(Vec1, Fac0), vec4_mul(Vec2, Fac1) ), vec4_mul( Vec3, Fac2 ) );
        var Inv1 = vec4_add( vec4_sub( vec4_mul(Vec0, Fac0), vec4_mul(Vec2, Fac3) ), vec4_mul( Vec3, Fac4 ) );
        var Inv2 = vec4_add( vec4_sub( vec4_mul(Vec0, Fac1), vec4_mul(Vec1, Fac3) ), vec4_mul( Vec3, Fac5 ) );
        var Inv3 = vec4_add( vec4_sub( vec4_mul(Vec0, Fac2), vec4_mul(Vec1, Fac4) ), vec4_mul( Vec2, Fac5 ) );
          
        var SignA = [+1.0, -1.0, +1.0, -1.0];
        var SignB = [-1.0, +1.0, -1.0, +1.0];
        var Inverse = [ vec4_mul(Inv0, SignA), vec4_mul(Inv1, SignB), vec4_mul(Inv2, SignA), vec4_mul(Inv3, SignB) ];
          
        var Row0 = [Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0] ];
          
        var Dot0 = [Row0[0], Row0[1], Row0[2], Row0[3] ];
        Dot0 = vec4_mul( Dot0, [ m[0], m[1], m[2], m[3] ] );
        var Dot1 = (Dot0[0] + Dot0[1]) + (Dot0[2] + Dot0[3]);
          
        var OneOverDeterminant = 1 / Dot1;
    
        var res = IdentityMat44();  
        for ( var inx1 = 0; inx1 < 4; inx1 ++ ) {
            for ( var inx2 = 0; inx2 < 4; inx2 ++ )
                res[inx1*4+inx2] = Inverse[inx1][inx2] * OneOverDeterminant;
        }
        return res;
    }
    
    
    Transform = function(vec, mat) {
        var h = [
            vec[0] * mat[0*4+0] + vec[1] * mat[1*4+0] + vec[2] * mat[2*4+0] + mat[3*4+0],
            vec[0] * mat[0*4+1] + vec[1] * mat[1*4+1] + vec[2] * mat[2*4+1] + mat[3*4+1],
            vec[0] * mat[0*4+2] + vec[1] * mat[1*4+2] + vec[2] * mat[2*4+2] + mat[3*4+2],
            vec[0] * mat[0*4+3] + vec[1] * mat[1*4+3] + vec[2] * mat[2*4+3] + mat[3*4+3] ]
        if ( h[3] == 0.0 )
            return [0, 0, 0]
        return [ h[0]/h[3], h[1]/h[3], h[2]/h[3] ];
    }
    
    var Camera = {};
    Camera.create = function() {
        this.pos    = [0, 3, 0.0];
        this.target = [0, 0, 0];
        this.up     = [0, 0, 1];
        this.fov_y  = 90;
        this.vp     = [800, 600];
        this.near   = 0.5;
        this.far    = 100.0;
    }
    Camera.Perspective = function() {
        var fn = this.far + this.near;
        var f_n = this.far - this.near;
        var r = this.vp[0] / this.vp[1];
        var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
        var m = IdentityMat44();
        m[0]  = t/r; m[1]  = 0; m[2]  =  0;                              m[3]  = 0;
        m[4]  = 0;   m[5]  = t; m[6]  =  0;                              m[7]  = 0;
        m[8]  = 0;   m[9]  = 0; m[10] = -fn / f_n;                       m[11] = -1;
        m[12] = 0;   m[13] = 0; m[14] = -2 * this.far * this.near / f_n; m[15] =  0;
        return m;
    }
    Camera.LookAt = function() {
        var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
        var mx = Normalize( Cross( this.up, mz ) );
        var my = Normalize( Cross( mz, mx ) );
        var tx = Dot( mx, this.pos );
        var ty = Dot( my, this.pos );
        var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos ); 
        var m = IdentityMat44();
        m[0]  = mx[0]; m[1]  = my[0]; m[2]  = mz[0]; m[3]  = 0;
        m[4]  = mx[1]; m[5]  = my[1]; m[6]  = mz[1]; m[7]  = 0;
        m[8]  = mx[2]; m[9]  = my[2]; m[10] = mz[2]; m[11] = 0;
        m[12] = tx;    m[13] = ty;    m[14] = tz;    m[15] = 1; 
        return m;
    } 
    
    // shader program object
    var ShaderProgram = {};
    ShaderProgram.Create = function( shaderList, uniformNames ) {
        var shaderObjs = [];
        for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
            var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
            if ( shderObj == 0 )
                return 0;
            shaderObjs.push( shderObj );
        }
        var progObj = this.LinkProgram( shaderObjs )
        if ( progObj != 0 ) {
            progObj.unifomLocation = {};
            for ( var i_n = 0; i_n < uniformNames.length; ++ i_n ) {
                var name = uniformNames[i_n];
                progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
            }
        }
        return progObj;
    }
    ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } 
    ShaderProgram.SetUniformInt = function( progObj, name, val ) { gl.uniform1i( progObj.unifomLocation[name], val ); }
    ShaderProgram.SetUniform2i = function( progObj, name, arr ) { gl.uniform2iv( progObj.unifomLocation[name], arr ); }
    ShaderProgram.SetUniformFloat = function( progObj, name, val ) { gl.uniform1f( progObj.unifomLocation[name], val ); }
    ShaderProgram.SetUniform2f = function( progObj, name, arr ) { gl.uniform2fv( progObj.unifomLocation[name], arr ); }
    ShaderProgram.SetUniform3f = function( progObj, name, arr ) { gl.uniform3fv( progObj.unifomLocation[name], arr ); }
    ShaderProgram.SetUniformMat44 = function( progObj, name, mat ) { gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
    ShaderProgram.CompileShader = function( source, shaderStage ) {
        var shaderScript = document.getElementById(source);
        if (shaderScript) {
          source = "";
          var node = shaderScript.firstChild;
          while (node) {
            if (node.nodeType == 3) source += node.textContent;
            node = node.nextSibling;
          }
        }
        var shaderObj = gl.createShader( shaderStage );
        gl.shaderSource( shaderObj, source );
        gl.compileShader( shaderObj );
        var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
        if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
        return status ? shaderObj : 0;
    } 
    ShaderProgram.LinkProgram = function( shaderObjs ) {
        var prog = gl.createProgram();
        for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
            gl.attachShader( prog, shaderObjs[i_sh] );
        gl.linkProgram( prog );
        status = gl.getProgramParameter( prog, gl.LINK_STATUS );
        if ( !status ) alert("Could not initialise shaders");
        gl.useProgram( null );
        return status ? prog : 0;
    }
            
    function drawScene(){
    
        var canvas = document.getElementById( "ogl-canvas" );
        Camera.create();
        Camera.vp = [canvas.width, canvas.height];
        var currentTime = Date.now();   
        var deltaMS = currentTime - startTime;
            
        gl.viewport( 0, 0, canvas.width, canvas.height );
        gl.enable( gl.DEPTH_TEST );
        gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
        gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
        
        var prjMat = Camera.Perspective();
        var viewMat = Camera.LookAt();
    
        // set up draw shader
        ShaderProgram.Use( progDraw );
        ShaderProgram.SetUniformMat44( progDraw, "u_projectionMat44", prjMat );
        ShaderProgram.SetUniformMat44( progDraw, "u_viewMat44", viewMat );
        var modelMat = IdentityMat44()
        modelMat = RotateAxis( modelMat, CalcAng( currentTime, 13.0 ), 0 );
        modelMat = RotateAxis( modelMat, CalcAng( currentTime, 17.0 ), 1 );
        ShaderProgram.SetUniformMat44( progDraw, "u_modelMat44", modelMat );
        
        // draw scene
        bufObj = bufCube;
        gl.enableVertexAttribArray( progDraw.inPos );
        gl.enableVertexAttribArray( progDraw.inCol );
        gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos );
        gl.vertexAttribPointer( progDraw.inPos, 3, gl.FLOAT, false, 0, 0 );
        gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.col );
        gl.vertexAttribPointer( progDraw.inCol, 3, gl.FLOAT, false, 0, 0 );
        gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
        gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
        gl.disableVertexAttribArray( progDraw.pos );
        gl.disableVertexAttribArray( progDraw.col );
    
        var newColor = "#000000";
        var pos = [-1, -1];
        if (mousePos[0] > 0 && mousePos[1] > 0 ) {
            var pos = [2.0 * mousePos[0] / canvas.width - 1.0, 1.0 - 2.0 * mousePos[1] / canvas.height];
    
            var invPrjMat = mat44_inverse( prjMat )
            var invViewMat = mat44_inverse( viewMat )
            var invModelMat = mat44_inverse( modelMat )
    
            var viewP1 = Transform([pos[0],pos[1],-1.0], invPrjMat);
            
            var R0 = Transform(Transform([0,0,0], invViewMat), invModelMat);
            var R1 = Transform(Transform(viewP1, invViewMat), invModelMat);
            var D = Normalize( [ R1[0]-R0[0], R1[1]-R0[1], R1[2]-R0[2] ] );
    
            var minDist = 100000;
            for ( it = 0; it < cubeInxData.length; it = it + 3 )
            {
                var trI = [ cubeInxData[it+0], cubeInxData[it+1], cubeInxData[it+2] ]
                var A = [ cubePosData[trI[0]*3+0], cubePosData[trI[0]*3+1], cubePosData[trI[0]*3+2] ];
                var B = [ cubePosData[trI[1]*3+0], cubePosData[trI[1]*3+1], cubePosData[trI[1]*3+2] ];
                var C = [ cubePosData[trI[2]*3+0], cubePosData[trI[2]*3+1], cubePosData[trI[2]*3+2] ];
                
                P0 = A;
                NV = Cross( [ B[0]-A[0], B[1]-A[1], B[2]-A[2] ], [ C[0]-A[0], C[1]-A[1], C[2]-A[2] ] );
                NV = Normalize( NV );
    
                dist_isect = Dot( [ P0[0]-R0[0], P0[1]-R0[1], P0[2]-R0[2] ], NV ) / Dot( D, NV );
                if ( dist_isect < 0.0 )
                    continue;
                P_isect    = [ R0[0] + D[0] * dist_isect, R0[1] + D[1] * dist_isect, R0[2] + D[2] * dist_isect ];
    
                if ( PointInOrOnTriangle( P_isect, A, B, C ) )
                {
                    var col = [ 
                        Math.floor(cubeColData[trI[0]*3+0]*255),
                        Math.floor(cubeColData[trI[0]*3+1]*255),
                        Math.floor(cubeColData[trI[0]*3+2]*255) ];
                    h0 = col[0].toString(16); if( h0.length < 2 ) h0 = "0" + h0;
                    h1 = col[1].toString(16); if( h1.length < 2 ) h1 = "0" + h1;
                    h2 = col[2].toString(16); if( h2.length < 2 ) h2 = "0" + h2;
                    if ( dist_isect < minDist ) {
                        minDist = dist_isect;
                        newColor = "#" + h0 + h1 + h2;
                    } 
                }
            }
        }
        document.getElementById( "color" ).value = newColor;
        document.getElementById( "mouseX" ).innerHTML = pos[0];
        document.getElementById( "mouseY" ).innerHTML = pos[1];
    }
    
    var startTime;
    function Fract( val ) { 
        return val - Math.trunc( val );
    }
    function CalcAng( currentTime, intervall ) {
        return Fract( (currentTime - startTime) / (1000*intervall) ) * 2.0 * Math.PI;
    }
    function CalcMove( currentTime, intervall, range ) {
        var pos = self.Fract( (currentTime - startTime) / (1000*intervall) ) * 2.0
        var pos = pos < 1.0 ? pos : (2.0-pos)
        return range[0] + (range[1] - range[0]) * pos;
    }    
    function EllipticalPosition( a, b, angRag ) {
        var a_b = a * a - b * b
        var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b );
        var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b );
        return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];
    }
    
    var mousePos = [-1, -1];
    var sliderScale = 100.0
    var gl;
    var progDraw;
    var bufCube = {};
    var bufTorus = {};
    var cubePosData = [];
    var cubeColData = [];
    var cubeInxData = [];
    function sceneStart() {
    
        var canvas = document.getElementById( "ogl-canvas");
        var vp = [canvas.width, canvas.height];
        gl = canvas.getContext( "experimental-webgl" );
        if ( !gl )
          return;
    
        progDraw = ShaderProgram.Create( 
          [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
            { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
          ],
          [ "u_projectionMat44", "u_viewMat44", "u_modelMat44" ] );
        progDraw.inPos = gl.getAttribLocation( progDraw, "inPos" );
        progDraw.inCol = gl.getAttribLocation( progDraw, "inCol" );
        if ( progDraw == 0 )
            return;
    
        // create cube
        var cubePos = [
            -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0,  1.0,  1.0, -1.0,  1.0,  1.0,
            -1.0, -1.0, -1.0,  1.0, -1.0, -1.0,  1.0,  1.0, -1.0, -1.0,  1.0, -1.0 ];
        var cubeCol = [ 1.0, 0.0, 0.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ];
        var cubeHlpInx = [ 0, 1, 2, 3, 1, 5, 6, 2, 5, 4, 7, 6, 4, 0, 3, 7, 3, 2, 6, 7, 1, 0, 4, 5 ]; 
        for ( var i = 0; i < cubeHlpInx.length; ++ i ) {
            cubePosData.push( cubePos[cubeHlpInx[i]*3], cubePos[cubeHlpInx[i]*3+1], cubePos[cubeHlpInx[i]*3+2] );
        }
        for ( var is = 0; is < 6; ++ is ) {
            for ( var ip = 0; ip < 4; ++ ip ) {
               cubeColData.push( cubeCol[is*3], cubeCol[is*3+1], cubeCol[is*3+2] ); 
            }
        }
        for ( var i = 0; i < cubeHlpInx.length; i += 4 ) {
            cubeInxData.push( i, i+1, i+2, i, i+2, i+3 );
        }
        bufCube.pos = gl.createBuffer();
        gl.bindBuffer( gl.ARRAY_BUFFER, bufCube.pos );
        gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( cubePosData ), gl.STATIC_DRAW );
        bufCube.col = gl.createBuffer();
        gl.bindBuffer( gl.ARRAY_BUFFER, bufCube.col );
        gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( cubeColData ), gl.STATIC_DRAW );
        bufCube.inx = gl.createBuffer();
        gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufCube.inx );
        gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( cubeInxData ), gl.STATIC_DRAW );
        bufCube.inxLen = cubeInxData.length;
    
        startTime = Date.now();
        setInterval(drawScene, 50);
    }
    
    (function() {
        document.onmousemove = handleMouseMove;
        function handleMouseMove(event) {
            var dot, eventDoc, doc, body, pageX, pageY;
    
            event = event || window.event; // IE-ism
    
            if (event.pageX == null && event.clientX != null) {
                eventDoc = (event.target && event.target.ownerDocument) || document;
                doc = eventDoc.documentElement;
                body = eventDoc.body;
    
                event.pageX = event.clientX +
                  (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
                  (doc && doc.clientLeft || body && body.clientLeft || 0);
                event.pageY = event.clientY +
                  (doc && doc.scrollTop  || body && body.scrollTop  || 0) -
                  (doc && doc.clientTop  || body && body.clientTop  || 0 );
            }
    
            var canvas = document.getElementById( "ogl-canvas");
            var x = event.pageX - canvas.offsetLeft;
            var y = event.pageY - canvas.offsetTop;
            mousePos = [-1, -1];
            if ( x >= 0 && x < canvas.width && y >= 0 && y < canvas.height ) {
                mousePos = [x, y]; 
            }
        }
    })();
    <script id="draw-shader-vs" type="x-shader/x-vertex">
    precision mediump float;
    
    attribute vec3 inPos;
    attribute vec3 inCol;
    
    varying vec3 vertCol;
    
    uniform mat4 u_projectionMat44;
    uniform mat4 u_viewMat44;
    uniform mat4 u_modelMat44;
    
    void main()
    {
        vertCol       = inCol;
        vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
        vec4 viewPos  = u_viewMat44 * modelPos;
        gl_Position   = u_projectionMat44 * viewPos;
    }
    </script>
    
    <script id="draw-shader-fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying vec3 vertCol;
    
    void main()
    {
        gl_FragColor = vec4( vertCol.rgb, 1.0 );
    }
    </script>
    
    <body onload="sceneStart();">
        <div style="margin-left: 260px;">
            <div style="float: right; width: 100%; background-color: #CCF;">
                <form name="inputs">
                    <table>
                        <tr> <td> <input type="color" value="#000000" id="color" disabled></td> </tr> 
                        <tr> <td> <span id="mouseX">0</span> </td> </tr>
                        <tr> <td> <span id="mouseY">0</span> </td> </tr>
                    </table>
                </form>
            </div>
            <div style="float: right; width: 260px; margin-left: -260px;">
                <canvas id="ogl-canvas" style="border: none;" width="256" height="256"></canvas>
            </div>
            <div style="clear: both;"></div>
        </div>
    </body>

答案 1 :(得分:1)

最常见和最现代的方式可能是Ray Intersection。

我以为你有很多立方体。

  
      
  1. 计算通过触摸Android屏幕制作的光线

  2.   
  3. (每个表面)     if(光线与它相交)        按距离在排序列表中保存曲面和距离

  4.   
  5. 从排序列表中选择最近的表面。

  6.