zoukankan      html  css  js  c++  java
  • creating normals from alpha/heightmap inside a shader

    http://www.polycount.com/forum/showthread.php?t=117185

    I am making some custom terrain shaders with strumpy's editor and I want to be able to create normals based on my blend mask. Does anyone know how I can turn grayscale data into basic normal mapping info? I have seen someone do this in unreal but I can't remember where.

    You probably want to get the difference of the values pixel-by-pixel using ddx, I think.

    Off the top of my head... for CG/HLSL;

    float heightmap = your height map value;
    float3 normal;
    normal.x = ddx(heightmap);
    normal.y = ddy(heightmap);
    normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y); // Reconstruct z component to get a unit normal.

    For OpenGL, I think the functions are dFdx and dFdy.

    DirectX11 has ddx_fine and ddy_fine which I think give more accurate results.


    That'll give you the normal in, ehr... screen space I think?

    Otherwise you can sample the heightmap multiple times, offsetting it by a pixel and working out the difference from those values. That should get you it in whatever space the base normal is in.

    Nicked frm here; http://www.gamedev.net/topic/594781-...mal-algorithm/

    float me = tex2D(heightMapSampler,IN.tex).x;
    float n = tex2D(heightMapSampler,float2(IN.tex.x,IN.tex.y+1.0/heightMapSizeY)).x;
    float s = tex2D(heightMapSampler,float2(IN.tex.x,IN.tex.y-1.0/heightMapSizeY)).x;
    float e = tex2D(heightMapSampler,float2(IN.tex.x+1.0/heightMapSizeX,IN.tex.y)).x;
    float w = tex2D(heightMapSampler,float2(IN.tex.x-1.0/heightMapSizeX,IN.tex.y)).x;                
    
    //find perpendicular vector to norm:        
    float3 temp = norm; //a temporary vector that is not parallel to norm
    if(norm.x==1)
        temp.y+=0.5;
    else
        temp.x+=0.5;
    
    //form a basis with norm being one of the axes:
    float3 perp1 = normalize(cross(norm,temp));
    float3 perp2 = normalize(cross(norm,perp1));
    
    //use the basis to move the normal in its own space by the offset        
    float3 normalOffset = -bumpHeightScale*(((n-me)-(s-me))*perp1 + ((e-me)-(w-me))*perp2);
    norm += normalOffset;
    norm = normalize(norm);

    Gave it a try out of curiosity.

    Here's the multi-sample method in a stripped-down surface shader.

    I had to change the handedness from the code above to match Unity (changing the sign of the operation when sampling the e and w values from + to - and vice versa).

    Shader "Debug/Normal Map From Height" {
        Properties {
            _Color ("Main Color", Color) = (1,1,1,1)
            _MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "white" {}
            _BumpMap ("Normal (Normal)", 2D) = "bump" {}
            _HeightMap ("Heightmap (R)", 2D) = "grey" {}
            _HeightmapStrength ("Heightmap Strength", Float) = 1.0
            _HeightmapDimX ("Heightmap Width", Float) = 2048
            _HeightmapDimY ("Heightmap Height", Float) = 2048
        }
    
        SubShader{
            Tags { "RenderType" = "Opaque" }
    
            CGPROGRAM
    
                #pragma surface surf NormalsHeight
                #pragma target 3.0
    
                struct Input
                {
                    float2 uv_MainTex;
                };
    
                sampler2D _MainTex, _BumpMap, _HeightMap;
                float _HeightmapStrength, _HeightmapDimX, _HeightmapDimY;
    
                void surf (Input IN, inout SurfaceOutput o)
                {
                    o.Albedo = fixed3(0.5);
    
                    float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    
                    float me = tex2D(_HeightMap,IN.uv_MainTex).x;
                    float n = tex2D(_HeightMap,float2(IN.uv_MainTex.x,IN.uv_MainTex.y+1.0/_HeightmapDimY)).x;
                    float s = tex2D(_HeightMap,float2(IN.uv_MainTex.x,IN.uv_MainTex.y-1.0/_HeightmapDimY)).x;
                    float e = tex2D(_HeightMap,float2(IN.uv_MainTex.x-1.0/_HeightmapDimX,IN.uv_MainTex.y)).x;
                    float w = tex2D(_HeightMap,float2(IN.uv_MainTex.x+1.0/_HeightmapDimX,IN.uv_MainTex.y)).x;
    
                    float3 norm = normal;
                    float3 temp = norm; //a temporary vector that is not parallel to norm
                    if(norm.x==1)
                        temp.y+=0.5;
                    else
                        temp.x+=0.5;
    
                    //form a basis with norm being one of the axes:
                    float3 perp1 = normalize(cross(norm,temp));
                    float3 perp2 = normalize(cross(norm,perp1));
    
                    //use the basis to move the normal in its own space by the offset
                    float3 normalOffset = -_HeightmapStrength * ( ( (n-me) - (s-me) ) * perp1 + ( ( e - me ) - ( w - me ) ) * perp2 );
                    norm += normalOffset;
                    norm = normalize(norm);
    
                    o.Normal = norm;
                }
    
                inline fixed4 LightingNormalsHeight (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
                {
                    viewDir = normalize(viewDir);
                    lightDir = normalize(lightDir);
                    s.Normal = normalize(s.Normal);
                    float NdotL = dot(s.Normal, lightDir);
                    _LightColor0.rgb = _LightColor0.rgb;
    
                    fixed4 c;
                    c.rgb = float3(0.5) * saturate ( NdotL ) * _LightColor0.rgb * atten;
                    c.a = 1.0;
                    return c;
                }
    
            ENDCG
        }
        FallBack "VertexLit"
    }

    Derivative method works, but it's fucking ugly 'cause it's in screen space - really noisy.

    ddx_fine might give better results in DX11, but it looks like crap in DX9.

  • 相关阅读:
    记录wordpress+nginx配置的坑
    Nginx进行反向代理多个web项目
    Docker 安装 Zabbix-4
    小特跨境电商ERP 小程序版 库存好帮手
    小特跨境电商ERP 浏览器版 为决策者提供数据支持
    小特跨境电商ERP桌面版 8.如何部署 真的这么难安装吗?
    小特跨境电商ERP桌面版 7.销售订单毛利计算 就是这么简单
    小特跨境电商ERP桌面版 6.运费结算是个大问题?容易一团糟
    小特跨境电商ERP桌面版 5.订单发货提交后,后续还要做什么?
    小特跨境电商ERP桌面版 4.平台商品和本地单品如何映射?
  • 原文地址:https://www.cnblogs.com/pulas/p/3867931.html
Copyright © 2011-2022 走看看