Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added transparency to StandardNodeMaterial #16996

Closed
wants to merge 10 commits into from
167 changes: 133 additions & 34 deletions examples/webgl_materials_transparency.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,37 @@
import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';

var params = { opacity: 0.25 };
import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js';

var params = {
opacity: 1,
transparency: 0,
roughness: 0,
metalness: 0,
colorSaturation: 0,
colorBrightness: 1,
showbox: false,
spotLight: 5,
};

var container, stats;
var camera, scene, renderer;
var material, material1, material2;
var hdrCubeRenderTarget;
var hdrCubeMap;
var spotLight;

init();
animate();
var fontLoader = new THREE.FontLoader();
fontLoader.load( 'fonts/gentilis_regular.typeface.json', function ( font ) {

function init() {
init( font );
animate();

} );

function init( font ) {

container = document.createElement( 'div' );
document.body.appendChild( container );
Expand All @@ -40,76 +62,75 @@

//

var geometry = new THREE.SphereBufferGeometry( 18, 30, 30 );
var geometry = new THREE.SphereBufferGeometry( 18, 100, 100 );

var material1 = new THREE.MeshStandardMaterial( {
opacity: params.opacity,
transparent: true
} );
//

material1 = new THREE.MeshPhysicalMaterial( {

var material2 = new THREE.MeshStandardMaterial( {
opacity: params.opacity,
premultipliedAlpha: true,
transparent: true
} );

var textureLoader = new THREE.TextureLoader();
textureLoader.load( "textures/hardwood2_diffuse.jpg", function ( map ) {
} );

map.anisotropy = 8;
material2 = new THREE.MeshPhysicalMaterial( {

material1.map = map;
material1.needsUpdate = true;
material2.map = map;
material2.needsUpdate = true;
transparent: true

} );

material2.premultipliedAlpha = true;

//

var textureLoader = new THREE.TextureLoader();
textureLoader.load( "textures/hardwood2_roughness.jpg", function ( map ) {

map.anisotropy = 8;

material1.roughnessMap = map;
material1.needsUpdate = true;
material2.roughnessMap = map;

material1.needsUpdate = true;
material2.needsUpdate = true;

} );

var mesh = new THREE.Mesh( geometry, material1 );
var mesh;

mesh = new THREE.Mesh( geometry, material1 );
mesh.position.x = - 25.0;
scene.add( mesh );

var mesh = new THREE.Mesh( geometry, material2 );
mesh = new THREE.Mesh( geometry, material2 );
mesh.position.x = 25.0;
scene.add( mesh );

//

var geometry = new THREE.PlaneBufferGeometry( 800, 800 );
var material = new THREE.MeshStandardMaterial( { color: 0x333333 } );
var geometry = new THREE.BoxBufferGeometry( 200, 100, 100 );
material = new THREE.MeshStandardMaterial( { color: 0x333333, side: THREE.BackSide } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = - 50;
mesh.rotation.x = - Math.PI * 0.5;
scene.add( mesh );
mesh.visible = false;

// Lights

var spotLight = new THREE.SpotLight( 0xff8888 );
spotLight = new THREE.SpotLight( 0xff0000, .1 );
spotLight.position.set( 100, 200, 100 );
spotLight.angle = Math.PI / 6;
spotLight.penumbra = 0.9;
scene.add( spotLight );
// scene.add( spotLight );

var spotLight = new THREE.SpotLight( 0x8888ff );
spotLight = new THREE.SpotLight( 0xffffff, params.spotlight );
spotLight.position.set( - 100, - 200, - 100 );
spotLight.angle = Math.PI / 6;
spotLight.penumbra = 0.9;
scene.add( spotLight );

//

//

renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
Expand All @@ -119,22 +140,93 @@
renderer.gammaInput = true;
renderer.gammaOutput = true;

var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
hdrCubeMap = new HDRCubeTextureLoader()
.setPath( './textures/cube/pisaHDR/' )
.setType( THREE.UnsignedByteType )
.load( hdrUrls, function () {

var pmremGenerator = new PMREMGenerator( hdrCubeMap );
pmremGenerator.update( renderer );

var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
pmremCubeUVPacker.update( renderer );

hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;

hdrCubeMap.magFilter = THREE.LinearFilter;
hdrCubeMap.needsUpdate = true;

pmremGenerator.dispose();
pmremCubeUVPacker.dispose();

} );

scene.background = hdrCubeMap;

stats = new Stats();
container.appendChild( stats.dom );

var controls = new OrbitControls( camera, renderer.domElement );

window.addEventListener( 'resize', onWindowResize, false );

function updateParams() {

spotLight.intensity = params.spotLight;
mesh.visible = params.showbox;

var color = new THREE.Color().setHSL(0, params.colorSaturation, params.colorBrightness * .5);

material1.opacity = material2.opacity = params.opacity;
material1.transparency = material2.transparency = params.transparency;
material1.metalness = material2.metalness = params.metalness;
material1.roughness = material2.roughness = params.roughness;
material1.roughness = material2.roughness = params.roughness;
material1.color = material2.color = color;

}

updateParams();

var gui = new GUI();
gui.add( params, 'opacity', 0, 1 ).onChange( function () {

material1.opacity = params.opacity;
material2.opacity = params.opacity;
gui.add( params, 'opacity', 0, 1 ).onChange( updateParams );
gui.add( params, 'transparency', 0, 1 ).onChange( updateParams );
gui.add( params, 'roughness', 0, 1 ).onChange( updateParams );
gui.add( params, 'metalness', 0, 1 ).onChange( updateParams );
gui.add( params, 'colorSaturation', 0, 1 ).onChange( updateParams );
gui.add( params, 'colorBrightness', 0, 1 ).onChange( updateParams );
gui.add( params, 'showbox' ).onChange( updateParams );
gui.add( params, 'spotLight', 0, 100 ).onChange( updateParams );

} );
gui.open();

//

function addLabel( name, location ) {

var textGeo = new THREE.TextBufferGeometry( name, {

font: font,

size: 3,
height: 0,
curveSegments: 1

} );

var textMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff } );
var textMesh = new THREE.Mesh( textGeo, textMaterial );
textMesh.position.copy( location );
scene.add( textMesh );

}

addLabel( "premultiplied alpha", new THREE.Vector3( 7, 20, 0 ) );

addLabel( "regular alpha", new THREE.Vector3( -37, 20, 0 ) );

}

function onWindowResize() {
Expand Down Expand Up @@ -163,6 +255,13 @@

function render() {

if( hdrCubeRenderTarget && material1.map != hdrCubeRenderTarget.texture ) {
material1.envMap = hdrCubeRenderTarget.texture;
material2.envMap = hdrCubeRenderTarget.texture;
material.envMap = hdrCubeRenderTarget.texture;
scene.background = hdrCubeMap;
}

for ( var i = 0, l = scene.children.length; i < l; i ++ ) {

var object = scene.children[ i ];
Expand Down
4 changes: 4 additions & 0 deletions src/materials/MeshPhysicalMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ function MeshPhysicalMaterial( parameters ) {
this.clearCoat = 0.0;
this.clearCoatRoughness = 0.0;

this.transparency = 0.0;

this.setValues( parameters );

}
Expand All @@ -43,6 +45,8 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
this.clearCoat = source.clearCoat;
this.clearCoatRoughness = source.clearCoatRoughness;

this.transparency = source.transparency;

return this;

};
Expand Down
1 change: 1 addition & 0 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2276,6 +2276,7 @@ function WebGLRenderer( parameters ) {

uniforms.clearCoat.value = material.clearCoat;
uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
uniforms.transparency.value = material.transparency;

}

Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderChunk.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export let ShaderChunk: {
points_vert: string;
shadow_frag: string;
shadow_vert: string;
transparentcy_pars_fragment: string;

premultiplied_alpha_fragment: string;
project_vertex: string;
Expand Down
2 changes: 2 additions & 0 deletions src/renderers/shaders/ShaderChunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import uv2_pars_fragment from './ShaderChunk/uv2_pars_fragment.glsl.js';
import uv2_pars_vertex from './ShaderChunk/uv2_pars_vertex.glsl.js';
import uv2_vertex from './ShaderChunk/uv2_vertex.glsl.js';
import worldpos_vertex from './ShaderChunk/worldpos_vertex.glsl.js';
import transparency_pars_fragment from './ShaderChunk/transparency_pars_fragment.glsl.js';

import background_frag from './ShaderLib/background_frag.glsl.js';
import background_vert from './ShaderLib/background_vert.glsl.js';
Expand Down Expand Up @@ -209,6 +210,7 @@ export var ShaderChunk = {
uv2_pars_vertex: uv2_pars_vertex,
uv2_vertex: uv2_vertex,
worldpos_vertex: worldpos_vertex,
transparency_pars_fragment: transparency_pars_fragment,

background_frag: background_frag,
background_vert: background_vert,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export default /* glsl */`
uniform float transparency;

// makes surface transparent without hiding the specular term
vec4 combineLight(const in vec3 diffuseLight, const in vec3 specularLight, const in GeometricContext geometry, const in PhysicalMaterial material) {

vec3 fresnel = BRDF_Specular_GGX_Environment(geometry, material.specularColor, material.specularRoughness);

// since we can't have per-channel opacity blending, we must settle for a single float (reflectance)
float reflectance = (fresnel.r + fresnel.g + fresnel.b) * (1. / 3.);

vec4 fragColor = vec4(specularLight, reflectance); // specularLight is already premultiplied by fresnel

float diffuseAlpha = (1. - reflectance) * (1. - transparency);
fragColor += vec4(diffuseLight * diffuseAlpha, diffuseAlpha);

// the above math is performed in premultiplied alpha
fragColor.rgb /= fragColor.a;

return fragColor;

}
`;
3 changes: 2 additions & 1 deletion src/renderers/shaders/ShaderLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ ShaderLib.physical = {
ShaderLib.standard.uniforms,
{
clearCoat: { value: 0 },
clearCoatRoughness: { value: 0 }
clearCoatRoughness: { value: 0 },
transparency: { value: 0 }
}
] ),

Expand Down
10 changes: 8 additions & 2 deletions src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ varying vec3 vViewPosition;
#include <normalmap_pars_fragment>
#include <roughnessmap_pars_fragment>
#include <metalnessmap_pars_fragment>
#include <transparency_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>

Expand Down Expand Up @@ -81,9 +82,14 @@ void main() {
// modulation
#include <aomap_fragment>

vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
gl_FragColor = combineLight(
reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance,
reflectedLight.directSpecular + reflectedLight.indirectSpecular,
geometry,
material
);

gl_FragColor = vec4( outgoingLight, diffuseColor.a );
gl_FragColor.a *= diffuseColor.a;

#include <tonemapping_fragment>
#include <encodings_fragment>
Expand Down