How to write the texture() function from ShaderToy to Metal shading language? - swift

I am working on a custom Metal shader, and I am trying to replicate this particular effect from shader toy: https://www.shadertoy.com/view/3sfcR2
But I can't seem to understand how to convert their texture() function to the Metal shader format. Any ideas?
Here's what I have so far in Metal:
#include <metal_stdlib>
using namespace metal;
kernel void chromaticAberration(texture2d<float, access::read> inTexture [[ texture(0) ]],
texture2d<float, access::write> outTexture [[ texture(1) ]],
device const float *time [[ buffer(0) ]],
uint2 gid [[ thread_position_in_grid ]])
{
float ChromaticAberration = 0.0 / 10.0 + 8.0;
// get the width and height of the screen texture
uint width = outTexture.get_width();
uint height = outTexture.get_height();
// set its resolution
float2 iResolution = float2(width, height);
float4 orig = inTexture.read(gid);
float2 uv = orig.xy / iResolution.xy;
float2 texel = 1.0 / iResolution.xy;
float2 coords = (uv - 0.5) * 2.0;
float coordDot = dot (coords, coords);
float2 precompute = ChromaticAberration * coordDot * coords;
float2 uvR = uv - texel.xy * precompute;
float2 uvB = uv + texel.xy * precompute;
// How to convert these texture() functions?
float r = texture(iChannel0, uvR).r;
float g = texture(iChannel0, uv).g;
float b = texture(iChannel0, uvB).b;
float a = 1.;
const float4 colorAtPixel = float4(r,g,b,1.0);
outTexture.write(colorAtPixel, gid);
}
EDIT:
Following the answer of #JustSomeGuy I was able to successfully replicate this shader in Metal. Here is the final version:
#include <metal_stdlib>
using namespace metal;
kernel void chromaticAberration(texture2d<float, access::read> inTexture [[ texture(0) ]],
texture2d<float, access::write> outTexture [[ texture(1) ]],
texture2d<float, access::sample> sampleTexture [[ texture(2) ]],
device const float *time [[ buffer(0) ]],
uint2 gid [[ thread_position_in_grid ]])
{
float ChromaticAberration = 0.0 / 10.0 + 8.0;
// get the width and height of the screen texture
uint width = inTexture.get_width();
uint height = inTexture.get_height();
// set its resolution
float2 iResolution = float2(width, height);
float2 uv = float2(gid) / iResolution.xy;
float2 texel = 1.0 / iResolution.xy;
float2 coords = (uv - 0.5) * 2.0;
float coordDot = dot (coords, coords);
float2 precompute = ChromaticAberration * coordDot * coords;
float2 uvR = uv - texel.xy * precompute;
float2 uvB = uv + texel.xy * precompute;
constexpr sampler s(address::clamp_to_edge, filter::linear);
float r = sampleTexture.sample(s, uvR).r;
float g = sampleTexture.sample(s, uv).g;
float b = sampleTexture.sample(s, uvB).b;
const float4 colorAtPixel = float4(r,g,b,1.0);
outTexture.write(colorAtPixel, gid);
}
Kudos to #JustSomeGuy! Thank you for your help!

Well, I think ShaderToy uses glsl or some of it's variants, so texture function is basically a sample call in Metal. Let's look at an example. I'm using this doc. We'll use the 2D version since that's what you probably want.
gvec4 texture( gsampler2D sampler,
vec2 P,
[float bias]);
So in this case iChannel0 is your sampler and uvR, uv, uvB are texture coordinates (P). They should be float2.
So this is a global function that samples color for us from a sampler. In Metal, we have separate textures and samplers and you'll need both to sample. Also, in Metal sample is not a global function, but a member function of a texture2d. Let's look at Metal Language Specification, Section 6.10.3 "2D Texture". There we'll find a method:
Tv sample(sampler s, float2 coord, int2 offset = int2(0)) const
where Tv is the template parameter you have in your texture2d instantiation (probably half or float). It also takes a sampler and texcoords, so this code from your sample:
float r = texture(iChannel0, uvR).r;
float g = texture(iChannel0, uv).g;
float b = texture(iChannel0, uvB).b;
will turn into something like this:
constexpr sampler mySampler { filter::linear };
float r = iChannel0.sample(mySampler, uvR).r;
float g = iChannel0.sample(mySampler, uv).g;
float b = iChannel0.sample(mySampler, uvB).b;
And you will also need to pass texture2d<float> iChannel [[texture(N)]] (where N is the index you chose) to your shader the same way shadertoy does it (it's just a global var there, but in Metal you'd need to actually pass it as an argument).

Related

Swift metal, corner irregular shape

I am developing an application in which non-standard shapes need to be rounded
what I mean
non-standard rect
for rounding i do this ( Metal shader )
constant float2 c00s = float2(0.0, 0.0);
constant float2 c01s = float2(0.0, 1.0);
constant float2 c11s = float2(1.0, 1.0);
constant float2 c10s = float2(1.0, 0.0);
// Check if a point is within a given corner
bool in_cornerS(float2 p, float2 corner, float2 radius) {
// determine the direction we want to be filled
float2 axis = (c11s - corner) - corner;
// warp the point so we are always testing the bottom left point with the
// circle centered on the origin
p = p - (corner + axis * radius);
p *= axis / radius;
return (p.x > 0.0 && p.y > -1.0) || (p.y > 0.0 && p.x > -1.0) || dot(p, p) < 1.0;
}
bool test_rounded_maskS(float2 p, float2 corner_size00, float2 corner_size01, float2 corner_size11, float2 corner_size10) {
return
in_cornerS(p, c00s, corner_size00) &&
in_cornerS(p, c01s, corner_size01) &&
in_cornerS(p, c10s, corner_size11) &&
in_cornerS(p, c11s, corner_size10);
}
fragment float4 fragmentStencil(VertexIn vert [[stage_in]],
device const float2 *dimensions00 [[ buffer(0) ]],
device const float2 *dimensions01 [[ buffer(1) ]],
device const float2 *dimensions11 [[ buffer(2) ]],
device const float2 *dimensions10 [[ buffer(3) ]]) {
float2 a_uv = vert.texCoord;
float2 u_dimensions00 = *dimensions00;
float2 u_dimensions01 = *dimensions01;
float2 u_dimensions11 = *dimensions11;
float2 u_dimensions10 = *dimensions10;
if (!test_rounded_maskS(a_uv, u_dimensions00, u_dimensions01, u_dimensions11, u_dimensions10)) {
discard_fragment();
}
return float4(1.0,1.0,1.0,1.0);
}
i get this result
but I want this
how I can achieve this ?
Step 1: Follow install instructions for the Metal port of NanoVG.
Step 2: Prosper. You can now render vector shapes and paths. This will fill a path:
- (void)renderFillWithPaint:(NVGpaint*)paint
compositeOperation:(NVGcompositeOperationState)compositeOperation
scissor:(NVGscissor*)scissor
fringe:(float)fringe
bounds:(const float*)bounds
paths:(const NVGpath*)paths
npaths:(int)npaths;

How render 3D render texture in a Unity3D custom shader

Hi is it possible to render a 3d render texture on a custom shader raymarching like a 3dtexture?
I use a 3D render texture because I calculate and set the color of the 3D volume in a compute shader. I set the rendertexture 3D as shown below:
output3DRenderTexture= new RenderTexture(m_CubeDim.x, m_CubeDim.y, 0, thisTexFormat);
outpuoutput3DRenderTextureRendTex.enableRandomWrite = true;
output3DRenderTexture.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
output3DRenderTexture.volumeDepth = m_CubeDim.z;
output3DRenderTexture.Create();
I populate the 3D RenderTexture data in a a compute shader and GetData helps me confirm the 3d render texture has all the correct color data.
I can successfully render if I replace the 3D renderTex in the custom shader's sampler3D for a 3DTexture I create with the Tex2D slices.
cubeRenderer.material.SetTexture("_MainTex", output3DRenderTexture);//this does not render
versus
cubeRenderer.material.SetTexture("_MainTex", outputTexture3D);//this renders
This post in 2016 seems to suggest it's possible to render 3d render textures in custom shaders but it may now be outdated, it doesn't work for me and no error shows either.
It seems to me there maybe a significant performance hit if create the Textures2D slices in GPU, carry on with the creation of the Texture3D on CPU and re-send this Tex3D to GPU for the custom shader to consume it. After all the 3D volume already existed in GPU except as RenderTexture set as Tex3D. Thank you!
Shader:
#include "UnityCG.cginc"
#define ITERATIONS 100
#define PI2 6.28318530718
half4 _Color;
sampler3D _MainTex;
half _Intensity, _Threshold;
half3 _SliceMin, _SliceMax;
float4x4 _AxisRotationMatrix;
float _Angle;
struct Ray {
float3 origin;
float3 dir;
};
struct AABB {
float3 min;
float3 max;
};
// https http.download.nvidia.com/developer/presentations/2005/GDC/Audio_and_Slides/VolumeRendering_files/GDC_2_files/GDC_2005_VolumeRenderingForGames_files/Slide0073.htm
bool intersect(Ray r, AABB aabb, out float t0, out float t1)
{
float3 invR = 1.0 / r.dir;
float3 tbot = invR * (aabb.min - r.origin);
float3 ttop = invR * (aabb.max - r.origin);
float3 tmin = min(ttop, tbot);
float3 tmax = max(ttop, tbot);
float2 t = max(tmin.xx, tmin.yz);
t0 = max(t.x, t.y);
t = min(tmax.xx, tmax.yz);
t1 = min(t.x, t.y);
return t0 <= t1;
}
float3 get_uv(float3 p) {
return (p + 0.5);
}
float sample_volume(float3 uv, float3 p)
{
float v = tex3D(_MainTex, uv).r * _Intensity;
return v;
}
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 world : TEXCOORD1;
float3 local : TEXCOORD2;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.world = mul(unity_ObjectToWorld, v.vertex).xyz;
o.local = v.vertex.xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
Ray ray;
ray.origin = i.local;
// world space direction to object space
float3 dir = (i.world - _WorldSpaceCameraPos);
ray.dir = normalize(mul(unity_WorldToObject, dir));
AABB aabb;
aabb.min = float3(-0.5, -0.5, -0.5);
aabb.max = float3(0.5, 0.5, 0.5);
float tnear;
float tfar;
intersect(ray, aabb, tnear, tfar);
tnear = max(0.0, tnear);
// float3 start = ray.origin + ray.dir * tnear;
float3 start = ray.origin;
float3 end = ray.origin + ray.dir * tfar;
float dist = abs(tfar - tnear);
float step_size = dist / float(ITERATIONS);
float3 ds = normalize(end - start) * step_size;
float4 dst = float4(0, 0, 0, 0);
float3 p = start;
[unroll]
for (int iter = 0; iter < ITERATIONS; iter++)
{
float3 uv = get_uv(p);
float v = sample_volume(uv, p);
float4 src = float4(v, v, v, v);
src.a *= 0.5;
src.rgb *= src.a;
// blend
dst = (1.0 - dst.a) * src + dst;
p += ds;
if (dst.a > _Threshold) break;
}
return saturate(dst) * _Color;
}
#endif

Shader that transforms a mercator projection to equirectangular?

I am trying to make a shader in Unity taking a mercator projection texture as a source and converting it to an equirectangular projection texture.
Input example:
Output example:
This example does the opposite with an equirectangular as source.
If you look at the source of the above example:
// mercator
float latClamped = clamp(lat, -1.4835298641951802, 1.4835298641951802);
float yMerc = log(tan(PI / 4.0 + latClamped / 2.0)) / PI2;
float xMerc = xEqui / 2.0;
vec4 mercatorPos = vec4(xMerc, yMerc, 0.0, 1.0);
Can anyone help to reverse this so I'm able to go from a mercator map as a source to equirectangular (or even better, azimuthal).
Looking for a way to do 2D texture deformations going from x/y to longitude(x)/latitude(y) and back.
I appreciate your input.
If you want to output the equirectangular projection, you need to convert from equirectangular coordinates to mercator coordinates and then sample the mercator projection at those coordinates.
This is what it would look like in a fragment shader from uvs:
//uv to equirectangular
float lat = (uv.x) * 2 * PI; // from 0 to 2PI
float lon = (uv.y - .5f) * PI; // from -PI to PI
// equirectangular to mercator
float x = lat;
float y = log(tan(PI / 4. + lon / 2.));
// bring x,y into [0,1] range
x = x / (2*PI);
y = (y+PI) / (2*PI);
// sample mercator projection
fixed4 col = tex2D(_MainTex, float2(x,y));
The same thing applies to the azimuthal projection: You can go from azimuthal coordinates -> equirectangular -> mercator and sample the image. Or you can find a formula to go directly from azimuthal -> mercator. The wiki pages have a bunch of formulas to go back and forth between projections. Here is a full shader to play around with. Input is a mercator projection and outputs a equirectangular or azimuthal projection (choose from the dropdown menu)
Shader "Unlit/NewUnlitShader 1"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[Enum(Equirectangular,0,Azimuthal,1)]
_Azimuthal("Projection", float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Azimuthal;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
#define PI 3.141592653589793238462f
#define PI2 6.283185307179586476924f
float2 uvToEquirectangular(float2 uv) {
float lat = (uv.x) * PI2; // from 0 to 2PI
float lon = (uv.y - .5f) * PI; // from -PI to PI
return float2(lat, lon);
}
float2 uvAsAzimuthalToEquirectangular(float2 uv) {
float2 coord = (uv - .5) * 4;
float radius = length(coord);
float angle = atan2(coord.y, coord.x) + PI;
//formula from https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
float lat = angle;
float lon = 2 * acos(radius / 2.) - PI / 2;
return float2(lat, lon);
}
fixed4 frag(v2f i) : SV_Target
{
// get equirectangular coordinates
float2 coord = _Azimuthal ? uvAsAzimuthalToEquirectangular(i.uv) : uvToEquirectangular(i.uv);
// equirectangular to mercator
float x = coord.x;
float y = log(tan(PI / 4. + coord.y / 2.));
// brin x,y into [0,1] range
x = x / PI2;
y = (y + PI) / PI2;
fixed4 col = tex2D(_MainTex, float2(x,y));
// just to make it look nicer
col = _Azimuthal && length(i.uv*2-1) > 1 ? 1 : col;
return col;
}
ENDCG
}
}
}

How can I convert these fragColor code snippets from ShaderToy so that they will work in Unity?

I'm following this tutorial: https://www.youtube.com/watch?v=CzORVWFvZ28 to convert some code from ShaderToy to Unity. This is the shader that I'm attempting to convert: https://www.shadertoy.com/view/Ws23WD.
I saw that in the tutorial, he was able to take his fragColor statement from ShaderToy and simply return a color in Unity instead. However, when I tried doing that with the code that I have from ShaderToy, an error about not being able to implicitly convert from float3 to float4 popped up. I saw that my color variable is being declared as a float3 which is what must be causing the issue, but I need some help figuring out how to fix this.
I also noticed that I have an 'a' value with the fragColor variable, in addition to the rgb values; would I use a float4 to take in the (r, g, b, a) values?
fixed4 frag (v2f i) : SV_Target
{
//float2 uv = float2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
float2 uv = float2(i.uv);
uv -= 0.5;
//uv /= float2(iResolution.y / iResolution.x, 1);
float3 cam = float3(0, -0.15, -3.5);
float3 dir = normalize(float3(uv,1));
float cam_a2 = sin(_Time.y) * pi * 0.1;
cam.yz = rotate(cam.yz, cam_a2);
dir.yz = rotate(dir.yz, cam_a2);
float cam_a = _Time.y * pi * 0.1;
cam.xz = rotate(cam.xz, cam_a);
dir.xz = rotate(dir.xz, cam_a);
float3 color = float3(0.16, 0.12, 0.10);
float t = 0.00001;
const int maxSteps = 128;
for(int i = 0; i < maxSteps; ++i) {
float3 p = cam + dir * t;
float d = scene(p);
if(d < 0.0001 * t) {
color = float3(1.0, length(p) * (0.6 + (sin(_Time.y*3.0)+1.0) * 0.5 * 0.4), 0);
break;
}
t += d;
}
//fragColor.rgb = color;
return color;
//fragColor.a = 1.0;
}

Problems porting a GLSL shadertoy shader to unity

I'm currently trying to port a shadertoy.com shader (Atmospheric Scattering Sample, interactive demo with code) to Unity. The shader is written in GLSL and I have to start the editor with C:\Program Files\Unity\Editor>Unity.exe -force-opengl to make it render the shader (otherwise a "This shader cannot be run on this GPU" error comes up), but that's not a problem right now. The problem is with porting that shader to Unity.
The functions for the scattering etc. are all identical and "runnable" in my ported shader, the only thing is that the mainImage() functions manages the camera, light directions and ray direction itself. This has to be ofcourse changed sothat Unity's camera position, view direction and light sources and directions are used.
The main function of the original looks like this:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// default ray dir
vec3 dir = ray_dir( 45.0, iResolution.xy, fragCoord.xy );
// default ray origin
vec3 eye = vec3( 0.0, 0.0, 2.4 );
// rotate camera
mat3 rot = rot3xy( vec2( 0.0, iGlobalTime * 0.5 ) );
dir = rot * dir;
eye = rot * eye;
// sun light dir
vec3 l = vec3( 0, 0, 1 );
vec2 e = ray_vs_sphere( eye, dir, R );
if ( e.x > e.y ) {
discard;
}
vec2 f = ray_vs_sphere( eye, dir, R_INNER );
e.y = min( e.y, f.x );
vec3 I = in_scatter( eye, dir, e, l );
fragColor = vec4( I, 1.0 );
}
I've read through the documentation of that function and how it's supposed work at https://www.shadertoy.com/howto .
Image shaders implement the mainImage() function in order to generate
the procedural images by computing a color for each pixel. This
function is expected to be called once per pixel, and it is
responsability of the host application to provide the right inputs to
it and get the output color from it and assign it to the screen pixel.
The prototype is:
void mainImage( out vec4 fragColor, in vec2 fragCoord );
where fragCoord contains the pixel coordinates for which the shader
needs to compute a color. The coordinates are in pixel units, ranging
from 0.5 to resolution-0.5, over the rendering surface, where the
resolution is passed to the shader through the iResolution uniform
(see below).
The resulting color is gathered in fragColor as a four component
vector, the last of which is ignored by the client. The result is
gathered as an "out" variable in prevision of future addition of
multiple render targets.
So in that function there are references to iGlobalTime to make the camera rotate with time and references to the iResolution for the resolution. I've embedded the shader in a Unity shader and tried to fix and wireup the dir, eye and l sothat it works with Unity, but I'm completly stuck. I get some sort of picture which looks "related" to the original shader: (Top is original, buttom the current unity state)
I'm not a shader profesional, I only know some basics of OpenGL, but for the most part, I write game logic in C#, so all I could really do was look at other shader examples and look at how I could get the data about camera, lightsources etc. in this code, but as you can see, nothing works out, really.
I've copied the skelton-code for the shader from https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Specular_Highlights and some vectors from http://forum.unity3d.com/threads/glsl-shader.39629/ .
I hope someone can point me in some direction on how to fix this shader / correctly port it to unity. Below is the current shader code, all you have to do to reproduce it is create a new shader in a blank project, copy that code inside, make a new material, assign the shader to that material, then add a sphere and add that material on it and add a directional light.
Shader "Unlit/AtmoFragShader" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_LC("LC", Color) = (1,0,0,0) /* stuff from the testing shader, now really used */
_LP("LP", Vector) = (1,1,1,1)
}
SubShader{
Tags{ "Queue" = "Geometry" } //Is this even the right queue?
Pass{
//Tags{ "LightMode" = "ForwardBase" }
GLSLPROGRAM
/* begin port by copying in the constants */
// math const
const float PI = 3.14159265359;
const float DEG_TO_RAD = PI / 180.0;
const float MAX = 10000.0;
// scatter const
const float K_R = 0.166;
const float K_M = 0.0025;
const float E = 14.3; // light intensity
const vec3 C_R = vec3(0.3, 0.7, 1.0); // 1 / wavelength ^ 4
const float G_M = -0.85; // Mie g
const float R = 1.0; /* this is the radius of the spehere? this should be set from the geometry or something.. */
const float R_INNER = 0.7;
const float SCALE_H = 4.0 / (R - R_INNER);
const float SCALE_L = 1.0 / (R - R_INNER);
const int NUM_OUT_SCATTER = 10;
const float FNUM_OUT_SCATTER = 10.0;
const int NUM_IN_SCATTER = 10;
const float FNUM_IN_SCATTER = 10.0;
/* begin functions. These are out of the defines because they should be accesible to anyone. */
// angle : pitch, yaw
mat3 rot3xy(vec2 angle) {
vec2 c = cos(angle);
vec2 s = sin(angle);
return mat3(
c.y, 0.0, -s.y,
s.y * s.x, c.x, c.y * s.x,
s.y * c.x, -s.x, c.y * c.x
);
}
// ray direction
vec3 ray_dir(float fov, vec2 size, vec2 pos) {
vec2 xy = pos - size * 0.5;
float cot_half_fov = tan((90.0 - fov * 0.5) * DEG_TO_RAD);
float z = size.y * 0.5 * cot_half_fov;
return normalize(vec3(xy, -z));
}
// ray intersects sphere
// e = -b +/- sqrt( b^2 - c )
vec2 ray_vs_sphere(vec3 p, vec3 dir, float r) {
float b = dot(p, dir);
float c = dot(p, p) - r * r;
float d = b * b - c;
if (d < 0.0) {
return vec2(MAX, -MAX);
}
d = sqrt(d);
return vec2(-b - d, -b + d);
}
// Mie
// g : ( -0.75, -0.999 )
// 3 * ( 1 - g^2 ) 1 + c^2
// F = ----------------- * -------------------------------
// 2 * ( 2 + g^2 ) ( 1 + g^2 - 2 * g * c )^(3/2)
float phase_mie(float g, float c, float cc) {
float gg = g * g;
float a = (1.0 - gg) * (1.0 + cc);
float b = 1.0 + gg - 2.0 * g * c;
b *= sqrt(b);
b *= 2.0 + gg;
return 1.5 * a / b;
}
// Reyleigh
// g : 0
// F = 3/4 * ( 1 + c^2 )
float phase_reyleigh(float cc) {
return 0.75 * (1.0 + cc);
}
float density(vec3 p) {
return exp(-(length(p) - R_INNER) * SCALE_H);
}
float optic(vec3 p, vec3 q) {
vec3 step = (q - p) / FNUM_OUT_SCATTER;
vec3 v = p + step * 0.5;
float sum = 0.0;
for (int i = 0; i < NUM_OUT_SCATTER; i++) {
sum += density(v);
v += step;
}
sum *= length(step) * SCALE_L;
return sum;
}
vec3 in_scatter(vec3 o, vec3 dir, vec2 e, vec3 l) {
float len = (e.y - e.x) / FNUM_IN_SCATTER;
vec3 step = dir * len;
vec3 p = o + dir * e.x;
vec3 v = p + dir * (len * 0.5);
vec3 sum = vec3(0.0);
for (int i = 0; i < NUM_IN_SCATTER; i++) {
vec2 f = ray_vs_sphere(v, l, R);
vec3 u = v + l * f.y;
float n = (optic(p, v) + optic(v, u)) * (PI * 4.0);
sum += density(v) * exp(-n * (K_R * C_R + K_M));
v += step;
}
sum *= len * SCALE_L;
float c = dot(dir, -l);
float cc = c * c;
return sum * (K_R * C_R * phase_reyleigh(cc) + K_M * phase_mie(G_M, c, cc)) * E;
}
/* end functions */
/* vertex shader begins here*/
#ifdef VERTEX
const float SpecularContribution = 0.3;
const float DiffuseContribution = 1.0 - SpecularContribution;
uniform vec4 _LP;
varying vec2 TextureCoordinate;
varying float LightIntensity;
varying vec4 someOutput;
/* transient stuff */
varying vec3 eyeOutput;
varying vec3 dirOutput;
varying vec3 lOutput;
varying vec2 eOutput;
/* lighting stuff */
// i.e. one could #include "UnityCG.glslinc"
uniform vec3 _WorldSpaceCameraPos;
// camera position in world space
uniform mat4 _Object2World; // model matrix
uniform mat4 _World2Object; // inverse model matrix
uniform vec4 _WorldSpaceLightPos0;
// direction to or position of light source
uniform vec4 _LightColor0;
// color of light source (from "Lighting.cginc")
void main()
{
/* code from that example shader */
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);
vec3 lightVec = normalize(_LP.xyz - ecPosition);
vec3 reflectVec = reflect(-lightVec, tnorm);
vec3 viewVec = normalize(-ecPosition);
/* copied from https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Specular_Highlights for testing stuff */
//I have no idea what I'm doing, but hopefully this computes some vectors which I need
mat4 modelMatrix = _Object2World;
mat4 modelMatrixInverse = _World2Object; // unity_Scale.w
// is unnecessary because we normalize vectors
vec3 normalDirection = normalize(vec3(
vec4(gl_Normal, 0.0) * modelMatrixInverse));
vec3 viewDirection = normalize(vec3(
vec4(_WorldSpaceCameraPos, 1.0)
- modelMatrix * gl_Vertex));
vec3 lightDirection;
float attenuation;
if (0.0 == _WorldSpaceLightPos0.w) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(vec3(_WorldSpaceLightPos0));
}
else // point or spot light
{
vec3 vertexToLightSource = vec3(_WorldSpaceLightPos0
- modelMatrix * gl_Vertex);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}
/* test port */
// default ray dir
//That's the direction of the camera here?
vec3 dir = viewDirection; //normalDirection;//viewDirection;// tnorm;//lightVec;//lightDirection;//normalDirection; //lightVec;//tnorm;//ray_dir(45.0, iResolution.xy, fragCoord.xy);
// default ray origin
//I think they mean the position of the camera here?
vec3 eye = vec3(_WorldSpaceCameraPos); //vec3(_WorldSpaceLightPos0); //// vec3(0.0, 0.0, 0.0); //_WorldSpaceCameraPos;//ecPosition; //vec3(0.0, 0.0, 2.4);
// rotate camera not needed, remove it
// sun light dir
//I think they mean the direciton of our directional light?
vec3 l = lightDirection;//_LightColor0.xyz; //lightDirection; //normalDirection;//normalize(vec3(_WorldSpaceLightPos0));//lightVec;// vec3(0, 0, 1);
/* this computes the intersection of the ray and the sphere.. is this really needed?*/
vec2 e = ray_vs_sphere(eye, dir, R);
/* copy stuff sothat we can use it on the fragment shader, "discard" is only allowed in fragment shader,
so the rest has to be computed in fragment shader */
eOutput = e;
eyeOutput = eye;
dirOutput = dir;
lOutput = dir;
}
#endif
#ifdef FRAGMENT
uniform sampler2D _MainTex;
varying vec2 TextureCoordinate;
uniform vec4 _LC;
varying float LightIntensity;
/* transient port */
varying vec3 eyeOutput;
varying vec3 dirOutput;
varying vec3 lOutput;
varying vec2 eOutput;
void main()
{
/* real fragment */
if (eOutput.x > eOutput.y) {
//discard;
}
vec2 f = ray_vs_sphere(eyeOutput, dirOutput, R_INNER);
vec2 e = eOutput;
e.y = min(e.y, f.x);
vec3 I = in_scatter(eyeOutput, dirOutput, eOutput, lOutput);
gl_FragColor = vec4(I, 1.0);
/*vec4 c2;
c2.x = 1.0;
c2.y = 1.0;
c2.z = 0.0;
c2.w = 1.0f;
gl_FragColor = c2;*/
//gl_FragColor = c;
}
#endif
ENDGLSL
}
}
}
Any help is appreciated, sorry for the long post and explanations.
Edit: I just found out that the radius of the spehere does have an influence on the stuff, a sphere with scale 2.0 in every direction gives a much better result. However, the picture is still completly independent of the viewing angle of the camera and any lights, this is nowhere near the shaderlab version.
It's look like you are trying to render a 2D texture over a sphere. It has some different approach. For what you trying to do, I would apply the shader over a plane crossed with the sphere.
For general purpose, look this article showing how to convert shaderToy to Unity3D.
There is some steps that I included here:
Replace iGlobalTime shader input (“shader playback time in seconds”) with _Time.y
Replace iResolution.xy (“viewport resolution in pixels”) with _ScreenParams.xy
Replace vec2 types with float2, mat2 with float2x2 etc.
Replace vec3(1) shortcut constructors in which all elements have same value with explicit float3(1,1,1)
Replace Texture2D with Tex2D
Replace atan(x,y) with atan2(y,x) <- Note parameter ordering!
Replace mix() with lerp()
Replace *= with mul()
Remove third (bias) parameter from Texture2D lookups
mainImage(out vec4 fragColor, in vec2 fragCoord) is the fragment shader function, equivalent to float4 mainImage(float2 fragCoord : SV_POSITION) : SV_Target
UV coordinates in GLSL have 0 at the top and increase downwards, in HLSL 0 is at the bottom and increases upwards, so you may need to use uv.y = 1 – uv.y at some point.
About this question:
Tags{ "Queue" = "Geometry" } //Is this even the right queue?
Queue references the order it will be rendered, Geometry is one of the first of, if you want you shader running over everything you could use Overlay for example. This topic is covered here.
Background - this render queue is rendered before any others. It is used for skyboxes and the like.
Geometry (default) - this is used for most objects. Opaque geometry uses this queue.
AlphaTest - alpha tested geometry uses this queue. It’s a separate queue from - Geometry one since it’s more efficient to render alpha-tested objects after all solid ones are drawn.
Transparent - this render queue is rendered after Geometry and AlphaTest, in back-to-front order. Anything alpha-blended (i.e. shaders that don’t write to depth buffer) should go here (glass, particle effects).
Overlay - this render queue is meant for overlay effects. Anything rendered last should go here (e.g. lens flares).