Jump to content
  • Advertisement
Sign in to follow this  
bandages

3D What are the advantages of creating normal maps the hard way?

Recommended Posts

I've built some simple normal maps out of meshes and a custom HLSL shader that writes their normals to the screen.  While I've only used this for creating tiling normal maps, where I control the orientation of the mesh used to generate normals, I don't see why I couldn't do this for a full-model normal map, placing the models in screen space based on their UV rather than world-space coords, writing the normals of the low-poly to one image, the high-poly to another, and the vector necessary to transform the normals of the first to the second onto a third image.  With the tiling normal maps I've made, I haven't seen any artifacts or weirdnesses.  All it takes is one or two models, a relatively simple shader, and a single frame of computer time.

But when I visit modelling sites, baking normals sounds like a major headache, involving the creation of a cage and a lengthy bake process.  It sounds like the modelling packages are using some kind of raycasting algorithm.

There must be a reason not to be doing things the way that I've been doing them.  Can anyone explain to me the problems with creating normal maps via shader?

Share this post


Link to post
Share on other sites
Advertisement

I don't exactly understand the method you are using... but I am guessing is very constrained to your specific use case, like a plane as a low poly version on a more detailed displaced version of it in just one axis. In the general case, the low poly and high poly models don´t have the same topology, and thus, they don´t share the same uv space... in fact, many times the high poly version of a model isn´t even uv unwrapped.

Share this post


Link to post
Share on other sites

I've done normal maps the way you describe, and it does have its uses. However, baking normal maps is a mapping process, mapping from high-detail geometry to low detail geometry. In the case of baking a tiling planar normal map, you are going from high-detail geometry arrayed on a plane, to a plane. It's a pretty easy mapping, 1 to 1 with the XY coordinates of a particular location on the plane. A given feature simply projects directly to the plane 'below' it. When baking an arbitrary mesh, however, then it's not so simple. In this case, you need to find the point on the high-detail poly mesh that most directly corresponds with a given point on the low-detail poly mesh. This involves projecting onto the surface of the high-poly, and this projection is NOT a simple projection onto a 2D plane. Once you advance to that level of complication, it's much easier to do the work in a 3D package. Not to say that it CAN'T be done in your own way, just that the math and logistics become a LOT more complex.

Share this post


Link to post
Share on other sites

Thanks for your responses, I think I understand better now.

 

It sounds like it should be acceptable-- it's nice to know that some awful artifact isn't going to jump out at me-- and the real issue is matching UV coords, matching corresponding points/spaces.  There are certainly situations where this is easy via UV correspondence, like if your high poly is just a subdivided low poly, it seems like it would be trivial; what I was doing with planes was trivial.  But I can see now how there are situations where it wouldn't be trivial.

Share this post


Link to post
Share on other sites

Yes, if the high poly is made by subdividing the low poly then it's not too difficult to bake yourself. You can build a workflow that ensures that. Some tools, however, allow dynamic subdivision while sculpting (see something like Sculptris, or Blender's dynamic subdiv). This allows more mesh detail in areas that need it, but can break the relationship between the high poly and low poly. If your workflow includes this, then the math becomes more difficult.

 

Additionally, I feel like you overstate the difficulty in using a 3d tool to bake normal maps. Tutorial videos make it seem more difficult than it really is. Once you understand the process, it can be a very quick thing. The actual baking setup and bake can take mere minutes.

 

Even for tiling textures, I now prefer Blender rather than my own older hand-tooled processes: 

 

Having access to all the other tools of a general purpose 3d tool makes all the difference.

Share this post


Link to post
Share on other sites

Thanks, that's easy to believe, and useful to know.  I actually made my own shader to bake lighting/mats/etc to textures in-engine before I discovered that in reality, there was nearly no difficulty involved in Blender baking.  So I can imagine the same is true with normals too.  (But, it wasn't bad HLSL practice either, not a bad way to get more comfortable with the concepts, not something I regret doing.)  So much just seems to be about finding the time to learn it, when there's so much to be learned, and difficult to know beforehand what's going to be hard to learn and what's going to be easy.

Share this post


Link to post
Share on other sites

You've implemented a baker ;)

You're using a 2D cage in texture space and require the artist to exactly map both meshes onto that cage.

Other methods change the workflow for the artist, such as not requiring UVs at all on the high poly 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By Gregory Aaron Martin
      I'm writing a sprawling fantasy series. I've written shorter stories in the world I'm creating. I want to turn one of those short stories into a game. It can be 2D. It's about dragons. There's a story arc below that shows a starting point and an ending point. Details will be given if there's anyone interested. I'm a storyteller but I don't have much knowledge on game development.
       
      Synopsis: A young man with a very special gift returns to his mountainous home to find it invaded by a cult. The community he's been a part of his whole life has been cut off by the king to ensure the cult's influence remains limited as it's very influential. This cult believes the dragon they follow and worship rests in the mountains and with the king pulling his soldiers out, the cult can begin its dig underground. The young man learns that the last individual with the same special gift who held a coveted seat on the council was killed by the cult during the cult's takeover of the village community. The young man, like others with the same special ability as him, vied for the seat on the council but he was turned away either for his own safety or because of council secrets. The cult has its own members with this same special ability and they're very intimidating. The community is oppressed for months. Tired of this oppression and feeling abandoned by his king, the young man sets out with a few new comrades to battle this cult, putting on display his own talent with this special gift.They make it their mission to sabotage the cult's dig into the mountains in hopes the cult doesn't awaken their dragon. They also make it their mission to defeat the cult members who posses the special ability. They are successful with this and he is appointed to the coveted seat on the council. 
       
      Thanks
    • By cozzie
      Hi guys,
      I've been struggling to create a function to draw an arrow with 2 lines making up the arrowhead.
      The challenge is that I somehow can't get the rotation right.
      I've pasted the code below and an image of the result.
      Findings so far, when I replace the 3x3 part of the transform matrix to identity, I get the same visual result.
      Also when I switch colums A and C in the matrix, this specific arrow looks good (with is pointing in the positive X direction).
      Any input would be appreciated.
      bool CDebugDraw::AddArrow(const CR_VECTOR3 &pPos1, const CR_VECTOR3 &pPos2, const CR_VECTOR3 &pColor, const bool pDepthEnabled, const bool pPersistent, const uint64_t pLifeTime) { if(!AddLine(pPos1, pPos2, pColor, pDepthEnabled, pPersistent, pLifeTime)) return false; /* p1 ------- X / | \ | / | \ | / | \ | p2 -----|-----p3 | Z | | | | p0 */ CR_VECTOR3 arrowDir = pPos2 - pPos1; arrowDir.Normalize(); // model space CR_VECTOR3 p1 = CR_VECTOR3(0.0f, 0.0f, 0.0f); CR_VECTOR3 p2 = CR_VECTOR3(0.2f, 0.0f, -0.2f); CR_VECTOR3 p3 = CR_VECTOR3(-0.2f, 0.0f, -0.2f); // transformation: translate and rotate CR_VECTOR3 transl = pPos2; CR_VECTOR3 colA = arrowDir; CR_VECTOR3 tVec; if(colA.x != 0 && colA.z != 0) tVec = CR_VECTOR3(0.0f, 1.0f, 0.0); else tVec = CR_VECTOR3(0.0f, 0.0f, 1.0f); CR_VECTOR3 colB = CMathHelper::CrossVec3(colA, tVec); CR_VECTOR3 colC = CMathHelper::CrossVec3(colB, colA); CR_MATRIX4X4 transform; transform.m11 = colA.x; transform.m12 = colB.x; transform.m13 = colC.x; transform.m14 = 0.0f; transform.m21 = colA.y; transform.m22 = colB.y; transform.m23 = colC.y; transform.m24 = 0.0f; transform.m31 = colA.z; transform.m32 = colB.z; transform.m33 = colC.z; transform.m34 = 0.0f; transform.m41 = transl.x; transform.m42 = transl.y; transform.m43 = transl.z; transform.m44 = 1.0f; // transform = CMathHelper::ComposeWorldMatrix(transform, CR_VECTOR3(1.0f), CR_VECTOR3(0.0f, 90.0f, 0.0f), pPos2); // transform to worldspace p1 = CMathHelper::TransformVec3Coord(p1, transform); p2 = CMathHelper::TransformVec3Coord(p2, transform); p3 = CMathHelper::TransformVec3Coord(p3, transform); if(!AddLine(p1, p2, CR_VECTOR3(1.0f, 0.0f, 0.0f), pDepthEnabled, pPersistent, pLifeTime)) return false; if(!AddLine(p1, p3, CR_VECTOR3(1.0f, 0.0f, 0.0f), pDepthEnabled, pPersistent, pLifeTime)) return false; if(!AddCross(p2, 0.02f, CR_VECTOR3(0.0f, 0.0f, 1.0f), pDepthEnabled, pPersistent, pLifeTime)) return false; if(!AddCross(p3, 0.02f, CR_VECTOR3(0.0f, 0.0f, 1.0f), pDepthEnabled, pPersistent, pLifeTime)) return false; return true; } Incorrect result:

      Aimed/ correct result (independent of arrow direction):

    • By NanaMarfo
      Hello Everyone!
      I am looking for a small team to do a rendering project with me. The roles I need are:
      -Character Modeller
      -Environment Designer
      -Environment Modeller(Found)
      You can use this in your portfolio and you will be credited at the end.
      If you are interested, please email me at marfo343@gmail.com. Thank you!
    • By D34DPOOL
      Edit Your Profile D34DPOOL 0 Threads 0 Updates 0 Messages Network Mod DB GameFront Sign Out Add jobEdit jobDeleteC# Programmer for a Unity FPS at Anywhere   Programmers located Anywhere.
      Posted by D34DPOOL on May 20th, 2018
      Hello, my name is Mason, and I've been working on a Quake style arena shooter about destroying boxes on and off for about a year now. I have a proof of concept with all of the basic features, but as an artist with little programming skill I've reached the end of my abilities as a programmer haha. I need someone to help fix bugs, optomize code, and to implent new features into the game. As a programmer you will have creative freedom to suggest new features and modes to add into the game if you choose to, I'm usually very open to suggestions :).
      What is required:
      Skill using C#
      Experience with Unity
      Experience using UNET (since it is a multiplayer game), or the effort and ability to learn it
      Compensation:
      Since the game currently has no funding, we can split whatever revenue the game makes in the future. However if you would perfer I can create 2D and/or 3D assets for whatever you need in return for your time and work.
      It's a very open and chill enviornment, where you'll have relative creative freedom. I hope you are interested in joining the team, and have a good day!
       
      To apply email me at mangemason@yahoo.com
    • By Andrew Parkes
      I am a talented 2D/3D artist with 3 years animation working experience and a Degree in Illustration and Animation. I have won a world-wide art competition hosted by SFX magazine and am looking to develop a survival game. I have some knowledge of C sharp and have notes for a survival based game with flexible storyline and PVP. Looking for developers to team up with. I can create models, animations and artwork and I have beginner knowledge of C sharp with Unity. The idea is Inventory menu based gameplay and is inspired by games like DAYZ.
      Here is some early sci-fi concept art to give you an idea of the work level. Hope to work with like minded people and create something special. email me andrewparkesanim@gmail.com.
      Developers who share the same passion please contact me, or if you have a similar project and want me to join your team email me. 
      Many thanks, Andrew.

    • By thecheeselover
      I made this post on Reddit. I need ideas and information on how to create the ground mesh for my specifications.
    • By Canadian Map Makers
      GOVERNOR is a modernized version of the highly popular series of “Caesar” games. Our small team has already developed maps, written specifications, acquired music and performed the historical research needed to create a good base for the programming part of the project.

      Our ultimate goal is to create a world class multi-level strategic city building game, but to start with we would like to create some of the simpler modules to demonstrate proof of concept and graphical elegance.

       

      We would like programmers and graphical artists to come onboard to (initially) create:

      A module where Province wide infrastructure can be built on an interactive 3D map of one of the ancient Roman Provinces.
      A module where city infrastructure can be built on a real 3D interactive landscape.
      For both parts, geographically and historically accurate base maps will be prepared by our team cartographer. Graphics development will be using Blender. The game engine will be Unity.

       

      More information, and examples of the work carried out so far can be found at http://playgovernor.com/ (most of the interesting content is under the Encyclopedia tab).

       

      This project represents a good opportunity for upcoming programmers and 3D modeling artists to develop something for their portfolios in a relatively short time span, working closely with one of Canada’s leading cartographers. There is also the possibility of being involved in this project to the point of a finished game and commercial success! Above all, this is a fun project to work on.

       

      Best regards,

      Steve Chapman (Canadian Map Makers)

       
    • By RobMaddison
      Hi
      I’ve been working on a game engine for years and I’ve recently come back to it after a couple of years break.  Because my engine uses DirectX9.0c I thought maybe it would be a good idea to upgrade it to DX11. I then installed Windows 10 and starting tinkering around with the engine trying to refamiliarise myself with all the code.
      It all seems to work ok in the new OS but there’s something I’ve noticed that has caused a massive slowdown in frame rate. My engine has a relatively sophisticated terrain system which includes the ability to paint roads onto it, ala CryEngine. The roads are spline curves and built up with polygons matching the terrain surface. It used to work perfectly but I’ve noticed that when I’m dynamically adding the roads, which involves moving the spline curve control points around the surface of the terrain, the frame rate comes to a grinding halt.
      There’s some relatively complex processing going on each time the mouse moves - the road either side of the control point(s) being moved, is reconstructed in real time so you can position and bend the road precisely. On my previous OS, which was Win2k Pro, this worked really smoothly and in release mode there was barely any slow down in frame rate, but now it’s unusable. As part of the road reconstruction, I lock the vertex and index buffers and refill them with the new values so my question is, on windows 10 using DX9, is anyone aware of any locking issues? I’m aware that there can be contention when locking buffers dynamically but I’m locking with LOCK_DISCARD and this has never been an issue before.
      Any help would be greatly appreciated.
    • By MikhailGorobets
      I have a problem with SSAO. On left hand black area.
      Code shader:
      Texture2D<uint> texGBufferNormal : register(t0); Texture2D<float> texGBufferDepth : register(t1); Texture2D<float4> texSSAONoise : register(t2); float3 GetUV(float3 position) { float4 vp = mul(float4(position, 1.0), ViewProject); vp.xy = float2(0.5, 0.5) + float2(0.5, -0.5) * vp.xy / vp.w; return float3(vp.xy, vp.z / vp.w); } float3 GetNormal(in Texture2D<uint> texNormal, in int3 coord) { return normalize(2.0 * UnpackNormalSphermap(texNormal.Load(coord)) - 1.0); } float3 GetPosition(in Texture2D<float> texDepth, in int3 coord) { float4 position = 1.0; float2 size; texDepth.GetDimensions(size.x, size.y); position.x = 2.0 * (coord.x / size.x) - 1.0; position.y = -(2.0 * (coord.y / size.y) - 1.0); position.z = texDepth.Load(coord); position = mul(position, ViewProjectInverse); position /= position.w; return position.xyz; } float3 GetPosition(in float2 coord, float depth) { float4 position = 1.0; position.x = 2.0 * coord.x - 1.0; position.y = -(2.0 * coord.y - 1.0); position.z = depth; position = mul(position, ViewProjectInverse); position /= position.w; return position.xyz; } float DepthInvSqrt(float nonLinearDepth) { return 1 / sqrt(1.0 - nonLinearDepth); } float GetDepth(in Texture2D<float> texDepth, float2 uv) { return texGBufferDepth.Sample(samplerPoint, uv); } float GetDepth(in Texture2D<float> texDepth, int3 screenPos) { return texGBufferDepth.Load(screenPos); } float CalculateOcclusion(in float3 position, in float3 direction, in float radius, in float pixelDepth) { float3 uv = GetUV(position + radius * direction); float d1 = DepthInvSqrt(GetDepth(texGBufferDepth, uv.xy)); float d2 = DepthInvSqrt(uv.z); return step(d1 - d2, 0) * min(1.0, radius / abs(d2 - pixelDepth)); } float GetRNDTexFactor(float2 texSize) { float width; float height; texGBufferDepth.GetDimensions(width, height); return float2(width, height) / texSize; } float main(FullScreenPSIn input) : SV_TARGET0 { int3 screenPos = int3(input.Position.xy, 0); float depth = DepthInvSqrt(GetDepth(texGBufferDepth, screenPos)); float3 normal = GetNormal(texGBufferNormal, screenPos); float3 position = GetPosition(texGBufferDepth, screenPos) + normal * SSAO_NORMAL_BIAS; float3 random = normalize(2.0 * texSSAONoise.Sample(samplerNoise, input.Texcoord * GetRNDTexFactor(SSAO_RND_TEX_SIZE)).rgb - 1.0); float SSAO = 0; [unroll] for (int index = 0; index < SSAO_KERNEL_SIZE; index++) { float3 dir = reflect(SamplesKernel[index].xyz, random); SSAO += CalculateOcclusion(position, dir * sign(dot(dir, normal)), SSAO_RADIUS, depth); } return 1.0 - SSAO / SSAO_KERNEL_SIZE; }  



    • By Ike aka Dk
      Hello everyone 
      I am a programmer from Baku.
      I need a 3D Modeller for my shooter project in unity.I have 2 years Unity exp.
      Project will paid when we finish the work 
      If you interested write me on email:
      mr.danilo911@gmail.com
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631400
    • Total Posts
      2999860
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!