Jump to content
  • Advertisement
Sign in to follow this  
yisky198781

Atmospheric Scattering

This topic is 1851 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys!

   recently I have been attempting to port the Sean O'Neil atmospheric scattering code to Java (Android) with OpenGL es 2.0. I have written the my glsl shader as same as the atmospheric scattering's.And pass the uniform variable as same as too.But I have a very weird result.I have google a lot of comments about this on web and tried to solve this as they say.but none of them have worked.

  I want to know whether the atmospheric scattering can work on android. If there anyone have the same problem with me. sorry for my english is not well, hope you know what i say.waitting for your help.

  thanks!

 

 atomsphere code

	private float mRadius;
	
	private int mProgram;
	private int mWVPMatrixHandle;
	//private int mInverseWMatrixHandle;
	private int mCameraPosHandle;
	private int mVLightPosHandle;
	private int mFLightPosHandle;
	private int mPositionHandle;
	//private int mNormalHandle;
	
	private int mVertexCount;
	private int mIndexCount;
	
	private FloatBuffer mVertexBuffer;
	private FloatBuffer mNormalBuffer;
	private ShortBuffer mIndexBuffer;
	
	//private float mColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	int m_nSamples;
	float m_Kr;
	float m_Km;
	float m_Kr4PI;
	float m_Km4PI;
	float m_ESun;
	float m_g;
	 
	float m_fInnerRadius;
	float m_fOuterRadius;
	float m_fScale;
	float m_fWavelength[] = { 0.650f, 0.570f, 0.475f };
	float m_fWavelength4[] = new float[3];
	float m_fRayleighScaleDepth;
	float m_fMieScaleDepth;
	
	public UGAtmosphere(float radius) {
		mRadius = radius;
		
		//
		m_nSamples = 3;
		m_Kr = 0.0025f;
		m_Kr4PI = (float) (m_Kr * 4.0f * Math.PI);
		m_Km = 0.0015f;
		m_Km4PI = (float) (m_Km * 4.0f * Math.PI);
		m_ESun = 15.0f;
		m_g = -0.95f;
		
		m_fOuterRadius = mRadius * 1.025f;
		m_fInnerRadius = mRadius;
		
		m_fWavelength4[0] = (float) Math.pow(m_fWavelength[0], 4.0f);
		m_fWavelength4[1] = (float) Math.pow(m_fWavelength[1], 4.0f);
		m_fWavelength4[2] = (float) Math.pow(m_fWavelength[2], 4.0f);
		
		m_fRayleighScaleDepth = 0.25f;
		m_fMieScaleDepth = 0.1f;
	}
	
	public void InitBuffer() {
		// 
		int meshPoint =  100; 
		float  minLat = -90.0f;
		float  maxLat =  90.0f;
		float  minLon = -180.0f;
		float  maxLon =  180.0f;
		
		int    upperBound = meshPoint - 1;
		float scaleFactor = 1.0f / (float)upperBound;
		float    latrange = maxLat - minLat;
		float    lonrange = maxLon - minLon;
		
		mVertexCount   = meshPoint * meshPoint * 3;
		float vertices[]  = new float[mVertexCount];
		for (int i = 0; i < meshPoint; i++) 
		{
			for ( int j = 0; j < meshPoint; j++) 
			{
				float lat = maxLat - scaleFactor * latrange * i;
				float lon = minLon + scaleFactor * lonrange * j;
				float position[] = UGUtility.SphericalToCartesian(m_fOuterRadius, lat, lon);
				
				vertices[i*meshPoint*3 + j*3]   = position[0];
				vertices[i*meshPoint*3 + j*3+1] = position[1];
				vertices[i*meshPoint*3 + j*3+2] = position[2];
			}
		}
		
		// 
		ByteBuffer vBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
		vBuffer.order(ByteOrder.nativeOrder());
		mVertexBuffer = vBuffer.asFloatBuffer();
		mVertexBuffer.put(vertices);
		mVertexBuffer.position(0);
		
		// 
		ByteBuffer nBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
		nBuffer.order(ByteOrder.nativeOrder());
		mNormalBuffer = nBuffer.asFloatBuffer();
		mNormalBuffer.put(vertices);
		mNormalBuffer.position(0); //  
		
		// 
		mIndexCount = 2 * upperBound * upperBound * 3; 
		short indices[] = new short[mIndexCount];
		for (int i = 0; i < upperBound; i++)
		{
			for (int j = 0; j < upperBound; j++)
			{
                indices[(2 * 3 * i * upperBound) + 6 * j] = (short)(i * meshPoint + j);
                indices[(2 * 3 * i * upperBound) + 6 * j + 1] = (short)((i + 1) * meshPoint + j);
                indices[(2 * 3 * i * upperBound) + 6 * j + 2] = (short)(i * meshPoint + j + 1);

                indices[(2 * 3 * i * upperBound) + 6 * j + 3] = (short)(i * meshPoint + j + 1);
                indices[(2 * 3 * i * upperBound) + 6 * j + 4] = (short)((i + 1) * meshPoint + j);
                indices[(2 * 3 * i * upperBound) + 6 * j + 5] = (short)((i + 1) * meshPoint + j + 1);
			}
		}
		
		// 
		ByteBuffer iBuffer = ByteBuffer.allocateDirect(indices.length * 2);
		iBuffer.order(ByteOrder.nativeOrder());
		mIndexBuffer = iBuffer.asShortBuffer();
		mIndexBuffer.put(indices);
		mIndexBuffer.position(0);
	}
	
	public void InitShader(String vShaderCode, String fShaderCode) {
		// 
		int vertexShader = UGUtility.loadShader(GLES20.GL_VERTEX_SHADER, 
				vShaderCode);
		int fragmentShader = UGUtility.loadShader(GLES20.GL_FRAGMENT_SHADER, 
				fShaderCode);
		
		mProgram = GLES20.glCreateProgram();
		GLES20.glAttachShader(mProgram, vertexShader);
		GLES20.glAttachShader(mProgram, fragmentShader);
		GLES20.glLinkProgram(mProgram);
		//String pLog = GLES20.glGetProgramInfoLog(mProgram);
		// 
		GLES20.glUseProgram(mProgram);
		
		// v3CameraPos
		mCameraPosHandle = GLES20.glGetUniformLocation(mProgram, "v3CameraPos");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		
		// v3LightPos
		mVLightPosHandle = GLES20.glGetUniformLocation(mProgram, "v3LightPos");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		
		// v3InvWavelength
		int invWavelength = GLES20.glGetUniformLocation(mProgram, "v3InvWavelength");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform3f(invWavelength, (1.0f / m_fWavelength4[0]), (1.0f / m_fWavelength4[1]), (1.0f / m_fWavelength4[2]));
		UGUtility.checkGlError("UGAtmoshpere", "glUniform3f");
		
		// v4Color
		//int v4Color = GLES20.glGetUniformLocation(mProgram, "v4Color");
		//UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		//GLES20.glUniform4f(v4Color, 1.0f, 1.0f, 1.0f, 1.0f);
		//UGUtility.checkGlError("UGAtmoshpere", "glUniform4f");
		
		// fOuterRadius
		int outerRadius = GLES20.glGetUniformLocation(mProgram, "fOuterRadius");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(outerRadius, m_fOuterRadius);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fOuterRadius2
		int outerRadius2 = GLES20.glGetUniformLocation(mProgram, "fOuterRadius2");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(outerRadius2, m_fOuterRadius*m_fOuterRadius);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fInnerRadius
		int innerRadius = GLES20.glGetUniformLocation(mProgram, "fInnerRadius");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(innerRadius, m_fInnerRadius);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fKrESun
		int krESun = GLES20.glGetUniformLocation(mProgram, "fKrESun");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(krESun, m_Kr * m_ESun);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fKmESun
		int kmESun = GLES20.glGetUniformLocation(mProgram, "fKmESun");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(kmESun, m_Km * m_ESun);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fKr4PI
		int kr4PI = GLES20.glGetUniformLocation(mProgram, "fKr4PI");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(kr4PI, m_Kr4PI);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fKm4PI
		int km4PI = GLES20.glGetUniformLocation(mProgram, "fKm4PI");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(km4PI, m_Km4PI);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fScale
		int scale = GLES20.glGetUniformLocation(mProgram, "fScale");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(scale, 1.0f / (m_fOuterRadius - m_fInnerRadius));
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fScaleDepth
		int scaleDepth = GLES20.glGetUniformLocation(mProgram, "fScaleDepth");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(scaleDepth, m_fRayleighScaleDepth);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// fScaleOverScaleDepth
		int scaleOverScaleDepth = GLES20.glGetUniformLocation(mProgram, "fScaleOverScaleDepth");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(scaleOverScaleDepth, (1.0f / (m_fOuterRadius - m_fInnerRadius)) / m_fRayleighScaleDepth);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// nSamples
		int samples = GLES20.glGetUniformLocation(mProgram, "nSamples");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1i(samples, m_nSamples);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1i");
		
		// fSamples
		int fSamples = GLES20.glGetUniformLocation(mProgram, "fSamples");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(fSamples, (float)m_nSamples);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// WorldViewProj
		mWVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "WorldViewProj");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		
		// InverseWorld
		//mInverseWMatrixHandle = GLES20.glGetUniformLocation(mProgram, "InverseWorld");
		//UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		
		// v4Position
		mPositionHandle = GLES20.glGetAttribLocation(mProgram, "v4Position");
		GLES20.glVertexAttribPointer(mPositionHandle, 3, 
				GLES20.GL_FLOAT, false, 
				12, mVertexBuffer);
		
		// f3LightPos
		mFLightPosHandle = GLES20.glGetUniformLocation(mProgram, "f3LightPos");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		
		// g
		int g = GLES20.glGetUniformLocation(mProgram, "g");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(g, m_g);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
		
		// g2
		int g2 = GLES20.glGetUniformLocation(mProgram, "g2");
		UGUtility.checkGlError("UGAtmoshpere", "glGetUniformLocation");
		GLES20.glUniform1f(g2, m_g*m_g);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform1f");
	}
	
	public void Draw(){
		//
		GLES20.glUseProgram(mProgram);
		
		//
		GLES20.glFrontFace(GLES20.GL_CW);
		//GLES20.glEnable(GLES20.GL_BLEND);
		GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
		GLES20.glDisable(GLES20.GL_CULL_FACE);
		GLES20.glDepthMask(false);
		
		//
		GLES20.glEnableVertexAttribArray(mPositionHandle);
		
		//
		GLES20.glDrawElements(GLES20.GL_TRIANGLES, mIndexCount, 
				GLES20.GL_UNSIGNED_SHORT, mIndexBuffer);
		
		//
		GLES20.glDisableVertexAttribArray(mPositionHandle);
		
		// 
		//GLES20.glDisable(GLES20.GL_BLEND);
		GLES20.glFrontFace(GLES20.GL_CCW);
		GLES20.glEnable(GLES20.GL_CULL_FACE);
		GLES20.glDepthMask(true);
	}
	
	public void UpdateWVPMatrix(float[] wvpMatrix) {
		//
		GLES20.glUseProgram(mProgram);
		GLES20.glUniformMatrix4fv(mWVPMatrixHandle,1,false,wvpMatrix,0);
		UGUtility.checkGlError("UGAtmoshpere", "glUniformMatrix4fv");
	}
	
	public void UpdateCameraPosition(float[] position) {
		//
		GLES20.glUseProgram(mProgram);
		GLES20.glUniform3fv(mCameraPosHandle, 1, position, 0);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform3fv");
	}
	
	public void UpdateLight(float[] lightPos) {
		// 
		GLES20.glUseProgram(mProgram);
		
		//
		float[] light = UGUtility.Normalise(lightPos[0], lightPos[1], lightPos[2]);
		GLES20.glUniform3fv(mVLightPosHandle, 1, light, 0);
		GLES20.glUniform3fv(mFLightPosHandle, 1, light, 0);
		UGUtility.checkGlError("UGAtmoshpere", "glUniform3fv");
	}
}

 

   skyfromspacever.glsl

uniform vec3 v3CameraPos;
uniform vec3 v3LightPos;		// The direction vector to the light source
uniform vec3 v3InvWavelength;	// 1 / pow(wavelength, 4) for the red, green, and blue channels
uniform float fOuterRadius;   // The outer (atmosphere) radius
uniform float fOuterRadius2;  // fOuterRadius * fOuterRadius
uniform float fInnerRadius;		// The inner (planetary) radius
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

uniform int nSamples;
uniform float fSamples;

uniform mat4 WorldViewProj;

attribute vec4 v4Position;        // The vertex's position

varying vec3 v3Direction;
varying vec4 v4FrontColor;
varying vec4 v4SecondaryColor;

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() {
  // 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 v3Pos            = v4Position.xyz; 
  vec3 v3WorldCameraPos = v3CameraPos;
  vec3 v3Ray            = v3Pos - v3WorldCameraPos;
  float fFar            = length(v3Ray);
  v3Ray                /= fFar;

  float fCameraHeight2=dot(v3WorldCameraPos,v3WorldCameraPos);  // fCameraHeight^2
  // 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(v3WorldCameraPos, 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 = v3WorldCameraPos + v3Ray * fNear;
  fFar -= fNear;
  float fStartAngle  = dot(v3Ray, v3Start) / fOuterRadius;
  float fStartDepth  = exp(-1.0 / fScaleDepth);
  float fStartOffset = fStartDepth*scale(fStartAngle);
  
  // 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);
  for(int i=0; i<nSamples; i++)
  {
	 float fHeight      = length(v3SamplePoint);
	 float fDepth       = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
	 float fLightAngle  = dot(v3LightPos, v3SamplePoint) / fHeight;
	 float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
	 float fScatter     = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle)));
	 vec3 v3Attenuate   = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
	 v3FrontColor      += v3Attenuate * (fDepth * fScaledLength);
	 v3SamplePoint     += v3SampleRay;
  }
  
  gl_Position      = WorldViewProj * v4Position;
  v3Direction      = v3WorldCameraPos - v3Pos;
  v4SecondaryColor.rgb = v3FrontColor * fKmESun;
  v4FrontColor.rgb     = v3FrontColor * (v3InvWavelength * fKrESun);
}

 

  skyfromspacefrag.glsl

precision mediump float;
uniform vec3 f3LightPos;
uniform float g;
uniform float g2;
					
varying vec3 v3Direction;
varying vec4 v4FrontColor;
varying vec4 v4SecondaryColor;

void main() {
 float fCos = dot(f3LightPos, v3Direction) / length(v3Direction);
 float fRayleighPhase = 0.75 * (1.0 + fCos*fCos);
 float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
 gl_FragColor.rgb = 1.0 - exp(-2.0 * (fRayleighPhase * v4SecondaryColor.rgb + fMiePhase * v4FrontColor.rgb));
 gl_FragColor.a = 1.0;
}

 

 

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!