2
\$\begingroup\$

I am working on a 2.5D mechanical app. I use 3D software like Blender to render the 3D model to create the 2D assets for the 2D game engine (which's cocos-creator , but it doesn't matter for this case).

How can I hide a part of object which's covered by another object with in the game engine? A sort of mask or something else, I am not sure.

For it has hundreds of object in the scene, like a car engine with all parts. So the solution I am looking for need to be automatic or half-automatic generated by 3D software (eg.Blender, etc), instead of full manual work like using Photoshop to create the mask.

enter image description here

\$\endgroup\$
3
  • 2
    \$\begingroup\$ It seems that cocos-creator supports 3D models, why not let the graphics card take care of this for you by rendering the actual 3D models? If you insist on 2D, you can also pre-render a depth buffer for each part and using some math you can determine the 'topmost' part for each individual pixel. \$\endgroup\$
    – Romen
    Oct 28, 2019 at 21:41
  • 1
    \$\begingroup\$ @Romen with a little elaboration on depth buffers and "some math," I think that could make a very useful answer! \$\endgroup\$
    – DMGregory
    Oct 29, 2019 at 1:58
  • \$\begingroup\$ @DMGregory, I'm honestly not sure that I understand the math enough to complete that answer. \$\endgroup\$
    – Romen
    Oct 29, 2019 at 14:03

2 Answers 2

-1
\$\begingroup\$

Since you wanted an agnostic answer, This answer will deal with how to integrate this in any 2D game framework.

You have supplied orthographic projection models. What you can do is, say, you have an origin for each of those models, and each pixel on the model itself will correspond to a depth value based on that offset. Blender apparently allows the z buffer value to be output directly to an image. The alternative is to create another program, say in opengl, webgl, directx, metal, or vulkan which does the same, but using the geometry you've generated. Once you have this depth value, it will probably be normalized between zero and 1.0, so you'll need to get the near and far clipping plane information. In blender you can get this from 3D view area properties. If you used a custom solution, you would have set this yourself in your orthographic transform matrix.

You can then use the far and near values to re-normalize the depth information if you wish, or you could skip this process if you are sure every model will be rendered using the same near and far values.

Re normalizing would look like this:

renormalized_depth = near + (far - near) * depth;

depth is then calculated, once you have your image, as the depth texture you've just created, offset by the current position of the image and offset where it was rendered originally to get the depth value (since depth starts at zero at your camera face, not at the origin of the object).

To account for the original position you placed it at for rendering you would need to do the following:

renormalized_depth = renormalized_depth - object_centroid_distance;

and then a simple offset for the current centroid would work for current depth.

Once you have this information, you can then go to your 2D rendering, and have a separate depth image you write to at the same time you write to your rendered image. For each pixel you are rendering your texture to, check if the value in the depth buffer is closer than the currently being written value (you should have a texture, depth pair at thispoint) if it is, don't write the color value out. Continue this for every image with depth.

Note In openg, vulkan, webgl, any of the other APIs, this is taken care of automatically in 3d rendering. Cocos does have shader support where this can be easier to manage if you have the depth information. Cocos may have 3D support, but i'm not sure to what extent, the documentation is very light on it.

Such a shader would look like this (I can't tell whether Cocos uses opengl ES 3.1 or not, which uses a newer shader version, but I'll be using similar syntax here) (note in opengl there are issues with reading and writing to the same texture):

Vertex Shader

#version 300 es
// vertex points for texture drawn can replace this with generated coordinates if using glDrawArrays(...) with no attached vertex buffer https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDrawArrays.xhtml
in vec2 position_attribute;
in vec2 texture_coord_attributes;
in mat4 mvp_matrix;

out vec2 texture_coordinates
void main(){
    texture_coordinates = texture_coord_attributes
    gl_Position = mvp_matrix * vec4(position_attribute, 0.0,1.0);
}

Fragment Shader

#version 300 es
uniform vec3 texture position;
uniform sampler2D texture_depth;
uniform sampler2D texture_color;
uniform sampler2D current_depth_texture;
//location of first color output attachment
layout(location = 0) out vec4 render_color;
//location of second depth output attachment
layout(location = 1) out vec4 render_depth;

in vec2 texture_coordinates;
in vec2 screen_coordinates;

void main(){
    float depth = texture(depth, texture_coordinates).r;
    float current_depth = texture(current_depth_texture, screen_coordinates);
    if(depth < current_depth){
        render_depth = depth;
        render_color = texture(texture_color, texture_coordinates);
    }else{
        render_depth = current_depth;
    }
}

Of course, this can all be replicated on the CPU if you don't have access to these facilities for what ever reason.

\$\endgroup\$
-2
\$\begingroup\$

In Unity this would be very easy to do that, but my question is, do you have actual 3d models? if yes, than you can go for orthographic projection and do what you want to do. No need to worry about the depth or masking. Even if you don't have 3d models, i would waste time in creating simple models and when everything will start working fine, than i will start playing with the shaders to make models look like how you wanted them to look like.

if you don't want to use unity, than you have to split your all images(assets) into tiles, and work like a tile game, or there's another possibility to swap images when they join.

If I were you, i would have done this using former approach.

\$\endgroup\$
1
  • \$\begingroup\$ He specified that he's using cocos creator \$\endgroup\$
    – Bálint
    Oct 30, 2019 at 9:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .