Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Qdot543 · Nov 03, 2014 at 05:47 AM · shaderrangecgpoint light

CG Programming, Points Lights attenuation and light range

The image below is showing what is happening. I'm simply trying to write a shader that does diffuse and specular lighting. I'm following this tutorial.

However I noticed that for diffuse, it doesn't take range into account, and doesn't behave exactly like the default shader in unity. And we have the edges shown below. I don't know how to actually access the range information so i'm stuck. I've searched, but I have not found any good documentation that tells me how to avoid this. Basically what should I do to fix this.

alt text

Herese my messy shader code :

 Shader "Custom/LightMap Blend Diffuse Specular Transparency" {
     Properties {
         _Color ("MainColor", Color) = (1, 1, 1, 1)
         _SpecColor ("Specular Color", Color) = (1, 1, 1, 1)
         _Shininess ("Shininess", Float) = 10
         _MainTex ("Base (RGB)", 2D) = "white" {}
         _LightMap01 ( "LightMap 1", 2D ) = "white" {}
         _LightMap02 ( "LightMap 2", 2D ) = "white" {}
         _Trans ("Transparency", Range(0, 1)) = 0
     }
     SubShader {
         Tags { "RenderType"="Opaque" }
         LOD 200
         
         Pass
         {
             Tags { "LightMode" = "ForwardBase" } 
         
             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
 
             uniform float4 _LightColor0;
 
             sampler2D _MainTex;
             
             float4 _Color;
             float4 _SpecColor;
             float _Shininess;
             
             struct vertexIn
             {
                 float4 pos : POSITION;
                 float3 norm : normal;
             };
         
             struct vertexOut
             {
                 float4 pos : SV_POSITION;
                 float4 col : COLOR;
                 float3 posWorld : TEXCOORD0;
                 float3 norm : TEXCOORD1;
             };
                 
             vertexOut vert(vertexIn i)
             {
                 vertexOut o;
                 
                                     
                 float4x4 modelMatrix = _Object2World;
                 float4x4 modelMatrixInverse = _World2Object;
                 
                 o.posWorld = mul(modelMatrix, i.pos); 
                 o.norm = normalize( mul(float4(i.norm, 0), modelMatrixInverse).xyz );
                 o.col = float4 (0, 0, 0, 0);
                 o.pos = mul( UNITY_MATRIX_MVP, i.pos);
                 
                 return o;
             }
             
             float4 frag(vertexOut o) : COLOR
             {
                 float3 normalDirection = normalize(o.norm);
                 float3 viewDirection = normalize(_WorldSpaceCameraPos - o.posWorld.xyz);
                 float3 lightDirection = float3(0, 0, 0);
                 float attenuation;
 
                 lightDirection =  normalize(_WorldSpaceLightPos0.xyz) * (1 - _WorldSpaceLightPos0.w);
                         
                 float3 PointLightDirection = _WorldSpaceLightPos0.xyz - o.posWorld.xyz;
                 float PointLightLength = length(PointLightDirection);
                 
                 lightDirection += normalize(PointLightDirection) * _WorldSpaceLightPos0.w;
                 
                 attenuation = 1.0 / PointLightLength;
 
                 float3 diffuseColor = lerp(_LightColor0.rgb * _Color.rgb * max(0, dot(normalDirection, lightDirection)), 
                                            _LightColor0.rgb * _Color.rgb * max(0, dot(normalDirection, lightDirection) * attenuation), _WorldSpaceLightPos0.w);
 
                 float3 specularColor = (_LightColor0.rgb * _Color.rgb * max(0, dot(reflect(-lightDirection, normalDirection), viewDirection)) ) 
                                         * max(0, dot (normalDirection,  lightDirection));
                 
                 
                 return float4((UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb) + diffuseColor, 1);
             }
             
             ENDCG
         }
         
         Pass
         {
             Tags { "LightMode" = "ForwardAdd" } 
         
             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
 
             uniform float4 _LightColor0;
 
             sampler2D _MainTex;
             
             float4 _Color;
             float4 _SpecColor;
             float _Shininess;
             
             struct vertexIn
             {
                 float4 pos : POSITION;
                 float3 norm : normal;
             };
         
             struct vertexOut
             {
                 float4 pos : SV_POSITION;
                 float4 col : COLOR;
                 float3 posWorld : TEXCOORD0;
                 float3 norm : TEXCOORD1;
             };
                 
             vertexOut vert(vertexIn i)
             {
                 vertexOut o;
                 
                                 
                 
                 float4x4 modelMatrix = _Object2World;
                 float4x4 modelMatrixInverse = _World2Object;
                 
                 o.posWorld = mul(modelMatrix, i.pos); 
                 o.norm = normalize( mul(float4(i.norm, 0), modelMatrixInverse).xyz );
                 o.col = float4 (0, 0, 0, 0);
                 o.pos = mul( UNITY_MATRIX_MVP, i.pos);
                 
                 return o;
             }
             
             float4 frag(vertexOut o) : COLOR
             {
                 float3 normalDirection = normalize(o.norm);
                 float3 viewDirection = normalize(_WorldSpaceCameraPos - o.posWorld.xyz);
                 float3 lightDirection = float3(0, 0, 0);
                 float attenuation;
 
                 lightDirection =  normalize(_WorldSpaceLightPos0.xyz) * (1 - _WorldSpaceLightPos0.w);
                         
                 float3 PointLightDirection = _WorldSpaceLightPos0.xyz - o.posWorld.xyz;
                 float PointLightLength = length(PointLightDirection);
                 
                 lightDirection += normalize(PointLightDirection) * _WorldSpaceLightPos0.w;
                 
                 attenuation = 1.0 / PointLightLength;
 
                 float3 diffuseColor = lerp(_LightColor0.rgb * _Color.rgb * max(0, dot(normalDirection, lightDirection)), 
                                            _LightColor0.rgb * _Color.rgb * max(0, dot(normalDirection, lightDirection) * attenuation), _WorldSpaceLightPos0.w);
 
 
                 float3 specularColor = (_LightColor0.rgb * _Color.rgb * max(0, dot(reflect(-lightDirection, normalDirection), viewDirection)) ) 
                                         * max(0, dot (normalDirection,  lightDirection));
                 
                 
                 return float4( (UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb) + diffuseColor, 1);
             }
             
             ENDCG
         }
         
     } 
     FallBack "Diffuse"
 }   

by the way. I'm also calculating specular, but I'm not using the values in the output, because I wanted to isolate diffuse, which is why my code is a mess.

shaderimage.png (37.5 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
3

Answer by CHPedersen · Nov 03, 2014 at 08:46 AM

You've almost got your own question answered in the topic. :)

It's all about light range and implementing attenuation.

Attenuation is the highlight's size as a function of distance between light and pixel. So, to calculate it, you obviously need access to the light's position. There are three ways to go about that:

1:

You can implement your shaders as surface shaders instead of native vert/frag pairs. Surface shaders are compiled by Unity into native vert/frag pairs in ways that utilize Unity's built-in complex lighting engine, so you don't have to worry about it. This comes at the cost of some coding flexibility, though surface shaders still do allow quite a bit of customization, including your own vertex shader.

2:

You can stick to a native vert/frag pair as in the above, and then try to tap into the built-in variables Unity's internal engine passes to the shader system each frame, so your custom vert/frag pair accesses the same variables Unity's own vert/frag pairs would do after its compiler makes vert/frag pairs out of surface shaders. These variables are mostly defined in UnityCG.cginc, Lighting.cginc and UnityShaderVariables.cginc, which can be found at this path:

C:/"Program Files (x86)/Unity/Editor/Data/CGIncludes

For example in UnityShaderVariables.cginc, you'll find these declarations for what I believe to be the real-time positions of the 8 nearest light sources to each object:

 float4 unity_LightColor[8];
 float4 unity_LightPosition[8];
 // x = -1
 // y = 1
 // z = quadratic attenuation
 // w = range^2
 float4 unity_LightAtten[8];
 float4 unity_SpotDirection[8];

3:

You can ignore Unity's built-in lighting engine altogether, and transfer the needed variables yourself. This means you have to identify the light sources you want to calculate lighting for in C# yourself, and then transfer all of their data manually, including its position, light color, intensity, range, etc. You must declare your own variables to hold the data in your shader, and then you must set the value of these variables on the CPU side using Material.SetFloat, Material.SetColor and Material.SetVector respectively. (Or the static versions found in the Shader class, if you want them to be globally available to all shaders).

Having done that, the real world, physically correct equation for standard light attenuation is 1/d^2, where d is the distance to the light source. But that doesn't always suit 3D graphics well. There is a more elaborate formula for this in the Cg tutorial here, if you're interested (Chapter 5.5.1):

http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter05.html

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Qdot543 · Nov 04, 2014 at 04:49 AM 0
Share

Thank your your replie. I going to use the second method. I know I'm going to unity_LightAtten. However I'm still confused on how to use it. I've tried using the the code in the tutorial on multiple point lights. However it still had the edges, and the light still didn't scale with range. The tutorial implies that I loop through the light values in the forward base pass, however that doesn't work, and its confusing because the lights are processed in the forward add pass. If you know what I should do next could you please post it. $$anonymous$$y code is below in pastebin.

http://pastebin.com/4Frcxuwz

avatar image
2

Answer by FluFFey · Oct 26, 2017 at 05:43 AM

UnityShaderVariables.cginc has the built-in variable float4 _LightPositionRange, where xyz = pos and w = (1/range). From this you get

float attenuation = 1-(distanceToLight / (1 / _LightPositionRange.w)) ;

Which gives a smooth transition and also works for ForwardAdd passes. You can find the distance by

_WorldSpaceLightPos0.xyz-posWorld.xyz;

You only need to include "AutoLight.cginc" for both _LightPositionRange and _WorldSpaceLightPos0. Found little info on this elsewhere so hope this helps someone.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Optimus6128 · Apr 02, 2015 at 12:42 PM

I have the same problem. Writing my own cg shaders for lighting. Want to get the light range so that I can calculate attenuation on my own. Or get attenuation. Any of two.

I debug in the shader by painting my pixels with some of the values. I realized this. unity_LightAtten does not update the range. The X = -1, Y = 1, Z = 0 and W = 1 No matter if I change the range to 0.5, 0.25 or 2 or 4 or whatever.

When I try to update other values like position or color, they don't seem to change when I move lightsource or change it's color. It seems like these are the original initialized values and nothing else is happening. Like Unity is not passing them unless I would write surface shaders which I don't want to. The third option would be to attach to my objects a C# code that simple reads the range and sends it as a uniform. I want to avoid this. Also what if I have different lights with different ranges?

I will continue to investigate this, but somehow some solutions to this are so hard to find (I searched for tutorials for hours).

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Accessing light's range value within a fragment shader? 0 Answers

What is the proper way of calculating attentuation in Unity3D non-surface shaders? 0 Answers

How to force the compilation of a shader in Unity? 5 Answers

Shader: get nearest point light's color, direction and general custom lighting questions 0 Answers

UnityObjectToClipPos is inverted? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges