• Very quick method of model recognition based on texture CRCs

    Hey y'all,
    This is my first tutorial in a long time, so comment below and let me know what you think.

    Preable
    The worst part about developing a rendering based hack (d3d, opengl, etc) is figuring out what's what in the scene. A few different methods exist, each with their advantages and disadvantages. The two most popular are Vertex Counts and Texture CRCs.

    Vertex counts pros
    - simple to find
    - simple to make

    Vertex counts cons
    - time consuming
    - dependent on individuals settings (rendering quality)
    - dependent on range (dynamic LOD)


    Texture checksum pros
    - not dependent on dynamic LOD
    - simple to find

    Texture checksum cons
    - time consuming
    - dependent on individuals settings (texture quality)


    One common problem for both these methods is that they are both very time consuming. The typical method of getting the right vertex count or texture CRC is to setup binds on your keyboards to change a variable that matches a range of the vertex count or texture CRC.


    My Solution
    Being unsatisfied with the amount of time it takes to create recognition for objects, I decided to invent a new, quick method of doing this.

    In a nutshell, we represent our texture CRCs as colour.
    This is not a new concept, as if you have ever used a game that uses normal mapping, which uses a similar method of conveying information as colour.

    In a normal map, each RGB component corresponds the X, Y, Z components. Meaning pure red (1, 0, 0), means straight up along the X axis.

    We will be using a similar concept to display our CRCs on the screen, but instead of storing a normal map, we're going to use the CRC to display this colour.

    Meaning, we will convert a CRC (0xAABBCCDD) to a colour, the problem is that a CRC is 4 bytes, meanwhile a colour is just 3. So we will use the first 3 bytes in the CRC as R, G, and B.

    Red = AA, Green = BB, Blue = CC, and DD is unused.


    The Code
    Now that was have the concept down, we must someone render our objects (players, scenery, guns, smoke, etc.) with this colour. The best way would be to use a pixel shader to ensure a pure single colour is sent to the screen. Here is the pixel shader assembly:

    Code:
    ps_1_3
    mov r0, c0
    If you're unfamiliar with pixel shaders, this just means that the output colour (r0) will be filled with whatever is stored in constant register 0 (c0). The first instruction lets the compiler know its PS 1.3 (directx8 shader, which will work for a Geforce4ti / Radeon 8500 or higher).

    To create this shader for use by Direct3D, we must assemble it. Below is how to do so:

    Code:
    ID3DXBuffer *pShaderBuf = NULL;
    char szShader[] = "ps_1_3 \nmov r0, c0 \n";
    
    if( SUCCEEDED(D3DXAssembleShader(szShader, sizeof(szShader), NULL, NULL, 0, &pShaderBuf, NULL)) )
    {
    	m_pD3Ddev->CreatePixelShader((const DWORD*)pShaderBuf->GetBufferPointer(), &m_pSimpleShader);
    	pShaderBuf->Release();
    }
    The variable m_pSimpleShader is defined as IDirect3DPixelShader9*, I store this in my Direct3DDevice9 object.

    Next, we're going to render our objects using this pixel shader. Below is the code to do so:

    Code:
    if( m_stage0Crc != 0 )
    {
    	IDirect3DPixelShader9 *tmpShader;
    
    	m_pD3Ddev->GetPixelShader(&tmpShader);
    	m_pD3Ddev->SetPixelShader(this->m_pSimpleShader);
    
    	float vals[] = { 
    		((m_stage0Crc >> 24)&0xFF) / 255.0f,
    		((m_stage0Crc >> 16)&0xFF) / 255.0f,
    		((m_stage0Crc >> 8)&0xFF) / 255.0f,
    		1.0f
    	};
    
    	m_pD3Ddev->SetPixelShaderConstantF(0, vals, 1);
    
    	HRESULT result = m_pD3Ddev->DrawIndexedPrimitive(Type,BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
    
    	m_pD3Ddev->SetPixelShader(tmpShader);
    		
    	return result;
    }
    The variable m_stage0Crc is the CRC for the texture stored in stage 0 (from SetTexture).
    The variable vals contains the RGBA components to be sent to the shader constant register 0. These values must be between 0.0 and 1.0, so we pick apart m_stage0Crc and divide by 255 to get the individual components.

    Notice how Alpha is set to 1.0, we do this because any sort of blending will produce a different colour, and we need exact values.

    Now that we have our shader working, lets see how it looks in game:



    Getting the CRC
    Like I said above, we need exact values, so make sure when you're getting a screenshot, make sure that it is not lossy compressed. I play my game in windowed mode and use the Print Screen button, which seems to work well.

    Since we have our screenshot, use your favorite image editing program to get the colour. I used photoshops eyedropper tool, it's very convenient because it will give you a hex value of that colour, which we will then compare to our list of CRCs we saved.

    We want to know the CRC for the texture of the soldiers chest, so use our eyedropper tool, and we find that its colour in hex is #b74fd6.

    From this number, we know that our CRC must start with 0xB74FD6xx, so we check our log files for any CRCs matching this, and we get 0xB74FD655. Tada, our CRC for the soldiers chest is 0xB74FD655.

    Verifying our Findings
    A very simple way to verify if our CRC is correct is to somehow tag it, the simplest method is to skip rendering of any objects that use that texture:

    Code:
    if( m_stage0Crc == 0xb74fd655 )
         return D3D_OK;


    As you can see, the soldiers chest is no longer being rendered, meaning we have the right CRC, mission accomplished.

    Notes
    One thing to keep in mind, is although our pixel shader is rendering a pure colour object, that does not necessarily mean that's what will be outputted to the screen. Post processing, fog, screen overlays can corrupt our colour, meaning you will have to first disable those to sure the pure colour is being passed to the monitor alone.

    For Call of Duty Modern Warfare 2, I just prevent calls to SetRenderState, and that fixed my problem, however different games and different configurations may be different.


    Post your questions or comments below.
    -Azorbix
    This article was originally published in forum thread: Very quick method of model recognition based on texture CRCs started by Azorbix View original post
    Comments 29 Comments
    1. Azorbix's Avatar
      I realize this tutorial looks like a giant run on sentence, I'll likely revise it tomorrow, it's kinda late atm.
    1. kynox's Avatar
      Very impressive. Simplifies the tedious art of chams!
    1. panzer's Avatar
      Great work Azo. Attachments don't work though, seems to be a forum problem. Maybe you can upload the images to imageshack or something alike.
    1. kynox's Avatar
      Quote Originally Posted by panzer View Post
      Great work Azo. Attachments don't work though, seems to be a forum problem. Maybe you can upload the images to imageshack or something alike.
      Can see em fine here.
    1. syntroniks's Avatar
      I am having problems with the attachments, I might try another browser.

      Suggestions:
      Bolded text in places
      Indented sections
      Text size variations and stuff for headings
      I will admit, after reading your post for 6 seconds, I don't understand it, but I realize how cool it is.

      Oh, and I like the pixel shader part.
    1. learn_more's Avatar
      a very nice idea, and a thorough description how to reproduce it, nice work
    1. Azorbix's Avatar
      I updated the post, fixed some screenshots, and (hopefully) made it easier to follow.
    1. Absolution's Avatar
      Nice tutorial, though would it be better if it was located in the DirectX forum?
    1. Azorbix's Avatar
      Probably, I wasn't really paying attention to where I put it.

      EDIT: Moved
    1. console's Avatar
      Good explanation, helped me anyway.
      Standard stride logging gave me RSI.
    1. atom0s's Avatar
      As said on IRC, niffty idea.

      +1 ninja star for joo.
    1. syntroniks's Avatar
      This is now easier to follow and the pictures help as well. Good job, I like the sylistic aspect of your pixel shader. If I had a graphics card, I'd be begging for a tutorial on how to use those >;D
    1. Anddos's Avatar
      wont the address of m_stage0Crc be diferent every time the program runs?
    1. kolbybrooks's Avatar
      Why does it matter? m_stage0Crc is Azorbix's Crc of the texture that was applied in SetTexture, it's something He declared.
    1. K@N@VEL's Avatar
      Great tutorial, I am only confused by "m_stage0Crc" varible, Do you hook SetTexture and then set this varible via that or am i burnt ?
    1. kolbybrooks's Avatar
      Yes, that is the CRC32 of the texture; How can you not conclude that from his post?
    1. Ownasaurus's Avatar
      Wonderful idea! Putting that mind to good use Glad I checked the forums again to find this post.
    1. regist's Avatar
      I'm not reading the whole thing right now, but that looks very well useful.
    1. Jordon's Avatar
      Great way of doing it, last time I got CRC's was colouring one at a time and scrolling through till I found what I was looking for.

      Much love to Azo <-- cat?
    1. Guy's Avatar
      Cool idea, I'll have to try it out some time for an easier way to cham