From 5565be120cd8e32d58849b53cd0b902dc8d4492f Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Tue, 31 Mar 2020 16:32:59 +0300 Subject: [PATCH] incomplete ground and space shading --- assets/shaders/planet.fs | 15 ++++ assets/shaders/planet.vs | 91 ++++++++++++++++++++++ src/engine/components/planet/atmosphere.js | 20 +++-- src/engine/components/planet/index.js | 33 ++++++++ src/index.js | 21 ++--- 5 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 assets/shaders/planet.fs create mode 100644 assets/shaders/planet.vs diff --git a/assets/shaders/planet.fs b/assets/shaders/planet.fs new file mode 100644 index 0000000..667f425 --- /dev/null +++ b/assets/shaders/planet.fs @@ -0,0 +1,15 @@ +precision mediump float; + +uniform float g; +uniform float g2; + +uniform sampler2D texture0; + +varying vec3 c0; +varying vec3 c1; +varying vec2 vUV; + +void main (void) { + vec3 diffuse = texture2D(texture0, vUV).xyz; + gl_FragColor = vec4(c1, 1.0) + vec4(diffuse * c0, 1.0); +} diff --git a/assets/shaders/planet.vs b/assets/shaders/planet.vs new file mode 100644 index 0000000..75d63a1 --- /dev/null +++ b/assets/shaders/planet.vs @@ -0,0 +1,91 @@ +precision mediump float; + +attribute vec3 aVertexPosition; +attribute vec3 aNormal; +attribute vec2 aTexCoords; + +uniform vec3 v3CameraPosition; // The camera position +uniform vec3 v3LightPosition; // The direction vector to the light source +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fCameraHeight; // The camera's current height +uniform float fCameraHeight2; // fCameraHeight^2 +uniform float fOuterRadius; // The outer (atmosphere) radius +uniform float fOuterRadius2; // fOuterRadius^2 +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fInnerRadius2; // fInnerRadius^2 +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + +const int nSamples = 3; +const float fSamples = 3.0; + +varying vec3 c0; +varying vec3 c1; +varying vec3 vNormal; +varying vec2 vUV; + +uniform mat4 uModelMatrix; +uniform mat4 uViewMatrix; +uniform mat4 uProjectionMatrix; + +float scale(float fCos) { + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +void main(void) { + // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Ray = aVertexPosition - v3CameraPosition; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere) + float B = 2.0 * dot(v3CameraPosition, v3Ray); + float C = fCameraHeight2 - fOuterRadius2; + float fDet = max(0.0, B*B - 4.0 * C); + float fNear = 0.5 * (-B - sqrt(fDet)); + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPosition + v3Ray * fNear; + fFar -= fNear; + float fDepth = exp((fInnerRadius - fOuterRadius) / fScaleDepth); + float fCameraAngle = dot(-v3Ray, aVertexPosition) / length(aVertexPosition); + float fLightAngle = dot(v3LightPosition, aVertexPosition) / length(aVertexPosition); + + float fCameraScale = scale(fCameraAngle); + float fLightScale = scale(fLightAngle); + float fCameraOffset = fDepth*fCameraScale; + float fTemp = (fLightScale + fCameraScale); + + // Initialize the scattering loop variables + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + vec3 v3Attenuate; + for(int i=0; i atmosphere.innerRadius + (atmosphere.outerRadius - atmosphere.innerRadius) / 3) { + // Draw the planet from space + // TODO: maybe separate atmosphere from space and ground shaders? + + planetShader.use(gl) + camera.draw(gl, planetShader) + atmosphere.setupPlanetShader(gl, planetShader, camera, sun) + planet.prepare(gl, planetShader) + planet.draw(gl, planetShader) + } else { + // Draw the planet within the atmosphere + surfaceShader.use(gl) + surfaceEnvironment.draw(gl, surfaceShader) + camera.draw(gl, surfaceShader) + + planet.prepare(gl, surfaceShader) + planet.draw(gl, surfaceShader) + } + } } export { CubePlanet, CubeFace, PlanetGenerator } diff --git a/src/index.js b/src/index.js index bcd1796..3169dd1 100644 --- a/src/index.js +++ b/src/index.js @@ -30,6 +30,7 @@ async function pipeline () { const terrainShader = await game.shaders.createShaderFromFiles(game.gl, 'terrain', false) const skyboxShader = await game.shaders.createShaderFromFiles(game.gl, 'skybox', false) const atmosShader = await game.shaders.createShaderFromFiles(game.gl, 'atmosphere', false) + const planetShader = await game.shaders.createShaderFromFiles(game.gl, 'planet', false) entity.setRotation([0.0, 0.0, -90.0]) @@ -97,6 +98,7 @@ async function pipeline () { // Planet test const planet = new CubePlanet([0.0, 0.0, 0.0], new PlanetGenerator(16, 1000, hmap)) const atmosphere = new Atmosphere([0.0, 0.0, 0.0], 1000, 1025, [0.650, 0.570, 0.475]) + planet.material = material // Update function for camera and terrain let fpsTimer = 0 @@ -157,28 +159,21 @@ async function pipeline () { game.prepare() // Draw the skybox - //skyboxShader.use(gl) - //skybox.draw(gl, skyboxShader, cam) + // skyboxShader.use(gl) + // skybox.draw(gl, skyboxShader, cam) // Use terrain shader - terrainShader.use(gl) + // terrainShader.use(gl) // Set environment variables in shader - env.draw(gl, terrainShader) + // env.draw(gl, terrainShader) // Set the viewport uniforms - cam.draw(gl, terrainShader) + // cam.draw(gl, terrainShader) // Draw terrain // terrain.draw(gl, terrainShader) - // entity.draw(gl, terrainShader) - // block.draw(gl, terrainShader) - material.apply(gl, terrainShader) - planet.draw(gl, terrainShader) - - atmosShader.use(gl) - cam.draw(gl, atmosShader) - atmosphere.draw(gl, atmosShader, cam, env.sun, true) + CubePlanet.drawPlanetAtmosphere(gl, planet, atmosphere, cam, env.sun, atmosShader, planetShader, terrainShader, env) } // Render function for the triangle