ObjReader Community

WIP => WIP => Topic started by: Patrice Terrier on July 19, 2019, 04:28:18 pm

Title: Animation
Post by: Patrice Terrier on July 19, 2019, 04:28:18 pm
I have found some bad interactions between animation and 3d meshes.

With canyon.fs and carribean.fs

I shall complete the Sketchfab model and send it to you once done, for test purpose.

Here is the link to the original
https://sketchfab.com/3d-models/daz-3d-model-15-v-g8f-b5ac04334dc94ae7af0cb5612921ef6d

Added:
After i reworked the original texture set, now it works with all the animations.  :)
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 19, 2019, 09:46:50 pm
Yeah, please send me the model to check when ready. I'm constantly working on OR little by little fixing bugs and doing minor optimizations here and there. So it's highly probable the glitch has already been fixed.
Title: Re: Animation
Post by: Patrice Terrier on July 20, 2019, 09:17:44 am
Here is the Sketchfab original, to check with canyon.fs and carribean.fs

As i told you, no more problem with the OR version that i am working on, should be completed soon...
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 20, 2019, 09:41:28 am
Thanks, I already got the originals from the SketchFab site yesterday.

Yes, I'm still seeing that glitch in my latest OR. But it reveals itself only in the legacy FFP mode. PPL renders the model all right with the FBOs either on or off.

I'll look into what might go wrong with FFP when it meets that particular combination of the model's raw materials/textures. FFP is emulated on modern GPUs with a built-in shader that might conflict with the user shaders resident on the GPU when it toggles between GLSL and immediate modes of operation. We had a similar problem when emulating your "ambient reflection" stuff in the Blinn-Phong (no-bumpmap) pipeline.

While we are at it, I think we should implement that map_d alpha mask approach in OR too. Using separate 24-bpp diffuse and alpha masks is a classic OBJ format mode of operation. I think it won't be too difficult: whenever OR comes across a separate map_d alpha mask, it should add it as an alpha channel into the existing normally opaque 32-bpp diffuse map.
Title: Re: Animation
Post by: Patrice Terrier on July 20, 2019, 12:07:51 pm
Yes, it occures only in FFP mode.

Quote
While we are at it, I think we should implement that map_d alpha mask approach in OR too.
I wrote already a GDImage utility to create directly a single transparent texture with the correct alpha channel (Alphamask.exe).
But that would be also nice to have it in OR.
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 20, 2019, 01:44:18 pm
So can you add appropriate code to the OR texture loader?
Title: Re: Animation
Post by: Patrice Terrier on July 20, 2019, 02:39:20 pm
Here is the PowerBASIC code

FUNCTION WinMain (BYVAL hInstance     AS LONG, _
                  BYVAL hPrevInstance AS LONG, _
                  BYVAL lpCmdLine     AS ASCIIZ PTR, _
                  BYVAL iCmdShow      AS LONG) AS LONG

    LOCAL zIn, zMask, zOut AS ASCIIZ * 260

    zIn = LCASE$(command$)
    zMask = PARSE$(zIn, 2)
    zIn = PARSE$(zIn, 1)
    zOut = PATHNAME$(PATH, zIn) + "_" + PATHNAME$(NAMEX, zIn)

    IF RIGHT$(zIn, 4) = ".png" THEN
       IF (ZI_ApplyAlphaMask(zIn, zMask, zOut) = 0) THEN ' Means no error
           MessageBox(0, "Alpha channel changed successfuly!", "Opacity", 0)
       END IF
    END IF

END FUNCTION


Strangely ZI_ApplyAlphaMask seems to be missing from the 64-bit DLL  :o
I must investigate  :-[

Anyway i shall write the code to use with OR, once i am done with "Lucky You"...
Title: Re: Animation
Post by: Patrice Terrier on July 20, 2019, 08:11:58 pm
Here is the OR Lucky_You.
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 20, 2019, 10:39:21 pm
Thank you Patrice,

I'm in the process of downloading it -- at some 80KB per second. ;D


P.S. DL completed 16 minutes after start. ;D
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 21, 2019, 09:50:12 am
Hey, I'm seeing the same glitch with the two animated background shaders when this model is rendered in the FFP mode. ???

Re. ZI_ApplyAlphaMask(): any news about the 64-bit GDImage?
Title: Re: Animation
Post by: Patrice Terrier on July 21, 2019, 09:52:45 am
I did check the download speed for "Lucky You" and the result is 4 minutes 28 secondes (in the morning) by me, much slower than when i uploaded the new file.

I did send again a message to my friend Bob about this (you should have a copy of it in your mail box).

Does the download speed is any better in the morning?
Title: Re: Animation
Post by: Patrice Terrier on July 21, 2019, 09:54:47 am
Quote
Re. ZI_ApplyAlphaMask(): any news about the 64-bit GDImage?

I plan to convert the code to 64-bit asap.  ;)
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 21, 2019, 10:05:09 am
Right now, downloading the Lucky_You model still goes at 80 to 100KBytes per second for me with the DL cache cleaned... :(
Title: Re: Animation
Post by: Patrice Terrier on July 21, 2019, 11:07:10 am
OK, we shall have to wait for Bob's return  :-[

Alpha mask,
i shall add support to TGA DDS and regular GDIPLUS graphic extension into the 64-bit version.
However the size of the two files must match.
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 21, 2019, 01:14:22 pm
Re. Bob: OK

Re. 64-bit support: OK

Re. size: while you're at it, why wouldn't you also add alpha mask GDI+ AA resizing to fit the diffuse texture size if necessary?
Title: Re: Animation
Post by: Patrice Terrier on July 21, 2019, 02:52:19 pm
This one is to put at the end of Tools.h until there is a better place in mobj.h

Code: [Select]
LONG_PTR zCreateAlphaMask (IN WCHAR* zInputName, IN WCHAR* zInputMask, IN BOOL ReturnBitmap) {
    LONG_PTR nResult = 0;
    LONG_PTR img1 = 0, img2 = 0, graphics1 = 0, graphics2 = 0;
    long imgW1 = 0, imgH1 = 0, imgW2 = 0, imgH2 = 0;
    long S1 = INWSTR(-1, zInputName, (WCHAR*) $DOT);
    if (!FileExist(zInputName)) S1 = 0;
    if (S1) {
        // Make sure that a full path is being used.
        zCheckName(zInputMask);
        long S2 = INWSTR(-1, zInputMask, (WCHAR*) $DOT);
        if (!FileExist(zInputMask)) S2 = 0;
        if (S2 == 0) S1 = 0;
    }
    if (S1) {
        long ImageType = TextureCheckExtension(zInputMask);
        long nRet = -1, nSwapRB = -1;
        if (ImageType == MEDIA_TGA) {
            nRet = ZI_LoadTGA(zInputMask, &img2);
        } else if (ImageType == MEDIA_DDS) {
            nRet = ZI_LoadDDS(zInputMask, &img2, &nSwapRB);
        } else { // all GDI+
            nRet = GdipLoadImageFromFile(zInputMask, img2);
        }
        if (nRet == 0) {
            GetImageSize(img2, imgW2, imgH2);
            nRet = -1, nSwapRB = -1;
            ImageType = TextureCheckExtension(zInputName);
            if (ImageType == MEDIA_TGA) {
                nRet = ZI_LoadTGA(zInputName, &img1);
            } else if (ImageType == MEDIA_DDS) {
                nRet = ZI_LoadDDS(zInputName, &img1, &nSwapRB);
            } else { // all GDI+
                nRet = GdipLoadImageFromFile(zInputName, img1);
            }
            if (nRet == 0) {
                GetImageSize(img1, imgW1, imgH1);
                if ((imgW1 == imgW2) && (imgH1 == imgH2)) {
                    HDC hDC = zDisplayDC();
                    HDC ImgHDC = CreateCompatibleDC(hDC);
                    HBITMAP hbmReturn = zCreateDIBSection(hDC, imgW1, imgH1, 32);
                    SelectObject(ImgHDC, hbmReturn);

                    HDC MaskHDC = CreateCompatibleDC(hDC);
                    HBITMAP hbmMask = zCreateDIBSection(hDC, imgW2, imgH2, 32);
                    SelectObject(MaskHDC, hbmMask);
                    DeleteDC(hDC);

                    if (GdipCreateFromHDC(MaskHDC, graphics2) == 0) {
                        if (GdipDrawImageRectI(graphics2, img2, 0, 0, imgW2, imgH2) == 0) {
                            // Draw image
                            if (GdipCreateFromHDC(ImgHDC, graphics1) == 0) {
                                if (GdipDrawImageRectI(graphics1, img1, 0, 0, imgW1, imgH1) == 0) {
                                    long AlphaRGB1 = 0, AlphaRGB2 = 0;
                                    GdipBitmapGetPixel(img2, 0, 0, AlphaRGB2);
                                    BITMAP bm2 = { 0 };
                                    GetObject(hbmMask, sizeof(bm2), &bm2);
                                    BYTE* pBits2 = (BYTE*) bm2.bmBits;

                                    GdipBitmapGetPixel(img1, 0, 0, AlphaRGB1);
                                    BITMAP bm1 = { 0 };
                                    GetObject(hbmReturn, sizeof(bm1), &bm1);
                                    BYTE* pBits1 = (BYTE*) bm1.bmBits;
                                    for (long y = 0; y < bm1.bmHeight; ++y) {
                                        for (long x = 0; x < bm1.bmWidth; ++x) {
                                            pBits1[3] = (BYTE) ((pBits2[2] * 0.2989f) + (pBits2[1] * 0.5870f) + (pBits2[0] * 0.114f));
                                            pBits2 += 4;
                                            pBits1 += 4;
                                        }
                                    }
                                }
                                // Cleanup
                                GdipDeleteGraphics(graphics1);
                            }
                            if (img1) { GdipDisposeImage(img1); img1 = 0; }
                            img1 = zBitmapToImage(ImgHDC);
                            if (ImgHDC) DeleteDC(ImgHDC);
                            DeleteObject(hbmReturn);
                        }

                        if (img2) { GdipDisposeImage(img2); img2 = 0; }
                        if (graphics2) GdipDeleteGraphics(graphics2);
                    }
                    if (MaskHDC) DeleteDC(MaskHDC);
                    DeleteObject(hbmMask);
                }
            }
        }
    }

    if (img1) {
        HDC hDC = zDisplayDC();
        HDC ImgHDC = CreateCompatibleDC(hDC);
        HBITMAP hbmReturn = zCreateDIBSection(hDC, imgW1, imgH1, 32);
        SelectObject(ImgHDC, hbmReturn);
        DeleteDC(hDC);
        // Draw image
        if (GdipCreateFromHDC(ImgHDC, graphics1) == 0) {
            for (long K = 0; K < 4; K++) { // Increase opacity
                GdipDrawImageRectI(graphics1, img1, 0, 0, imgW1, imgH1);
            }
            // Cleanup
            GdipDeleteGraphics(graphics1);
        }
        GdipDisposeImage(img1);
        if (ReturnBitmap) {
            DeleteDC(ImgHDC);
            nResult = (LONG_PTR) hbmReturn;
        } else {
            nResult = zBitmapToImage(ImgHDC);
            DeleteDC(ImgHDC);
            DeleteObject(hbmReturn);
        }
    }
    return nResult;
}

and the missing GdipDrawImageRectI API to add into Tools.h after GdipDeleteGraphics.

Code: [Select]
long GdipDrawImageRectI(IN LONG_PTR graphics, IN LONG_PTR lpImg, IN long x, IN long y, IN long W, IN long H) {
    long nRet = -1; // Error
    HMODULE hModule = gdiplib();
    if (hModule) {
        long_proc (LONG_PTR, LONG_PTR, long, long, long, long);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc) GetProcAddress(hModule, "GdipDrawImageRectI"); }
        if (hProc) { nRet = hProc(graphics, lpImg, x, y, W, H); }
    }
    return nRet;
}

Warning, the zCreateAlphaMask code has not been tested yet.

The function returns either a gdiplus LONG_PTR or a HBITMAP handle if ReturnBitmap is TRUE.

It is up to you to cleanup the bitmap handle or the gdiplus LONG_PTR once done.

Look at the "Increase opacity" loop, 4 seems the good value to me, this is what i am using in my standalone utility.

Quote
why wouldn't you also add alpha mask GDI+ AA resizing to fit the diffuse texture size if necessary?
I do not understand what you mean.
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 21, 2019, 06:19:46 pm
I do not understand what you mean.

You said:

However the size of the two files must match.

As I understood it, you were trying to say that the resolution (i.e. image physical size, or width in pxs * height in pxs) of the color and alpha maps to merge should be the same, say, 1024 * 1024 pxs both.

So, my question was why couldn't we just resize (using GDI+ high-quality anti-aliasing) the alpha mask size to match the color map size in case they happen to be different?
Title: Re: Animation
Post by: Patrice Terrier on July 22, 2019, 09:55:04 am
Ok, the standalone version has been checked successfully.

Here is the source (source.zip) and the binary EXE with a couple of images for test purpose.

Test it in command line mode, like this:

alphamask hair.jpg larger_mask.jpg

The mask is resized on the fly to match the size of the zInputName.

The resulting alpha_InputName is saved as a .png file.

You should be able to use directly the zCreateAlphaMask inside of OR.
Title: Re: Animation
Post by: Michael Lobko-Lobanovsky on July 22, 2019, 01:46:04 pm
Thank you, Patrice!

I'll get in touch with you when tested.