Created
March 2, 2023 23:34
-
-
Save rfikes4/631b43301b3a2306b039ddd7ab86200f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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