Bahadır Bahadır - 6 months ago 75
Javascript Question

Overlapping Edges With Transparent Shader Material - Three.js

Im newbie at webgl world and trying to learn something. while after i figured out how shaders work, wanted to go a step further and make a smooth, transparent cloud. Actually i made it, but as you see in the images below, there is some overlaping edges look jagged.

can you explain why this is happening and how to solve it?

thank you

v77







Snippet



var camera, controls, scene, renderer;
var sceneCss, rendererCss;
var dirLight, ambientLight, pointLight;
var displacementMaterial;

var wH = window.innerHeight;
var wW = window.innerWidth;
var start = Date.now();
var properties;
var cloudRadius = 150;
var cloudMesh;

var noiseMaterial, noiseMap;
var uniforms, displamentUniforms;


$(document).ready(function() {
//init Core Engine;
init();
//init All Engines;
onLoaded();
animateAll();
});

//Give it life;
function init() {

properties = {
smoke: 2.0,
heat: 0.0007,
shapeBiasX: 1.5,
shapeBiasY: 2.5,
displacementScale: 40,
displacementBias: -22,
turbulence: 40,
twist: 0,
wireframes: false,
rotationX: .5,
rotationY: 0,
rotationZ: 0,
opacity: 1.0
}

// add camera and controls
camera = new THREE.PerspectiveCamera(70, wW / wH, 0.1, 20000);
camera.position.set(0, 0, 400);

//PostProcess Materials
sceneRenderTarget = new THREE.Scene();

cameraOrtho = new THREE.OrthographicCamera(wW / -2, wW / 2, wH / 2, wH / -2, -10000, 10000);
cameraOrtho.position.z = 100;
cameraOrtho.updateProjectionMatrix();

var plane = new THREE.PlaneGeometry(wW, wH);
quadTarget = new THREE.Mesh(plane, new THREE.MeshBasicMaterial({ transparent: true, opacity: .1, color: 0x000000 }));
quadTarget.position.z = -500;
sceneRenderTarget.add(quadTarget);

//
//scene
scene = new THREE.Scene();
sceneCss = new THREE.Scene();
fog = new THREE.FogExp2(0x212121, 0.002);
scene.fog = fog;

//renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(wW, wH);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.sortObjects = false;
renderer.domElement.style.zIndex = 0;
renderer.setClearColor(0x222222);
document.body.appendChild(renderer.domElement);
}

function onLoaded() {
//Will Check Processes
createClouds();
}

function createClouds() {

uniforms = {
time: {
type: "f",
value: 1.0
},
uSpeed: {
type: "f",
value: 1.0
},
scale: {
type: "v2",
value: new THREE.Vector2(1, 1)
},
opacity: {
type: "f",
value: 1.0
}
};

noiseMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('noise_vertex').textContent,
fragmentShader: document.getElementById('noise_fragment').textContent,
lights: false,
wireframe: properties.wireframes
});

noiseMap = new THREE.WebGLRenderTarget(512, 512, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBFormat,
wrapS: THREE.RepeatWrapping
});

displacementUniforms = {
time: {
type: "f",
value: 1.0
},
tHeightMap: {
type: "t",
value: noiseMap.texture
},
uDisplacementBias: {
type: "f",
value: properties.displacementBias
},
uDisplacementScale: {
type: "f",
value: properties.displacementScale
},
uColor1: {
type: "c",
value: new THREE.Color(0xffff00)
},
uColor2: {
type: "c",
value: new THREE.Color(0x0000ff)
},
uSmoke: {
type: "f",
value: properties.smoke
},
uShapeBias: {
type: "v2",
value: new THREE.Vector2(properties.shapeBiasX, properties.shapeBiasY)
},
uScreenHeight: {
type: "f",
value: wH
},
uTurbulence: {
type: "f",
value: properties.turbulence
},
uTwist: {
type: "f",
value: properties.twist
},
opacity: {
type: "f",
value: 1.0
}
};

displacementMaterial = new THREE.ShaderMaterial({
wireframe: properties.wireframes,
transparent: true,
uniforms: displacementUniforms,
vertexShader: document.getElementById('displacement_vertex').textContent,
fragmentShader: document.getElementById('displacement_fragment').textContent,
premultipliedAlpha: true,
side: THREE.DoubleSide,
shading: THREE.SmoothShading,
depthTest: false
});

var geometrySphere = new THREE.SphereGeometry(cloudRadius, 140, 100);
geometrySphere.computeFaceNormals();
cloudMesh = new THREE.Mesh(geometrySphere, displacementMaterial);
cloudMesh.position.y = -40;
cloudMesh.renderOrder = 5;
scene.add(cloudMesh);
}

function animateAll() {

uniforms.uSpeed.value += properties.heat;
uniforms.time.value += properties.heat * .3;

displacementUniforms.opacity.value = properties.opacity;
displacementMaterial.uniforms["time"].value += properties.heat * .3;

//cloudMesh.rotation.x = properties.rotationX;
cloudMesh.rotation.z = properties.rotationZ;
//cloudMesh.rotation.y = properties.rotationY;

cloudMesh.rotation.y += 0.002;



requestAnimationFrame(animateAll);
renderAll();
}

//render
function renderAll() {
renderer.clear();

quadTarget.material = noiseMaterial;

renderer.render(sceneRenderTarget, cameraOrtho, noiseMap, true);
renderer.render(scene, camera);

}

canvas {
width: 100%;
height: 100%;
position: absolute;
z-index: -10
}

body {
overflow: hidden;
padding: 0;
margin: 0;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.2.js"></script>
<script data-src="shaders/displacement_vertex.js" data-name="Displacement" type="x-shader/x-vertex" id="displacement_vertex">
uniform float time;
uniform vec2 scale;
uniform float uTwist;
varying vec2 vUv;
varying vec3 vNormal;
uniform vec2 uShapeBias;
uniform float uTurbulence;

#ifdef VERTEX_TEXTURES
uniform sampler2D tHeightMap;
uniform float uDisplacementScale;
uniform float uDisplacementBias;
#endif

vec4 DoTwist( vec4 pos, float t )
{
float st = sin(t);
float ct = cos(t);
vec4 new_pos;

new_pos.x = pos.x*ct - pos.z*st;
new_pos.z = pos.x*st + pos.z*ct;

new_pos.y = pos.y;
new_pos.w = pos.w;

return( new_pos );
}

void main( void ) {

vUv = uv;
vNormal = normalize( normalMatrix * normal );

//change matrix
vec4 mPosition = modelMatrix * vec4( position, 1.0 );

mPosition.x *= uShapeBias.x +1.0; // uShapeBias.x*(vUv.x+1.0);
mPosition.y *= (1.0 -(vUv.y-0.5)*-uShapeBias.y);
//mPosition.y -= 40.0;

float turbFactor = uTurbulence*(vUv.y-0.5);

//shape turbulance
mPosition.x += sin(mPosition.y/100.0 + time*20.0 )*turbFactor;
mPosition.z += cos(mPosition.y/100.0 + time*20.0 )*turbFactor;

//twist
float angle_rad = uTwist * 3.14159 / 180.0;
float height = -300.0;
float ang = (position.y-height*0.5)/height * angle_rad;

vec4 twistedPosition = DoTwist(mPosition, ang);
vec4 twistedNormal = DoTwist(vec4(vNormal,1.0), ang);

//change matrix
vec4 mvPosition = viewMatrix * twistedPosition;

#ifdef VERTEX_TEXTURES
vec3 dv = texture2D( tHeightMap, vUv ).xyz;
float df = uDisplacementScale * dv.x + uDisplacementBias;
vec4 displacedPosition = vec4( twistedNormal.xyz * df, 0.0 ) + mvPosition;
gl_Position = projectionMatrix * displacedPosition;
#else
gl_Position = projectionMatrix * mvPosition;
#endif

}
</script>
<script data-src="shaders/displacement_fragment.js" data-name="Displacement" type="x-shader/x-fragment" id="displacement_fragment">

varying vec2 vUv;

uniform sampler2D tHeightMap;
uniform float uSmoke;
uniform vec3 uColor1;
uniform vec3 uColor2;
uniform float uScreenHeight;
void main( void ) {


vec4 heightColor = texture2D( tHeightMap, vUv);
vec3 heightAlpha = texture2D( tHeightMap, vUv).xyz;

vec3 gradient1 = uColor1/(gl_FragCoord.y/uScreenHeight*4.0);
vec3 gradient2 = uColor2/(gl_FragCoord.y/uScreenHeight*4.0);
vec3 fireSumColor = (gradient1+gradient2)*heightColor.b;
float opacity = heightAlpha.x *.05;

//smoke
gl_FragColor = vec4(mix( fireSumColor, vec3(1.0), gl_FragCoord.y/uScreenHeight*uSmoke ), opacity);

float depth = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = smoothstep( 10.0, 400.0, depth* .9 );

gl_FragColor = mix( gl_FragColor, vec4( vec3(0.0,0.0,0.0), gl_FragColor.w ), fogFactor )*1.0;

// gl_FragColor = gl_FragColor*vec4(vec3(1.0), 1.0);

}
</script>
<script data-src="shaders/noise_vertex.js" data-name="Noise" type="x-shader/x-vertex" id="noise_vertex">
varying vec2 vUv;
uniform vec2 scale;

void main( void ) {
vUv = uv * scale;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script data-src="shaders/noise_fragment.js" data-name="Noise" type="x-shader/x-fragment" id="noise_fragment">
//
// Description : Array and textureless GLSL 3D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : ijm
// Lastmod : 20110409 (stegu)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
//

uniform float time;
uniform float uSpeed;

varying vec2 vUv;

vec4 permute( vec4 x ) {

return mod( ( ( x * 34.0 ) + 1.0 ) * x, 289.0 );
}

vec4 taylorInvSqrt( vec4 r ) {

return 1.79284291400159 - 0.85373472095314 * r;

}

float PI = 3.14159265;
float TWOPI = 6.28318531;
float BaseRadius = 1.0;

vec3 sphere( float u, float v) {

u *= PI;
v *= TWOPI;
vec3 pSphere;

pSphere.x = BaseRadius * cos(v) * sin(u);
pSphere.y = BaseRadius * sin(v) * sin(u);
pSphere.z = BaseRadius * cos(u);

return pSphere;
}

float snoise( vec3 v ) {

const vec2 C = vec2( 1.0 / 6.0, 1.0 / 3.0 );
const vec4 D = vec4( 0.0, 0.5, 1.0, 2.0 );

// First corner

vec3 i = floor( v + dot( v, C.yyy ) );
vec3 x0 = v - i + dot( i, C.xxx );

// Other corners

vec3 g = step( x0.yzx, x0.xyz );
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );

vec3 x1 = x0 - i1 + 1.0 * C.xxx;
vec3 x2 = x0 - i2 + 2.0 * C.xxx;
vec3 x3 = x0 - 1. + 3.0 * C.xxx;

// Permutations

i = mod( i, 289.0 );
vec4 p = permute( permute( permute(
i.z + vec4( 0.0, i1.z, i2.z, 1.0 ) )
+ i.y + vec4( 0.0, i1.y, i2.y, 1.0 ) )
+ i.x + vec4( 0.0, i1.x, i2.x, 1.0 ) );

// Gradients
// ( N*N points uniformly over a square, mapped onto an octahedron.)

float n_ = 1.0 / 7.0; // N=7

vec3 ns = n_ * D.wyz - D.xzx;

vec4 j = p - 49.0 * floor( p * ns.z *ns.z ); // mod(p,N*N)

vec4 x_ = floor( j * ns.z );
vec4 y_ = floor( j - 7.0 * x_ ); // mod(j,N)

vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs( x ) - abs( y );

vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );


vec4 s0 = floor( b0 ) * 2.0 + 1.0;
vec4 s1 = floor( b1 ) * 2.0 + 1.0;
vec4 sh = -step( h, vec4( 0.0 ) );

vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;

vec3 p0 = vec3( a0.xy, h.x );
vec3 p1 = vec3( a0.zw, h.y );
vec3 p2 = vec3( a1.xy, h.z );
vec3 p3 = vec3( a1.zw, h.w );

// Normalise gradients

vec4 norm = taylorInvSqrt( vec4( dot( p0, p0 ), dot( p1, p1 ), dot( p2, p2 ), dot( p3, p3 ) ) );
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;

// Mix final noise value

vec4 m = max( 0.6 - vec4( dot( x0, x0 ), dot( x1, x1 ), dot( x2, x2 ), dot( x3, x3 ) ), 0.0 );
m = m * m;
return 42.0 * dot( m*m, vec4( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 ), dot( p3, x3 ) ) );

}

float surface( vec3 coord ) {

float n = 0.0;

n += 0.7 * abs( snoise( coord ) );
n += 0.25 * abs( snoise( coord * 2.0 ) );
n += 0.125 * abs( snoise( coord * 4.0 ) );
n += 0.0625 * abs( snoise( coord * 8.0 ) );

return n;

}

void main( void ) {

vec3 coord = sphere(vUv.y,vUv.x);

coord.x += uSpeed;
coord.y += -time;
coord.z += -time;

float n = surface( coord );

gl_FragColor = vec4( vec3( n, n, n ), 1.0 );

}
</script>




Answer

When you have overlapping transparent materials in three.js, you can often remove unwanted artifacts by setting

material.depthTest = false;

It depends on your use case.

It will not work well if you have opaque objects the occlude the transparent objects, however. But that is not your use case here.

EDIT: As @Bahadir points out in the comment below, you can an also try

material.depthWrite = false;

three.js r.77

Comments