Skip to content

Instantly share code, notes, and snippets.

@rfikes4
Created March 2, 2023 23:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfikes4/631b43301b3a2306b039ddd7ab86200f to your computer and use it in GitHub Desktop.
Save rfikes4/631b43301b3a2306b039ddd7ab86200f to your computer and use it in GitHub Desktop.
/*
Texture Maps break down in the following way:
Map1- R: Flow, G: Height(water level), B: Erosion
Map2- R: AO, G: Curvature, B: Biomes
NormalMap- Normal map (OpenGL style)
Map4- R:Emission (dark side only), G: Cloud Layer
Ramp- Shared ramps to be used by all planets
*/
var PlanetShader = pc.createScript('planetShader');
PlanetShader.attributes.add('parentNode', {
type: 'entity',
description: 'Target the parent node of the template',
title: 'Parent Node'
});
PlanetShader.attributes.add('Debug', {
type: 'boolean',
default: false,
description: ' Enable this when editing shader variables at runtime, but disable it when done',
title: 'Debug Mode'
});
PlanetShader.attributes.add('LOD', {
type: 'number',
enum: [
{ 'LOD0': 0 },
{ 'LOD1': 1 }
],
default: 1
});
PlanetShader.attributes.add('Map1_1k', {
type: 'asset',
assetType: 'texture',
description: "R = Flow, G = Height, B = Erosion",
title: 'Map1 1k: _FHE'
});
PlanetShader.attributes.add('Map1_4k', {
type: 'asset',
assetType: 'texture',
description: "R = Flow, G = Height, B = Erosion",
title: 'Map1 4k: _FHE'
});
PlanetShader.attributes.add('Map2', {
type: 'asset',
assetType: 'texture',
description: "R = Occlusion, G = Curvature, B = Biomes",
title: 'Map2: _OCB'
});
PlanetShader.attributes.add('NormalMap', {
type: 'asset',
assetType: 'texture',
title: 'Normal Map: _N'
});
PlanetShader.attributes.add('Map4_1k', {
type: 'asset',
assetType: 'texture',
description: "R = Dark side emissive amount, G = Cloud Layer",
title: 'Map4_1k: _EC'
});
PlanetShader.attributes.add('Map4_4k', {
type: 'asset',
assetType: 'texture',
description: "R = Dark side emissive amount, G = Cloud Layer",
title: 'Map4_4k: _EC'
});
PlanetShader.attributes.add('Ramp', {
type: 'asset',
assetType: 'texture',
description: "U = Ramp Range, V = Ramp selection",
title: 'Ramp'
});
PlanetShader.attributes.add('RampOffset', {
type: 'number',
default: 0,
description: "U Offset of ramp texture (default: 0)",
title: 'Ramp Offset'
});
PlanetShader.attributes.add('RampScrollSpeed', {
type: 'number',
default: 0,
description: "Speed of ramp offset overtime (default: 0)",
title: 'Ramp Scroll Speed'
});
PlanetShader.attributes.add('SurfaceST', {
type: 'vec4',
default: [1.0, 1.0, 0.0, 0.0],
description: "Surface tiling + Offset (default: [1,1,0,0])",
title: 'Surface Tiling/Offset'
});
PlanetShader.attributes.add('SurfaceEmission', {
type: 'number',
min: 0,
max: 1,
default: 0,
description: "Emissive level of surface, useful for suns (default: 0)",
title: 'Surface Emission'
});
PlanetShader.attributes.add('SurfaceEmissionBrightness', {
type: 'number',
min: 0,
max: 50,
default: 1,
description: "Multiplier for emissive surface (default: 1)",
title: 'Surface Emission Brightness'
});
PlanetShader.attributes.add('TerrainRamp', {
type: 'number',
min: 0,
max: 255,
step: 1,
precision: 0,
description: "Select a terrain color ramp",
title: 'Terrain Ramp'
});
PlanetShader.attributes.add('TerrainTint', {
type: 'rgb',
default: [1.0, 1.0, 1.0],
description: "Terrain ramp tint (default: [1,1,1])",
title: 'Terrain Tint'
});
PlanetShader.attributes.add('WaterRamp', {
type: 'number',
min: 0,
max: 255,
step: 1,
precision: 0,
description: "Select a water color ramp",
title: 'Water Ramp'
});
PlanetShader.attributes.add('WaterTint', {
type: 'rgb',
default: [1.0, 1.0, 1.0],
description: "Water ramp tint (default: [1,1,1])",
title: 'Water Tint'
});
PlanetShader.attributes.add('WaterLevel', {
type: 'number',
min: -1,
max: 1.5,
description: "Water level",
title: 'Water Level'
});
PlanetShader.attributes.add('WaterMaskFalloff', {
type: 'number',
min: 0,
max: 1,
description: "Water mask feathering",
title: 'Water Mask Falloff'
});
PlanetShader.attributes.add('ErosionAmount', {
type: 'number',
min: -1,
max: 1.5,
default: -1,
description: "Erosion amount from terrain (default: -1)",
title: 'Erosion Amount'
});
PlanetShader.attributes.add('ErosionFalloff', {
type: 'number',
min: 0,
max: 1,
description: "Erosion amount fall off",
title: 'Erosion Falloff'
});
PlanetShader.attributes.add('TropicsDistance', {
type: 'number',
min: -1.0,
max: 1.5,
default: 0.5,
description: "Latitudinal distance for Tropics (default: 0.5)",
title: 'Tropics Distance'
});
PlanetShader.attributes.add('TropicsMaskFalloff', {
type: 'number',
min: 0.0,
max: 1.0,
default: 0.5,
description: "Falloff distance/contrast for tropics (default: 0.5)",
title: 'Tropics Mask Falloff'
});
PlanetShader.attributes.add('TropicsHueShift', {
type: 'number',
min: 0.0,
max: 6.28319,
description: "Tropics hue shift amount from terrain color (in radians)",
title: 'Tropics Hue '
});
PlanetShader.attributes.add('TropicsSaturation', {
type: 'number',
min: 0.0,
max: 1.0,
default: 1.0,
description: "Saturation level of tropics (default: 1)",
title: 'Tropics Saturation'
});
PlanetShader.attributes.add('TropicsBrightness', {
type: 'number',
min: -1.0,
max: 1.0,
default: 0.0,
description: "Brightness adjustment to tropics (default: 0)",
title: 'Tropics Brightness'
});
PlanetShader.attributes.add('PolesDistance', {
type: 'number',
min: -1.0,
max: 1.5,
default: 0.5,
description: "Distance for poles (default: 0.5)",
title: 'Poles Distance'
});
PlanetShader.attributes.add('PolesMaskFalloff', {
type: 'number',
min: 0.0,
max: 1.0,
default: 0.5,
description: "Falloff distance/contrast for poles (default: 0.5)",
title: 'Poles Mask Falloff'
});
PlanetShader.attributes.add('PolesHueShift', {
type: 'number',
min: 0.0,
max: 6.28319,
description: "Poles hue shift amount from terrain color (in radians)",
title: 'Poles Hue '
});
PlanetShader.attributes.add('PolesSaturation', {
type: 'number',
min: 0.0,
max: 1.0,
default: 1.0,
description: "Saturation level of poles (default: 1.0)",
title: 'Poles Saturation'
});
PlanetShader.attributes.add('PolesBrightness', {
type: 'number',
min: -1.0,
max: 1.0,
default: 0.0,
description: "Brightness adjustment to poles (default: 0)",
title: 'Poles Brightness'
});
PlanetShader.attributes.add('AtmosphereColor', {
type: 'rgb',
description: "Set to black for no atmosphere",
title: 'Atmosphere color'
});
PlanetShader.attributes.add('EclipseAtmosphere', {
type: 'boolean',
default: true,
description: 'Enabling will only apply atmosphere color to one side. Ideally enable for planets and disable for stars',
title: 'Eclipse Atmosphere'
});
PlanetShader.attributes.add('DarkSideEmissiveColor', {
type: 'rgb',
default: [0, 0, 0],
description: "Set to black for no emissive (default: [0, 0, 0])",
title: 'Dark side emissive color'
});
PlanetShader.attributes.add('CloudColor', {
type: 'rgba',
default: [0.8, 0.8, 0.8, 1.0],
description: "Cloud Color. Use alpha to control intensity (default: [0.8, 0.8, 0.8, 1.0])",
title: 'Cloud Layer'
});
PlanetShader.attributes.add('CloudST', {
type: 'vec4',
default: [1.0, 1.0, 0.0, 0.0],
description: "Cloud tiling + Offset (default: [1,1,0,0])",
title: 'Cloud Tiling/Offset'
});
PlanetShader.attributes.add('CloudSpeed', {
type: 'vec2',
default: [0.0, 0.0],
description: "Speed of cloud uv scrolling (default: [0.0,0.0])",
title: 'Cloud Speed'
});
PlanetShader.attributes.add('CurvatureAmount', {
type: 'number',
min: -1.0,
max: 1.5,
default: -1.0,
description: "Distance for poles (default: -1.0)",
title: 'Curvature Amount'
});
PlanetShader.attributes.add('CurvatureFalloff', {
type: 'number',
min: 0.0,
max: 1.0,
default: 0.01,
description: "Distance for poles (default: 0.01)",
title: 'Curvature Falloff'
});
PlanetShader.attributes.add('CurvatureHueShift', {
type: 'number',
min: 0.0,
max: 6.28319,
description: "Poles hue shift amount from terrain color (in radians)",
title: 'Curvature Hue'
});
PlanetShader.attributes.add('CurvatureSaturation', {
type: 'number',
min: 0.0,
max: 1.0,
default: 1.0,
description: "Saturation level of Curvature (default: 1.0)",
title: 'Curvature Saturation'
});
PlanetShader.attributes.add('CurvatureBrightness', {
type: 'number',
min: -1.0,
max: 1.0,
default: 0.0,
description: "Brightness adjustment to Curvature (default: 0)",
title: 'Curvature Brightness'
});
PlanetShader.attributes.add('AOIntensity', {
type: 'number',
min: 0.0,
max: 1.0,
default: 1.0,
description: "Ambient Occlusion Intensity (default: 1)",
title: 'AO Intensity'
});
PlanetShader.attributes.add('FlowMapping', {
type: 'boolean',
default: false,
description: ' Enable this when material needs flow mapping (more work in pixel shader!)',
title: 'Flow Mapping'
});
PlanetShader.attributes.add('FlowSpeed', {
type: 'number',
default: 0.0,
description: "Flow map speed. Negate to change direction (default: 0)",
title: 'Flow Speed'
});
PlanetShader.attributes.add('FlowIntensity', {
type: 'number',
min: 0.0,
default: 0.0,
description: "Flow Intensity (default: 0)",
title: 'Flow Intensity'
});
// initialize code called once per entity
PlanetShader.prototype.initialize = function () {
this.material = this.entity.render.meshInstances[0].material.clone();
this.entity.render.meshInstances[0].material = this.material;
this.material.chunks.baseVS = PlanetShader.baseVS;
this.material.chunks.startVS = this.EclipseAtmosphere ? PlanetShader.startVSEclipse : PlanetShader.startVS;
this.material.chunks.basePS = this.FlowMapping ? PlanetShader.basePSFlowMapping : PlanetShader.basePS;
this.material.chunks.startPS = this.FlowMapping ? PlanetShader.startPSFlowMapping : PlanetShader.startPS;
this.material.chunks.diffusePS = this.FlowMapping ? PlanetShader.diffusePSFlowMapping : PlanetShader.diffusePS;
this.material.chunks.emissivePS = this.FlowMapping ? PlanetShader.emissivePSFlowMapping : PlanetShader.emissivePS;
this.material.chunks.normalMapPS = PlanetShader.normalMapPS;
this.material.chunks.glossPS = PlanetShader.glossPS;
this.setLOD(1, this.parentNode);
this.time = 0.0;
this.material.setParameter('uTime', this.time);
// Set map parameters
var mapAttributes = [this.Ramp, this.Map1, this.Map2, this.NormalMap, this.Map4];
var mapUniforms = ['uRampMap', 'uMap1', 'uMap2', 'uNormalMap', 'uMap4'];
for (let i = 0; i < mapAttributes.length; i++) {
if (mapAttributes[i] !== null) {
this.material.setParameter(mapUniforms[i], mapAttributes[i].resource);
}
}
this.material.setParameter('uRO_RSS_SE_SEB', [this.RampOffset, this.RampScrollSpeed, this.SurfaceEmission, this.SurfaceEmissionBrightness]);
this.material.setParameter('uTR_WR_WMF_WL', [this.TerrainRamp / 255, this.WaterRamp / 255, this.WaterMaskFalloff, this.WaterLevel]);
this.material.setParameter('uEA_EF_THS_TS', [this.ErosionAmount, this.ErosionFalloff, this.TropicsHueShift, this.TropicsSaturation]);
this.material.setParameter('uTB_TD_TMF_PHS', [this.TropicsBrightness, this.TropicsDistance, this.TropicsMaskFalloff, this.PolesHueShift]);
this.material.setParameter('uPS_PB_PD_PMF', [this.PolesSaturation, this.PolesBrightness, this.PolesDistance, this.PolesMaskFalloff]);
this.material.setParameter('uCHS_CS_CB_CA', [this.CurvatureHueShift, this.CurvatureSaturation, this.CurvatureBrightness, this.CurvatureAmount]);
this.material.setParameter('uCF_AOI_FS_FI', [this.CurvatureFalloff, this.AOIntensity, this.FlowSpeed, this.FlowIntensity]);
this.material.setParameter('uSurfaceST', [this.SurfaceST.x, this.SurfaceST.y, this.SurfaceST.z, this.SurfaceST.w]);
this.material.setParameter('uTerrainTint', [this.TerrainTint.r, this.TerrainTint.g, this.TerrainTint.b]);
this.material.setParameter('uWaterTint', [this.WaterTint.r, this.WaterTint.g, this.WaterTint.b]);
this.material.setParameter('uAtmosphereColor', [this.AtmosphereColor.r, this.AtmosphereColor.g, this.AtmosphereColor.b]);
this.material.setParameter('uDarkSideEmissiveColor', [this.DarkSideEmissiveColor.r, this.DarkSideEmissiveColor.g, this.DarkSideEmissiveColor.b]);
this.material.setParameter('uCloudColor', [this.CloudColor.r, this.CloudColor.g, this.CloudColor.b, this.CloudColor.a]);
this.material.setParameter('uCloudST', [this.CloudST.x, this.CloudST.y, this.CloudST.z, this.CloudST.w]);
this.material.setParameter('uCloudSpeed', [this.CloudSpeed.x, this.CloudSpeed.y]);
this.material.update();
this.on('attr:LOD', function (value, prev) {
this.setLOD(value, this.parentNode);
});
this.app.on("LOD_PLANET_SHADER", this.setLOD, this);
this.on('destroy', function () {
this.app.mouse.off("LOD_PLANET_SHADER", this.setLOD, this);
});
};
PlanetShader.prototype.setLOD = function (lod, entity) {
if (entity == this.parentNode) {
switch (lod) {
case 0:
this.Map1 = this.Map1_4k;
this.Map4 = this.Map4_4k;
break;
case 1:
this.Map1 = this.Map1_1k;
this.Map4 = this.Map4_1k;
break;
default:
break;
}
this.material.setParameter('uMap1', this.Map1.resource);
this.material.setParameter('uMap4', this.Map4.resource);
}
};
// update code called every frame
PlanetShader.prototype.update = function (dt) {
this.time += dt;
this.material.setParameter('uTime', this.time);
if (this.Debug === true) {
// Set map parameters
var mapAttributes = [this.Ramp, this.Map1, this.Map2, this.NormalMap, this.Map4];
var mapUniforms = ['uRampMap', 'uMap1', 'uMap2', 'uNormalMap', 'uMap4'];
for (let i = 0; i < mapAttributes.length; i++) {
if (mapAttributes[i] !== null) {
this.material.setParameter(mapUniforms[i], mapAttributes[i].resource);
}
}
this.material.setParameter('uRO_RSS_SE_SEB', [this.RampOffset, this.RampScrollSpeed, this.SurfaceEmission, this.SurfaceEmissionBrightness]);
this.material.setParameter('uTR_WR_WMF_WL', [this.TerrainRamp / 255, this.WaterRamp / 255, this.WaterMaskFalloff, this.WaterLevel]);
this.material.setParameter('uEA_EF_THS_TS', [this.ErosionAmount, this.ErosionFalloff, this.TropicsHueShift, this.TropicsSaturation]);
this.material.setParameter('uTB_TD_TMF_PHS', [this.TropicsBrightness, this.TropicsDistance, this.TropicsMaskFalloff, this.PolesHueShift]);
this.material.setParameter('uPS_PB_PD_PMF', [this.PolesSaturation, this.PolesBrightness, this.PolesDistance, this.PolesMaskFalloff]);
this.material.setParameter('uCHS_CS_CB_CA', [this.CurvatureHueShift, this.CurvatureSaturation, this.CurvatureBrightness, this.CurvatureAmount]);
this.material.setParameter('uCF_AOI_FS_FI', [this.CurvatureFalloff, this.AOIntensity, this.FlowSpeed, this.FlowIntensity]);
this.material.setParameter('uSurfaceST', [this.SurfaceST.x, this.SurfaceST.y, this.SurfaceST.z, this.SurfaceST.w]);
this.material.setParameter('uTerrainTint', [this.TerrainTint.r, this.TerrainTint.g, this.TerrainTint.b]);
this.material.setParameter('uWaterTint', [this.WaterTint.r, this.WaterTint.g, this.WaterTint.b]);
this.material.setParameter('uAtmosphereColor', [this.AtmosphereColor.r, this.AtmosphereColor.g, this.AtmosphereColor.b]);
this.material.setParameter('uDarkSideEmissiveColor', [this.DarkSideEmissiveColor.r, this.DarkSideEmissiveColor.g, this.DarkSideEmissiveColor.b]);
this.material.setParameter('uCloudColor', [this.CloudColor.r, this.CloudColor.g, this.CloudColor.b, this.CloudColor.a]);
this.material.setParameter('uCloudST', [this.CloudST.x, this.CloudST.y, this.CloudST.z, this.CloudST.w]);
this.material.setParameter('uCloudSpeed', [this.CloudSpeed.x, this.CloudSpeed.y]);
this.material.update();
}
};
// swap method called for script hot-reloading
// inherit your script state here
PlanetShader.prototype.swap = function (old) {
this.material = this.entity.render.meshInstances[0].material.clone();
this.entity.render.meshInstances[0].material = this.material;
this.material.chunks.baseVS = PlanetShader.baseVS;
this.material.chunks.startVS = this.EclipseAtmosphere ? PlanetShader.startVSEclipse : PlanetShader.startVS;
this.material.chunks.basePS = this.FlowMapping ? PlanetShader.basePSFlowMapping : PlanetShader.basePS;
this.material.chunks.startPS = this.FlowMapping ? PlanetShader.startPSFlowMapping : PlanetShader.startPS;
this.material.chunks.diffusePS = this.FlowMapping ? PlanetShader.diffusePSFlowMapping : PlanetShader.diffusePS;
this.material.chunks.normalMapPS = PlanetShader.normalMapPS;
this.material.chunks.glossPS = PlanetShader.glossPS;
this.material.chunks.emissivePS = this.FlowMapping ? PlanetShader.emissivePSFlowMapping : PlanetShader.emissivePS;
this.time = 0.0;
// Set map parameters
var mapAttributes = [this.Ramp, this.Map1, this.Map2, this.NormalMap, this.Map4];
var mapUniforms = ['uRampMap', 'uMap1', 'uMap2', 'uNormalMap', 'uMap4'];
for (let i = 0; i < mapAttributes.length; i++) {
if (mapAttributes[i] !== null) {
this.material.setParameter(mapUniforms[i], mapAttributes[i].resource);
}
}
this.material.setParameter('uRO_RSS_SE_SEB', [this.RampOffset, this.RampScrollSpeed, this.SurfaceEmission, this.SurfaceEmissionBrightness]);
this.material.setParameter('uTR_WR_WMF_WL', [this.TerrainRamp / 255, this.WaterRamp / 255, this.WaterMaskFalloff, this.WaterLevel]);
this.material.setParameter('uEA_EF_THS_TS', [this.ErosionAmount, this.ErosionFalloff, this.TropicsHueShift, this.TropicsSaturation]);
this.material.setParameter('uTB_TD_TMF_PHS', [this.TropicsBrightness, this.TropicsDistance, this.TropicsMaskFalloff, this.PolesHueShift]);
this.material.setParameter('uPS_PB_PD_PMF', [this.PolesSaturation, this.PolesBrightness, this.PolesDistance, this.PolesMaskFalloff]);
this.material.setParameter('uCHS_CS_CB_CA', [this.CurvatureHueShift, this.CurvatureSaturation, this.CurvatureBrightness, this.CurvatureAmount]);
this.material.setParameter('uCF_AOI_FS_FI', [this.CurvatureFalloff, this.AOIntensity, this.FlowSpeed, this.FlowIntensity]);
this.material.setParameter('uSurfaceST', [this.SurfaceST.x, this.SurfaceST.y, this.SurfaceST.z, this.SurfaceST.w]);
this.material.setParameter('uTerrainTint', [this.TerrainTint.r, this.TerrainTint.g, this.TerrainTint.b]);
this.material.setParameter('uWaterTint', [this.WaterTint.r, this.WaterTint.g, this.WaterTint.b]);
this.material.setParameter('uAtmosphereColor', [this.AtmosphereColor.r, this.AtmosphereColor.g, this.AtmosphereColor.b]);
this.material.setParameter('uDarkSideEmissiveColor', [this.DarkSideEmissiveColor.r, this.DarkSideEmissiveColor.g, this.DarkSideEmissiveColor.b]);
this.material.setParameter('uCloudColor', [this.CloudColor.r, this.CloudColor.g, this.CloudColor.b, this.CloudColor.a]);
this.material.setParameter('uCloudST', [this.CloudST.x, this.CloudST.y, this.CloudST.z, this.CloudST.w]);
this.material.setParameter('uCloudSpeed', [this.CloudSpeed.x, this.CloudSpeed.y]);
this.material.update();
};
// to learn more about script anatomy, please read:
// https://developer.playcanvas.com/en/user-manual/scripting/
PlanetShader.baseVS = `
// START OF PLAYCANVAS BUILT INS
attribute vec3 vertex_position;
attribute vec3 vertex_normal;
attribute vec4 vertex_tangent;
attribute vec2 vertex_texCoord0;
attribute vec2 vertex_texCoord1;
attribute vec4 vertex_color;
uniform mat4 matrix_viewProjection;
uniform mat4 matrix_model;
uniform mat3 matrix_normal;
vec3 dPositionW;
mat4 dModelMatrix;
mat3 dNormalMatrix;
// END OF PLAYCANVAS BUILT INS END
uniform vec3 view_position;
uniform vec3 light0_position;
uniform float uTime;
uniform vec4 uSurfaceST;
uniform vec4 uCloudST;
uniform vec2 uCloudSpeed;
varying vec4 vSurfaceCloudUvs;
varying vec3 vEmissiveAmounts;
`;
PlanetShader.startVS = `
void main(void) {
// START OF PLAYCANVAS BUILT INS
gl_Position = getPosition();
// END OF PLAYCANVAS BUILT INS
// Getting vertex normal here since we don't have access to dVertexNormalW in vertex shader
vNormalW = getNormal();
// Do the uv calculations per vertex, and pack into a vec4 to send to the fragment shader
vSurfaceCloudUvs.xy = (vertex_texCoord0 + uSurfaceST.zw) * uSurfaceST.xy;
vSurfaceCloudUvs.zw = (vertex_texCoord0 + uCloudST.zw) * uCloudST.xy + (uCloudSpeed.xy * vec2(uTime));
// Do the fresnel calculations per vertex and pack into a vec2
vec3 V = normalize(dPositionW.xyz - view_position.xyz);
vec3 N = normalize(vNormalW);
vec3 L = normalize(dPositionW.xyz - light0_position.xyz);
float LdotN = dot(L, N);
float fresnel = pow(1.0 + dot(V, N), 4.0);
float eclipse = 4.0 - LdotN;
vEmissiveAmounts.x = fresnel * eclipse + (fresnel * 0.1); // Regular atmosphere for non emissive planets. Maintly affects the lit side, with some view based mixed in to fake scattering
vEmissiveAmounts.y = 1.0 - pow(1.0 + dot(V, N), 1.0); // Center based glow for emissive planets
vEmissiveAmounts.z = pow(max(0.0,LdotN),2.0); // Dot calculation for emissive map to show only on dark side of planet
`;
PlanetShader.startVSEclipse = `
void main(void) {
// START OF PLAYCANVAS BUILT INS
gl_Position = getPosition();
// END OF PLAYCANVAS BUILT INS
// Getting vertex normal here since we don't have access to dVertexNormalW in vertex shader
vNormalW = getNormal();
// vNormalW = vertex_normal;
// Do the uv calculations per vertex, and pack into a vec4 to send to the fragment shader
vSurfaceCloudUvs.xy = (vertex_texCoord0 + uSurfaceST.zw) * uSurfaceST.xy;
vSurfaceCloudUvs.zw = (vertex_texCoord0 + uCloudST.zw) * uCloudST.xy + (uCloudSpeed.xy * vec2(uTime));
// Do the fresnel calculations per vertex and pack into a vec2
vec3 V = normalize(dPositionW.xyz - view_position.xyz);
vec3 N = normalize(vNormalW);
vec3 L = normalize(dPositionW.xyz - light0_position.xyz);
float LdotN = dot(L, N);
float fresnel = pow(1.0 + dot(V, N), 4.0);
float eclipse = pow(1.0 - LdotN, 2.0);
vEmissiveAmounts.x = fresnel * eclipse + (fresnel * 0.1); // Regular atmosphere for non emissive planets. Maintly affects the lit side, with some view based mixed in to fake scattering
vEmissiveAmounts.y = 1.0 - pow(1.0 + dot(V, N), 1.0); // Center based glow for emissive planets
vEmissiveAmounts.z = pow(max(0.0,LdotN),2.0); // Dot calculation for emissive map to show only on dark side of planet
`;
PlanetShader.basePS = `
// START OF PLAYCANVAS BUILT INS
uniform vec3 view_position;
uniform vec3 light_globalAmbient;
float square(float x) {
return x*x;
}
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
vec3 saturate(vec3 x) {
return clamp(x, vec3(0.0), vec3(1.0));
}
// END OF PLAYCANVAS BUILT INS
// Basic hue shift found here https://gist.github.com/mairod/a75e7b44f68110e1576d77419d608786?permalink_comment_id=3195243#gistcomment-3195243
vec3 hueShift(vec3 color, float hue) {
const vec3 k = vec3(0.57735, 0.57735, 0.57735);
float cosAngle = cos(hue);
return vec3(color * cosAngle + cross(k, color) * sin(hue) + k * dot(k, color) * (1.0 - cosAngle));
}
// UNIFORMS
uniform float uTime;
uniform sampler2D uRampMap;
uniform sampler2D uMap1;
uniform sampler2D uMap2;
uniform sampler2D uMap4;
uniform sampler2D uNormalMap;
uniform lowp vec4 uRO_RSS_SE_SEB; // Packed floats: RampOffset, RampScrollSpeed, SurfaceEmission, SurfaceEmissionBrightness
uniform lowp vec4 uTR_WR_WMF_WL; // Packed floats: TerrainRamp, WaterRamp, WaterMaskFalloff, WaterLevel
uniform lowp vec4 uEA_EF_THS_TS; // Packed floats: ErosionAmount, ErosionFalloff, TropicsHueShift, TropicsSaturation
uniform lowp vec4 uTB_TD_TMF_PHS; // Packed floats: TropicsBrightness, TropicsDistance, TropicsMaskFalloff, PolesHuShift
uniform lowp vec4 uPS_PB_PD_PMF; // Packed floats: PolesSaturation, PolesBrightness, PolesDistance, PolesMaskFalloff
uniform lowp vec4 uCHS_CS_CB_CA; // Packed floats: CurvatureHueShift, CurvatureSaturation, CurvatureBrightness, CurvatureAmount
uniform lowp vec4 uCF_AOI_FS_FI; // Packed floats: CurvatureFalloff, AOIntensity, FlowSpeed, FlowIntensity
uniform lowp vec3 uTerrainTint;
uniform lowp vec3 uWaterTint;
uniform lowp vec3 uAtmosphereColor;
uniform lowp vec3 uDarkSideEmissiveColor;
uniform lowp vec4 uCloudColor;
// VARYINGS
varying vec4 vSurfaceCloudUvs;
varying vec3 vEmissiveAmounts;
// VARIABLES
float waterMask;
vec3 map1;
vec3 map2;
vec3 map4;
vec3 clouds;
vec3 terrainWaterMix;
const vec3 desaturationVector = vec3( 0.2126, 0.7152, 0.0722); // Dotting against this magic vector converts an RGB to greyscale.
`;
PlanetShader.basePSFlowMapping = `
// START OF PLAYCANVAS BUILT INS
uniform vec3 view_position;
uniform vec3 light_globalAmbient;
float square(float x) {
return x*x;
}
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
vec3 saturate(vec3 x) {
return clamp(x, vec3(0.0), vec3(1.0));
}
// END OF PLAYCANVAS BUILT INS
// Basic hue shift found here https://gist.github.com/mairod/a75e7b44f68110e1576d77419d608786?permalink_comment_id=3195243#gistcomment-3195243
vec3 hueShift(vec3 color, float hue) {
const vec3 k = vec3(0.57735, 0.57735, 0.57735);
float cosAngle = cos(hue);
return vec3(color * cosAngle + cross(k, color) * sin(hue) + k * dot(k, color) * (1.0 - cosAngle));
}
// UNIFORMS
uniform float uTime;
uniform sampler2D uRampMap;
uniform sampler2D uMap1;
uniform sampler2D uMap2;
uniform sampler2D uMap4;
uniform sampler2D uNormalMap;
uniform lowp vec4 uRO_RSS_SE_SEB; // Packed floats: RampOffset, RampScrollSpeed, SurfaceEmission, SurfaceEmissionBrightness
uniform lowp vec4 uTR_WR_WMF_WL; // Packed floats: TerrainRamp, WaterRamp, WaterMaskFalloff, WaterLevel
uniform lowp vec4 uEA_EF_THS_TS; // Packed floats: ErosionAmount, ErosionFalloff, TropicsHueShift, TropicsSaturation
uniform lowp vec4 uTB_TD_TMF_PHS; // Packed floats: TropicsBrightness, TropicsDistance, TropicsMaskFalloff, PolesHuShift
uniform lowp vec4 uPS_PB_PD_PMF; // Packed floats: PolesSaturation, PolesBrightness, PolesDistance, PolesMaskFalloff
uniform lowp vec4 uCHS_CS_CB_CA; // Packed floats: CurvatureHueShift, CurvatureSaturation, CurvatureBrightness, CurvatureAmount
uniform lowp vec4 uCF_AOI_FS_FI; // Packed floats: CurvatureFalloff, AOIntensity, FlowSpeed, FlowIntensity
uniform lowp vec3 uTerrainTint;
uniform lowp vec3 uWaterTint;
uniform lowp vec3 uAtmosphereColor;
uniform lowp vec3 uDarkSideEmissiveColor;
uniform lowp vec4 uCloudColor;
// VARYINGS
varying vec4 vSurfaceCloudUvs;
varying vec3 vEmissiveAmounts;
// VARIABLES
float waterMask;
vec3 map1;
vec3 map2;
vec3 map4;
vec3 clouds;
vec3 terrainWaterMix;
const vec3 desaturationVector = vec3( 0.2126, 0.7152, 0.0722); // Dotting against this magic vector converts an RGB to greyscale.
vec3 mixedFlowMap1;
vec3 mixedFlowMap2;
vec3 mixedFlowMap4;
`;
PlanetShader.startPS = `
void main(void) {
// START OF PLAYCANVAS BUILT INS
dReflection = vec4(0);
#ifdef LIT_CLEARCOAT
ccSpecularLight = vec3(0);
ccReflection = vec3(0);
#endif
// END OF PLAYCANVAS BUILT INS
// Do the basic texture map lookups (except normal map which is done in its own chunk)
map1 = texture2DBias(uMap1, vSurfaceCloudUvs.xy, textureBias).rgb;
map2 = texture2DBias(uMap2, vSurfaceCloudUvs.xy, textureBias).rgb;
map4 = texture2DBias(uMap4, vSurfaceCloudUvs.xy, textureBias).rgb;
clouds = texture2DBias(uMap4, vSurfaceCloudUvs.zw, textureBias).rgb;
waterMask = clamp(smoothstep(uTR_WR_WMF_WL.w, uTR_WR_WMF_WL.w + uTR_WR_WMF_WL.z, map1.g),0.0,1.0);
`;
PlanetShader.startPSFlowMapping = `
void main(void) {
// START OF PLAYCANVAS BUILT INS
dReflection = vec4(0);
#ifdef LIT_CLEARCOAT
ccSpecularLight = vec3(0);
ccReflection = vec3(0);
#endif
// END OF PLAYCANVAS BUILT INS
// Do the basic texture map lookups (except normal map which is done in its own chunk)
map1 = texture2DBias(uMap1, vSurfaceCloudUvs.xy, textureBias).rgb;
map2 = texture2DBias(uMap2, vSurfaceCloudUvs.xy, textureBias).rgb;
map4 = texture2DBias(uMap4, vSurfaceCloudUvs.xy, textureBias).rgb;
clouds = texture2DBias(uMap4, vSurfaceCloudUvs.zw, textureBias).rgb;
// Set up seamless flow values
float flow = map1.r;
float fractTime01 = fract(uTime * uCF_AOI_FS_FI.z);
float fractTime02 = fract(fractTime01 + 0.5);
float flowMix = abs((fractTime01 - 0.5) * 2.0);
vec2 flowUv = vec2(vUv0.x + (flow * fractTime01 * 0.1), vUv0.y);
// Distort map1 u value based on the looping flow amounts.
vec3 flowedMap1_a = texture2DBias(uMap1, vec2(vSurfaceCloudUvs.x + (flow * fractTime01 * uCF_AOI_FS_FI.w), vSurfaceCloudUvs.y), textureBias).rgb;
vec3 flowedMap1_b = texture2DBias(uMap1, vec2(vSurfaceCloudUvs.x + (flow * fractTime02 * uCF_AOI_FS_FI.w), vSurfaceCloudUvs.y), textureBias).rgb;
mixedFlowMap1 = mix(flowedMap1_a, flowedMap1_b, flowMix);
// Distort map2 u value based on the looping flow amounts.
vec3 flowedMap2_a = texture2DBias(uMap2, vec2(vSurfaceCloudUvs.x + (flow * fractTime01 * uCF_AOI_FS_FI.w), vSurfaceCloudUvs.y), textureBias).rgb;
vec3 flowedMap2_b = texture2DBias(uMap2, vec2(vSurfaceCloudUvs.x + (flow * fractTime02 * uCF_AOI_FS_FI.w), vSurfaceCloudUvs.y), textureBias).rgb;
mixedFlowMap2 = mix(flowedMap2_a, flowedMap2_b, flowMix);
// Distort map4 u value based on the looping flow amounts.
vec3 flowedMap4_a = texture2DBias(uMap4, vec2(vSurfaceCloudUvs.x + (flow * fractTime01 * uCF_AOI_FS_FI.w), vSurfaceCloudUvs.y), textureBias).rgb;
vec3 flowedMap4_b = texture2DBias(uMap4, vec2(vSurfaceCloudUvs.x + (flow * fractTime02 * uCF_AOI_FS_FI.w), vSurfaceCloudUvs.y), textureBias).rgb;
mixedFlowMap4 = mix(flowedMap4_a, flowedMap4_b, flowMix);
waterMask = clamp(smoothstep(uTR_WR_WMF_WL.w, uTR_WR_WMF_WL.w + uTR_WR_WMF_WL.z, mixedFlowMap1.g),0.0,1.0);
`;
PlanetShader.glossPS = `
#ifdef MAPFLOAT
uniform float material_shininess;
#endif
void getGlossiness() {
dGlossiness = 1.0;
// Mask out any shininess that isn't on the water
dGlossiness *= material_shininess * (1.0 - waterMask);
dGlossiness += 0.0000001;
}
`;
PlanetShader.emissivePS = `
#ifdef MAPCOLOR
uniform vec3 material_emissive;
#endif
#ifdef MAPFLOAT
uniform float material_emissiveIntensity;
#endif
void getEmission() {
dEmission = vec3(1.0);
vec3 darkSideEmission = uDarkSideEmissiveColor * (map4.r * vEmissiveAmounts.z) * waterMask;
vec3 surfaceEmission = mix(darkSideEmission, terrainWaterMix * (vEmissiveAmounts.y * uRO_RSS_SE_SEB.w), uRO_RSS_SE_SEB.z);
dEmission = uAtmosphereColor * vEmissiveAmounts.x + surfaceEmission;
}
`;
PlanetShader.emissivePSFlowMapping = `
#ifdef MAPCOLOR
uniform vec3 material_emissive;
#endif
#ifdef MAPFLOAT
uniform float material_emissiveIntensity;
#endif
void getEmission() {
dEmission = vec3(1.0);
vec3 darkSideEmission = uDarkSideEmissiveColor * (mixedFlowMap4.r * vEmissiveAmounts.z) * waterMask;
vec3 surfaceEmission = mix(darkSideEmission, terrainWaterMix * (vEmissiveAmounts.y * uRO_RSS_SE_SEB.w), uRO_RSS_SE_SEB.z);
dEmission = uAtmosphereColor * vEmissiveAmounts.x + surfaceEmission;
}
`;
PlanetShader.diffusePS = `
#ifdef MAPCOLOR
uniform vec3 material_diffuse;
#endif
void getAlbedo() {
dAlbedo = vec3(1.0);
#ifdef MAPCOLOR
dAlbedo *= material_diffuse.rgb;
#endif
#ifdef MAPTEXTURE
// Set up base terrain ramp coloring and tint it. Includes ramp offset values
vec3 terrainColor = $DECODE(texture2D(uRampMap, vec2(map1.g + uRO_RSS_SE_SEB.x + (uTime * uRO_RSS_SE_SEB.y), uTR_WR_WMF_WL.x))).rgb;
terrainColor *= uTerrainTint;
// Set up water ramp and tint it
vec3 waterColor = $DECODE(texture2D(uRampMap, vec2(map1.g, uTR_WR_WMF_WL.y))).rgb;
waterColor *= uWaterTint;
// Set up RGB value of tropics and mix it to terrain color
vec3 tropicsColor = hueShift(terrainColor, uEA_EF_THS_TS.z);
vec3 tropicsDesaturate = vec3(dot(tropicsColor, desaturationVector));
tropicsColor = (mix(tropicsDesaturate, tropicsColor, uEA_EF_THS_TS.w) + uTB_TD_TMF_PHS.x);
terrainColor = mix(terrainColor, tropicsColor, smoothstep(1.0 - uTB_TD_TMF_PHS.y, 1.0 - uTB_TD_TMF_PHS.y + uTB_TD_TMF_PHS.z, map2.b));
// Set up RGB value of Poles and mix it to terrain color
vec3 polesColor = hueShift(terrainColor, uTB_TD_TMF_PHS.w);
vec3 polesDesaturate = vec3(dot(polesColor, desaturationVector));
polesColor = (mix(polesDesaturate, polesColor, uPS_PB_PD_PMF.x) + uPS_PB_PD_PMF.y);
terrainColor = mix(terrainColor, polesColor, smoothstep(1.0 - uPS_PB_PD_PMF.z, 1.0 - uPS_PB_PD_PMF.z + uPS_PB_PD_PMF.w, 1.0 -map2.b));
// Set up RGB value of Curvature map and mix it to terrain color
vec3 curvatureColor = hueShift(terrainColor, uCHS_CS_CB_CA.x);
vec3 curvatureDesaturate = vec3(dot(curvatureColor, desaturationVector));
curvatureColor = (mix(curvatureDesaturate, curvatureColor, uCHS_CS_CB_CA.y) + uCHS_CS_CB_CA.z);
terrainColor = mix(curvatureColor, terrainColor, smoothstep(uCHS_CS_CB_CA.w, uCHS_CS_CB_CA.w + uCF_AOI_FS_FI.x, map2.g));
// Mix in AO map as specified
terrainColor = mix(terrainColor, terrainColor * map2.r, uCF_AOI_FS_FI.y);
float erosion = smoothstep(1.0 - uEA_EF_THS_TS.x, (1.0 - uEA_EF_THS_TS.x) + uEA_EF_THS_TS.y, map1.b);
terrainWaterMix = mix(terrainColor, waterColor, erosion);
terrainWaterMix = mix(terrainWaterMix, waterColor, 1.0 - waterMask);
terrainWaterMix = mix(terrainWaterMix, uCloudColor.rgb, clouds.g * uCloudColor.w);
dAlbedo *= addAlbedoDetail(terrainWaterMix);
#endif
#ifdef MAPVERTEX
dAlbedo *= gammaCorrectInput(saturate(vVertexColor.$VC));
#endif
}
`;
PlanetShader.diffusePSFlowMapping = `
#ifdef MAPCOLOR
uniform vec3 material_diffuse;
#endif
void getAlbedo() {
dAlbedo = vec3(1.0);
#ifdef MAPCOLOR
dAlbedo *= material_diffuse.rgb;
#endif
#ifdef MAPTEXTURE
// Set up base terrain ramp coloring and tint it. Includes ramp offset values
vec3 terrainColor = $DECODE(texture2D(uRampMap, vec2(mixedFlowMap1.g + uRO_RSS_SE_SEB.x + (uTime * uRO_RSS_SE_SEB.y), uTR_WR_WMF_WL.x))).rgb;
terrainColor *= uTerrainTint;
// Set up water ramp and tint it
vec3 waterColor = $DECODE(texture2D(uRampMap, vec2(mixedFlowMap1.g, uTR_WR_WMF_WL.y))).rgb;
waterColor *= uWaterTint;
// Set up RGB value of tropics and mix it to terrain color
vec3 tropicsColor = hueShift(terrainColor, uEA_EF_THS_TS.z);
vec3 tropicsDesaturate = vec3(dot(tropicsColor, desaturationVector));
tropicsColor = (mix(tropicsDesaturate, tropicsColor, uEA_EF_THS_TS.w) + uTB_TD_TMF_PHS.x);
terrainColor = mix(terrainColor, tropicsColor, smoothstep(1.0 - uTB_TD_TMF_PHS.y, 1.0 - uTB_TD_TMF_PHS.y + uTB_TD_TMF_PHS.z, mixedFlowMap2.b));
// Set up RGB value of Poles and mix it to terrain color
vec3 polesColor = hueShift(terrainColor, uTB_TD_TMF_PHS.w);
vec3 polesDesaturate = vec3(dot(polesColor, desaturationVector));
polesColor = (mix(polesDesaturate, polesColor, uPS_PB_PD_PMF.x) + uPS_PB_PD_PMF.y);
terrainColor = mix(terrainColor, polesColor, smoothstep(1.0 - uPS_PB_PD_PMF.z, 1.0 - uPS_PB_PD_PMF.z + uPS_PB_PD_PMF.w, 1.0 -mixedFlowMap2.b));
// Set up RGB value of Curvature map and mix it to terrain color
vec3 curvatureColor = hueShift(terrainColor, uCHS_CS_CB_CA.x);
vec3 curvatureDesaturate = vec3(dot(curvatureColor, desaturationVector));
curvatureColor = (mix(curvatureDesaturate, curvatureColor, uCHS_CS_CB_CA.y) + uCHS_CS_CB_CA.z);
terrainColor = mix(curvatureColor, terrainColor, smoothstep(uCHS_CS_CB_CA.w, uCHS_CS_CB_CA.w + uCF_AOI_FS_FI.x, mixedFlowMap2.g));
// Mix in AO map as specified
terrainColor = mix(terrainColor, terrainColor * map2.r, uCF_AOI_FS_FI.y);
float erosion = smoothstep(1.0 - uEA_EF_THS_TS.x, (1.0 - uEA_EF_THS_TS.x) + uEA_EF_THS_TS.y, mixedFlowMap1.b);
terrainWaterMix = mix(terrainColor, waterColor, erosion);
terrainWaterMix = mix(terrainWaterMix, waterColor, 1.0 - waterMask);
terrainWaterMix = mix(terrainWaterMix, uCloudColor.rgb, clouds.g * uCloudColor.w);
dAlbedo *= addAlbedoDetail(terrainWaterMix);
#endif
#ifdef MAPVERTEX
dAlbedo *= gammaCorrectInput(saturate(vVertexColor.$VC));
#endif
}
`;
PlanetShader.normalMapPS = `
#ifdef MAPTEXTURE
uniform float material_bumpiness;
#endif
void getNormal() {
#ifdef MAPTEXTURE
vec3 normalMap = unpackNormal(texture2DBias(uNormalMap, vSurfaceCloudUvs.xy, textureBias));
normalMap = mix(vec3(0.0, 0.0, 1.0), normalMap, material_bumpiness);
vec3 waterNormalMix = mix(vec3(0.0, 0.0, 1.0), normalMap, waterMask - (clouds.g * uCloudColor.w));
dNormalW = normalize(dTBN * addNormalDetail(waterNormalMix));
#else
dNormalW = dVertexNormalW;
#endif
}
`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment