GLSL Plane Transparency (Remove Plane Background) - fragment

I followed a tutorial online that basically draws a shape on a plane. I want to make only the shape visible, while the background of the plane invisible, so that I can put it onto another plane instead.
I'm extremely new to ThreeJS and GLSL Shaders so I'm completely lost on this, any help is welcome, thank you.
My Fragment Shader:
uniform float time;
uniform float progress;
uniform vec2 mouse;
uniform sampler2D matcap;
uniform vec4 resolution;
varying vec2 vUv;
varying vec3 vPosition;
float PI = 3.141592653589793238;
mat4 rotationMatrix(vec3 axis, float angle) {
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0,
0.0, 0.0, 0.0, 1.0);
}
vec2 getmatcap(vec3 eye, vec3 normal) {
vec3 reflected = reflect(eye, normal);
float m = 2.8284271247461903 * sqrt( reflected.z+1.0 );
return reflected.xy / m + 0.5;
}
vec3 rotate(vec3 v, vec3 axis, float angle) {
mat4 m = rotationMatrix(axis, angle);
return (m * vec4(v, 1.0)).xyz;
}
float smin( float a, float b, float k )
{
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
float sdSphere( vec3 p, float r ){
return length(p)-r;
}
float sdBox( vec3 p, vec3 b ){
vec3 q = abs(p) - b;
return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.);
}
float rand(vec2 co){
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
}
float sdf(vec3 p){
vec3 p1 = rotate(p,vec3(1.),time/5.);
float box = smin(sdBox(p1,vec3(0.2)),sdSphere(p,0.2), 0.3);
float realsphere = sdSphere(p1, 0.1);
float final = mix(box,realsphere,progress);
for(float i = 0.; i < 10.; i++) {
float randOffset = rand(vec2(i,0.));
float progr = 1. - fract(time/3. + randOffset*3.);
vec3 pos = vec3(sin(randOffset*2.*PI),cos(randOffset*2.*PI),0.);
float gotoCenter = sdSphere(p-pos*progr, 0.1);
final = smin(final,gotoCenter,0.1);
}
float mouseSphere = sdSphere(p - vec3(mouse*2.,0.),0.1);
return smin(final, mouseSphere, 0.1);
}
vec3 calcNormal( in vec3 p )
{
const float eps = 0.0001;
const vec2 h = vec2(eps,0);
return normalize( vec3(sdf(p+h.xyy) - sdf(p-h.xyy),
sdf(p+h.yxy) - sdf(p-h.yxy),
sdf(p+h.yyx) - sdf(p-h.yyx) ) );
}
void main() {
float dist = length(vUv - vec2(0.5));
vec3 bg = mix(vec3(0.3),vec3(0.0), dist);
vec3 camPos = vec3(0.,0.,2.);
vec3 ray = normalize(vec3(vUv - vec2(0.5),-1));
vec3 rayPos = camPos;
float t = 0.;
float tMax = 5.;
for(int i = 0; i < 256; i++) {
vec3 pos = camPos + t*ray;
float h = sdf(pos);
if(h<0.0001 || t>tMax) break;
t+=h;
}
vec3 color = bg;
if(t<tMax){
vec3 pos = camPos + t*ray;
color = vec3(1.);
vec3 normal = calcNormal(pos);
color = normal;
float diff = dot(vec3(1.),normal);
vec2 matcapUV = getmatcap(ray,normal);
color = vec3(diff);
color = texture2D(matcap,matcapUV).rgb;
float fresnel = pow(1. + dot(ray,normal),3.);
color = mix(color,bg,fresnel);
}
gl_FragColor = vec4(color,1.);
}

Related

Problem generating Perlin Noise in HLSL from C# working code

I'm trying to program a Compute-Shader Perlin Noise code based on a working C# code.
The problem is that i only got smooth dots.
Left C# Working, Right Compute-Shader
with this values for both
If i lower the frequency the dots get bigger:
This is the code i'm using
#pragma kernel CSMain
RWTexture2D<float> Result;
RWStructuredBuffer<float> resfloat;
float res;
float frequency;
float octaves;
float lacunarity;
float persistence;
StructuredBuffer<float3> gradients3D;
StructuredBuffer<int> hash;
float lerp(float v0, float v1, float t);
float Dot(float3 g, float x, float y, float z);
float Smooth(float t);
float Perlin3D(float3 v, float frequency);
float noise(float3 v, float frequency, int octaves, float lacunarity, float persistence);
int hashMask = 255;
int gradientsMask3D = 15;
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
float3 v = float3(id.x, id.y, id.z) / res;
float h = 0.0;
h = noise(v, frequency, octaves, lacunarity, persistence);
Result[id.xy] = float4(h, 0, 0, 0);
resfloat[id.x + id.y * res] = h;
}
float lerp(float v0, float v1, float t) {
return v0 + t * (v1 - v0);
}
float Smooth(float t) {
return t * t * t * (t * (t * (float) 6 - (float) 15) + (float) 10);
}
float Perlin3D(float3 v, float frequency) {
v *= frequency;
int ix0 = (int) floor(v.x);
int iy0 = (int) floor(v.y);
int iz0 = (int) floor(v.z);
float tx0 = v.x - ix0;
float ty0 = v.y - iy0;
float tz0 = v.z - iz0;
float tx1 = tx0 - (float) 1;
float ty1 = ty0 - (float) 1;
float tz1 = tz0 - (float) 1;
ix0 &= hashMask;
iy0 &= hashMask;
iz0 &= hashMask;
int ix1 = ix0 + (float) 1;
int iy1 = iy0 + (float) 1;
int iz1 = iz0 + (float) 1;
int h0 = hash[ix0];
int h1 = hash[ix1];
int h00 = hash[h0 + iy0];
int h10 = hash[h1 + iy0];
int h01 = hash[h0 + iy1];
int h11 = hash[h1 + iy1];
float3 g000 = gradients3D[hash[h00 + iz0] & gradientsMask3D];
float3 g100 = gradients3D[hash[h10 + iz0] & gradientsMask3D];
float3 g010 = gradients3D[hash[h01 + iz0] & gradientsMask3D];
float3 g110 = gradients3D[hash[h11 + iz0] & gradientsMask3D];
float3 g001 = gradients3D[hash[h00 + iz1] & gradientsMask3D];
float3 g101 = gradients3D[hash[h10 + iz1] & gradientsMask3D];
float3 g011 = gradients3D[hash[h01 + iz1] & gradientsMask3D];
float3 g111 = gradients3D[hash[h11 + iz1] & gradientsMask3D];
float v000 = dot(g000, float3(tx0, ty0, tz0));
float v100 = dot(g100, float3(tx1, ty0, tz0));
float v010 = dot(g010, float3(tx0, ty1, tz0));
float v110 = dot(g110, float3(tx1, ty1, tz0));
float v001 = dot(g001, float3(tx0, ty0, tz1));
float v101 = dot(g101, float3(tx1, ty0, tz1));
float v011 = dot(g011, float3(tx0, ty1, tz1));
float v111 = dot(g111, float3(tx1, ty1, tz1));
float tx = Smooth(tx0);
float ty = Smooth(ty0);
float tz = Smooth(tz0);
return lerp(
lerp(lerp(v000, v100, tx), lerp(v010, v110, tx), ty),
lerp(lerp(v001, v101, tx), lerp(v011, v111, tx), ty),
tz);
}
float noise(float3 v, float frequency, int octaves, float lacunarity, float persistence)
{
float sum = Perlin3D(v, frequency);
float amplitude = 1;
float range = 1;
for (int o = 1; o < octaves; o++) {
frequency *= lacunarity;
amplitude *= persistence;
range += amplitude;
sum += Perlin3D(v, frequency) * amplitude;
}
return sum / range;
}
This is the C# working code
And this is the C# code that calls the shader
I already checked that the StructuredBuffer (gradients3D and hash), and the float params are correctly loaded .
Any ideas?
The problem was that for some reason, when the function Perlin3D, used hashMask and gradientsMask3D, they had a 0.
So i moved the definition to the function:
float Perlin3D(float3 v, float frequency)
{
int hashMask = 255;
int gradientsMask3D = 15;
v *= frequency;
int ix0 = (int) floor(v.x);

Generating a normal map from a height map in compute shader?

The problem is that when I tried converting height map to normal map. The results are wrong. For some reason there is 3 light sources that is emitting from top (green), right (red), and left (blue) in the texture.
This is the GeoMath.hlsl code that I am using
static const float PI = 3.141592653589793238462643383279;
float2 longitudeLatitudeToUV(float2 longLat) {
float longitude = longLat[0];
float latitude = longLat[1];
float u = longitude / (2 * PI) + 0.5;
float v = latitude / PI + 0.5;
return float2(u,v);
}
float3 longitudeLatitudeToPoint(float2 longLat) {
float longitude = longLat[0];
float latitude = longLat[1];
float x;
float y;
float z;
y = sin(latitude);
float r = cos(latitude);
x = sin(longitude) * r;
z = -cos(longitude) * r;
return float3(x, y, z);
}
float2 uvToLongitudeLatitude(float2 uv) {
float longitude = (uv.x - 0.5) * (2 * PI);
float latitude = (uv.y - 0.5) * PI;
return float2(longitude, latitude);
}
float2 pointToLongitudeLatitude(float3 p) {
float longitude = atan2(p.x, p.z);
float latitude = asin(p.y);
return float2(longitude, latitude);
}
float2 pointToUV(float3 p) {
p = normalize(p);
return longitudeLatitudeToUV(pointToLongitudeLatitude(p));
}
This is the compute shader I am using to convert height map into normal map.
#pragma kernel CSMain
#include "GeoMath.hlsl"
Texture2D<float> _HeightMap;
RWTexture2D<float4> _NormalMap;
int _TextureSize_Width;
int _TextureSize_Height;
float _WorldRadius;
float _HeightMultiplier;
float3 CalculateWorldPoint(uint2 texCoord)
{
float2 uv = texCoord / float2(_TextureSize_Width - 1, _TextureSize_Height - 1);
float2 longLat = uvToLongitudeLatitude(uv);
float3 spherePoint = longitudeLatitudeToPoint(longLat);
float height01 = _HeightMap[texCoord].r + 1.0;
float worldHeight = _WorldRadius + height01 * _HeightMultiplier;
return spherePoint * worldHeight;
}
uint2 WrapIndex(uint2 texCoord)
{
texCoord.x = (texCoord.x + _TextureSize_Width) % _TextureSize_Width;
texCoord.y = max(min(_TextureSize_Height - 1, texCoord.y), 0);
return texCoord;
}
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
float3 normalVector;
float3 posNorth = CalculateWorldPoint(WrapIndex(id.xy + uint2(0, 1)));
float3 posSouth = CalculateWorldPoint(WrapIndex(id.xy + uint2(0, -1)));
float3 posEast = CalculateWorldPoint(WrapIndex(id.xy + uint2(1, 0)));
float3 posWest = CalculateWorldPoint(WrapIndex(id.xy + uint2(-1, 0)));
float3 dirNorth = normalize(posNorth - posSouth);
float3 dirEast = normalize(posEast - posWest);
normalVector = normalize(cross(dirNorth, dirEast));
_NormalMap[id.xy] = float4(normalVector, 1.0);
}
And this is the result I am getting is down below height map (top), generated normal map from the code above (bottom)
I believe that you are trying to get object space normals.
But there is tiny detail is missing.
Possible values for normalized vector3 are -1..1 for each axis.
And possible values for pixel: 0..1.
You just need to adjust ranges.
This line roughly fixes problem:
_NormalMap[id.xy] = float4(normalVector / 2 + float3(0.5, 0.5, 0.5), 1.0);
Result

URP Shader, almost the same codes affect differently

I'm working on urp shader gerstner wave. Problem was that two side by side ocean plane waves were not continuesly. So, I tought if vertex positions would be world position, problem could fixed. it worked. However there was something I really don't understand.
this code worked
v.positionOS = mul(unity_ObjectToWorld, v.positionOS);
that one made weird things
float worldPos = mul(unity_ObjectToWorld, v.positionOS);
v.positionOS = worldPos;
all vertex shader here:
v2f vert(a2v v)
{
v2f o;
float3 tangent = float3(1, 0, 0);
float3 binormal = float3(0, 0, 1);
float3 p = v.positionOS;
/*float worldPos = mul(unity_ObjectToWorld, v.positionOS);
v.positionOS = worldPos;*/
v.positionOS = mul(unity_ObjectToWorld, v.positionOS);
p += GerstnerWave(_WaveA, v.positionOS.xyz, tangent, binormal);
o.heightOS = p.y;
VertexPositionInputs positionInputs = GetVertexPositionInputs(p);
o.positionCS = positionInputs.positionCS;
o.positionWS = positionInputs.positionWS;
return o;
}
float3 GerstnerWave(
float4 wave, float3 p, inout float3 tangent, inout float3 binormal
)
{
float steepness = wave.z;
float wavelength = wave.w;
float k = 2 * UNITY_PI / wavelength;
float c = sqrt(9.8 / k);
float2 d = normalize(wave.xy) * _Frequency;
float f = k * (dot(d, p.xz) - c * _Time.y * _Speed);
float a = steepness / k;
tangent += float3(
- d.x * d.x * (steepness * sin(f)),
d.x * (steepness * cos(f)),
- d.x * d.y * (steepness * sin(f))
);
binormal += float3(
- d.x * d.y * (steepness * sin(f)),
d.y * (steepness * cos(f)),
- d.y * d.y * (steepness * sin(f))
);
return float3(
d.x * (a * cos(f)),
a * sin(f),
d.y * (a * cos(f))
);
}

Color Blending in WebGL

I'm using the following library:
https://github.com/tengbao/vanta/blob/master/src/vanta.halo.js
A demo can be found here:
https://www.vantajs.com/?effect=halo
If I'm using a bright (or even white) background color, the effect is not visible anymore.
With my limited WebGL knowledge, my guess is that this is because of the subtraction of the background color (mixedColor = texture2D(...) - backgroundColor) (but I could be wrong).
void main() {
vec2 res2 = iResolution.xy * iDpr;
vec2 uv = gl_FragCoord.xy / res2; // 0 to 1
vec4 oldImage = texture2D(iBuffer, uv);
vec3 mixedColor = oldImage.rgb - backgroundColor;
float cropDist = 0.01;
float cropXOffset = 0.2;
float cropYOffset = 0.2;
vec2 offset = uv + vec2((mixedColor.g - cropXOffset) * cropDist, (mixedColor.r - cropYOffset) * cropDist);
float spinDist = 0.001;
float spinSpeed = 0.2 + 0.15 * cos(iTime * 0.5);
float timeFrac = mod(iTime, 6.5);
vec2 offset2 = uvBig + vec2(cos(timeFrac * spinSpeed) * spinDist, sin(timeFrac * spinSpeed) * spinDist);
mixedColor = texture2D(iBuffer, offset).rgb * 0.4
+ texture2D(iBuffer, offset2).rgb * 0.6
- backgroundColor;
float fadeAmt = 0.0015; // fade this amount each frame // 0.002
mixedColor = (mixedColor - fadeAmt) * .995;
vec4 spectrum = abs( abs( .95*atan(uv.x, uv.y) -vec4(0,2,4,0) ) -3. )-1.;
float angle = atan(pixel.x, pixel.y);
float dist = length(pixel - mouse2*0.15) * 8. + sin(iTime) * .01;
float flowerPeaks = .05 * amplitudeFactor * size;
float flowerPetals = 7.;
float edge = abs((dist + sin(angle * flowerPetals + iTime * 0.5) * sin(iTime * 1.5) * flowerPeaks) * 0.65 / size);
float colorChangeSpeed = 0.75 + 0.05 * sin(iTime) * 1.5;
float rainbowInput = timeFrac * colorChangeSpeed;
float brightness = 0.7;
vec4 rainbow = sqrt(j2hue(cos(rainbowInput))) + vec4(baseColor,0) - 1.0 + brightness;
float factor = smoothstep(1., .9, edge) * pow(edge, 2.);
vec3 color = rainbow.rgb * smoothstep(1., .9, edge) * pow(edge, 20.);
vec4 ring = vec4(
backgroundColor + clamp( mixedColor + color, 0., 1.)
, 1.0);
gl_FragColor = ring;
}
However I'm not able to figure out, how to adapt the behavior, so I can use a bright background.
If I remove the subtraction (and also remove the addition of the same at the end (vec4 ring = vec4(clamp(...))), I get the correct effect but with a black background.
Does anyone have an idea how to adapt the shader?
The problem is likely that backgroundColor is being added to the color to calculate the ring value. This will blow out your final color if backgroundColor is too bright.

Shader works just fine in Unity Editor, but became black in WebGL build

I am working on a project which encodes sensor values at different positions into a 3d heatmap of a building. I use a vertex shader for this purpose and this works just fine in Editor:example, but after I built the scene in WebGL, this turned out to be black.
I has tried using constant loop indices or always include this shader in project settings etc., but none of these works. Here are some of the code:
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
//...
float2 boxIntersection(in float3 ro, in float3 rd, in float3 rad)
{
float3 m = 1.0 / rd;
float3 n = m * ro;
float3 k = abs(m) * rad;
float3 t1 = -n - k;
float3 t2 = -n + k;
float tN = max(max(t1.x, t1.y), t1.z);
float tF = min(min(t2.x, t2.y), t2.z);
if (tN > tF || tF < 0.0) return float2(-1.0, -1.0); // no intersection
return float2(tN, tF);
}
//p in object space
float SampleValue(float3 p) {
float totalValue = 0.0;
float denom = 0.0;
for (int i = 0; i < 34; ++i) { // _DataSize
float4 sd = _SensorData[i];
float dist = length(p - sd.xyz);
totalValue += sd.w / (dist * dist);
denom += 1.0 / (dist * dist);
}
if (denom == 0.0) {
return 0.0;
}
return totalValue / denom;
}
float4 transferFunction(float value) {
float tv = (value - _DataScale.x) / (_DataScale.y - _DataScale.x); // _DataScale.x, _DataScale.y
float4 col = tex2D(_TransferTexture, float2(0.5, tv));
col.w *= _Strength; // _Strength
return float4(col.xyz * col.w, col.w);
}
float4 rayMarch(float3 ro, float3 rd, float dp) {
float3 ro1 = mul(unity_WorldToObject, float4(ro, 1.0));
float3 rd1 = mul(unity_WorldToObject, rd);
float2 t = boxIntersection(ro1, rd1, float3(1, 1, 1) * 0.5);
t.x = length(mul(unity_ObjectToWorld, float4(ro1 + rd1 * max(t.x, 0.0), 1.0)) - ro);
t.y = length(mul(unity_ObjectToWorld, float4(ro1 + rd1 * t.y, 1.0)) - ro);
t.y = min(t.y, dp);
float4 acc = float4(0.0, 0.0, 0.0, 1.0);
float totalDelta = (t.y - t.x);
float delta = totalDelta / float(_RM_Samples - 1.0);
float3 p = ro + t.x * rd;
for (int i = 0; i < 34; ++i) { // _RM_Samples
float v = SampleValue(p);
float4 tf = transferFunction(v);
float tr = exp(-tf.w * delta);
acc.xyz += tf.xyz * acc.w * delta;
acc.w *= tr;
p += delta * rd;
}
return float4(acc.xyz, (1.0 - acc.w) * step(t.x, t.y));
}
fixed4 frag(v2f i) : SV_Target
{
float2 tc = i.screenPos.xy / i.screenPos.w;
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, tc));
float eD = LinearEyeDepth(depth);
float3 ro = _WorldSpaceCameraPos;
float3 rd = normalize(i.worldPos - ro);
float4 col = rayMarch(ro, rd, eD);
//if (col.w < 1) col = float4(1, 0, 0, 1);
//else col = float4(0, 1, 0, 1);
if (wingCullPlaneValue(i.worldPos.xyz) == 0 || cullPlaneValue(i.worldPos.xyz) == 0) {
discard;
}
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
Since this works fine in Editor, I don't think there is any error in boxIntersection or rayMarching functions. I wonder if there is anything special in WebGl that it processes the pixels differently, and I has to tweak some codes accordingly. I am new to WebGL and Shader, and would appreciate any help or advice, thanks in advance.
that's because of the step function.
Approximate it with your own sigmoid function (might be expensive)
float emulated_step(float a, float x){
return 1.0/(1+pow(1000, -(x-a)*8192));
}