2
\$\begingroup\$

I'm currently trying to implement a ArcBall Camera which should fly around a given XMFLOAT3 position stored in a cb with a spezified distance to the position. I used the code from Allen Sherrod for this but the constant buffer that should pass the viewmatrix and the second one for the position to the shaders doesn't update. Any ideas?

This should return the view mat:

    XMMATRIX ArcCamera::GetViewMatrix()
{
    XMVECTOR zoom = XMVectorSet(0.0f, 0.0f, distance_, 1.0f);
    XMMATRIX rotation = XMMatrixRotationRollPitchYaw(xRotation_, -yRotation_, 0.0f);

    zoom = XMVector3Transform(zoom, rotation);

    XMVECTOR pos = XMLoadFloat3(&position_);
    XMVECTOR lookAt = XMLoadFloat3(&target_);

    pos = lookAt + zoom;
    XMStoreFloat3(&position_, pos);

    XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 1.0f);
    up = XMVector3Transform(up, rotation);

    XMMATRIX viewMat = XMMatrixLookAtLH(pos, lookAt, up);


    return viewMat;
}

The rotation (xRotation, yRotation) increases every frame.

The shaders:

Texture2D colorMap : register( t0 );
SamplerState colorSampler : register( s0 );


cbuffer cbChangesEveryFrame : register( b0 )
{
    matrix worldMatrix;
};

cbuffer cbNeverChanges : register( b1 )
{
    matrix viewMatrix;
};

cbuffer cbChangeOnResize : register( b2 )
{
    matrix projMatrix;
};

cbuffer cbCameraData : register( b3 )
{
    float3 cameraPos;
};


struct VS_Input
{
    float4 pos  : POSITION;
    float2 tex0 : TEXCOORD0;
    float3 norm : NORMAL;
};

struct PS_Input
{
    float4 pos  : SV_POSITION;
    float2 tex0 : TEXCOORD0;
    float3 norm : NORMAL;
    float3 lightVec : TEXCOORD1;
    float3 viewVec : TEXCOORD2;
};


PS_Input VS_Main( VS_Input vertex )
{
    PS_Input vsOut = ( PS_Input )0;
    float4 worldPos = mul( vertex.pos, worldMatrix );
    vsOut.pos = mul( worldPos, viewMatrix );
    vsOut.pos = mul( vsOut.pos, projMatrix );

    vsOut.tex0 = vertex.tex0;
    vsOut.norm = mul( vertex.norm, (float3x3)worldMatrix );
    vsOut.norm = normalize( vsOut.norm );

    float3 lightPos = float3( 0.0f, 500.0f, 50.0f );
    vsOut.lightVec = normalize( lightPos - worldPos );

    vsOut.viewVec = normalize( cameraPos - worldPos );

    return vsOut;
}


float4 PS_Main( PS_Input frag ) : SV_TARGET
{
    float3 ambientColor = float3( 0.2f, 0.2f, 0.2f );
    float3 lightColor = float3( 0.7f, 0.7f, 0.7f );

    float3 lightVec = normalize( frag.lightVec );
    float3 normal = normalize( frag.norm );

    float diffuseTerm = clamp( dot( normal, lightVec ), 0.0f, 1.0f );
    float specularTerm = 0;

    if( diffuseTerm > 0.0f )
    {
        float3 viewVec = normalize( frag.viewVec );
        float3 halfVec = normalize( lightVec + viewVec );

        specularTerm = pow( saturate( dot( normal, halfVec ) ), 25 );
    }

    float3 finalColor = ambientColor + lightColor * diffuseTerm + lightColor * specularTerm;

    return float4( finalColor, 1.0f );
}

Must I update all subresources and stuff before every time I call the context's draw method to render every my objects by the way?

\$\endgroup\$
  • \$\begingroup\$ FWIW, I have an ArcBall implementation in this project that uses DirectXMath and was based on the DXUT version. \$\endgroup\$ – Chuck Walbourn May 19 '16 at 21:13
  • \$\begingroup\$ Thank you very much. I got it working with enaught coffee and Jamaica Papa Curvin :D \$\endgroup\$ – kessler bebe May 20 '16 at 12:56
1
\$\begingroup\$

You are doing more than you should to generate your arc ball matrix. The code below should be enough for your need.

DirectX::XMMATRIX ComputeArcBallViewMatrix(DirectX::XMVECTOR origin,float distance,float yaw,float pitch,float roll = 0.f) {
    auto rotation = DirectX::XMMatrixRotationRollPitchYaw(pitch,yaw,roll);
    auto offset = DirectX::XMVectorScale(rotation.r[3],-distance); // assuming camera see positive Z, move back in camera axis
    offset = DirectX::XMVectorAdd(offset,origin); // camera to center of interest offset
    rotation.r[3] = DirectX::XMVectorSetW(offset,1.f); // finalize the cam to world
    return DirectX::XMMatrixInverse(nullptr,rotation); // invert to get world to cam from cam to world
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ The XMMatrixInverse() let's the program crash in xmmathmisc.inl at XMAssert(). Why do you want to swap rotation to a nullptr? \$\endgroup\$ – kessler bebe Jun 1 '16 at 13:07
  • \$\begingroup\$ @kesslerbebe the first parameter of XMMatrixInverse is an optional output to retrieve the determinant, but we don't care about it here. A matrix inversion should not crash, the invert-able matrix is supposed to have a non zero determinant, and by construct, our matrix should be. The documentation of XMMatrixInverse states that xna math version earlier than 2.04 was non optional, may be that. \$\endgroup\$ – galop1n Jun 1 '16 at 23:36
  • \$\begingroup\$ youtube.com/watch?v=7ADjQL5hGBM but using the commented code above it works \$\endgroup\$ – kessler bebe Jun 3 '16 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.