我有一个通过互联网找到的大气散射着色器。实际上,这是WebGL(three.js)着色器。我尝试在移动设备上运行它。我发现当我使用Qualcomm
精度时,它在KIRIN
和hihgp
芯片组上效果很好,并且根本不在Mali
芯片组上工作(只是黑屏) 。 Athouth,它编译没有任何错误。我认为这是因为Mali
GPU(或类似的)对此着色器的精度不够highp
。如果我使用mediump精度,它不适用于所有设备(只是黑屏)。是否可以使用mediump
精度使这个(任何)着色器工作?或者如何使这个着色器适用于所有流行的芯片组?
顶点着色器:
attribute vec3 a_position;
attribute vec2 a_texCoord0;\n"+
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
varying vec3 vWorldPosition;
void main() {
vec4 worldPosition = u_worldTrans * vec4( a_position, 1.0 );
vWorldPosition = worldPosition.xyz;
gl_Position = u_projTrans * worldPosition;
}
片段着色器:
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 sunPosition;
varying vec3 vWorldPosition;
const float turbidity = 3.2;
const float reileigh = 2.7;
const float luminance = 1.0;
const float mieCoefficient = 0.007;
const float mieDirectionalG = .990;
#define e 2.718281828459
#define pi 3.141592653589
#define n 1.0003
#define pn 0.035
const vec3 lambda = vec3(0.00000068, 0.00000055, 0.00000045);
const vec3 K = vec3(0.686, 0.678, 0.666);
const vec3 up = vec3(0.0, 1.0, 0.0);
#define v 4.0
#define rayleighZenithLength 8400.0
#define mieZenithLength 1250.0
#define EE 1000.0
#define sunAngularDiameterCos 0.999956676946
#define cutoffAngle pi/1.95
#define steepness 1.5
vec3 simplifiedRayleigh()
{
return 0.0005 / vec3(94., 40., 18.);
}
float rayleighPhase(float cosTheta)
{
return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));
}
vec3 totalMie(vec3 lambda, vec3 K, float T)
{
float val = 10E-18;
float c = (0.2 * T ) * val;
return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;
}
float hgPhase(float cosTheta, float g)
{
return (1.0 / (4.0*pi)) * ((1.0 - pow(g, 2.0)) / pow(abs(1.0 - 2.0*g*cosTheta + pow(g, 2.0)), 1.5));
}
float sunIntensity(float zenithAngleCos)
{
return EE * max(0.0, 1.0 - exp(-((cutoffAngle - acos(zenithAngleCos))/steepness)));
}
#define A 0.15
#define B 0.50
#define C 0.10
#define D 0.20
#define E 0.02
#define F 0.30
#define W 1000.0
vec3 Uncharted2Tonemap(vec3 x)
{
return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}
void main()
{
vec3 cameraPos = vec3(0., 0., -500.);
float sunfade = 1.0-clamp(1.0-exp((sunPosition.y/4000.0)),0.0,1.0);
float reileighCoefficient = reileigh - (1.0* (1.0-sunfade));
vec3 sunDirection = normalize(sunPosition);
float sunE = sunIntensity(dot(sunDirection, up));
vec3 betaR = simplifiedRayleigh() * reileighCoefficient;
vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;
float zenithAngle = acos(max(0.0, dot(up, normalize(vWorldPosition - cameraPos))));
float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(abs(93.885 - ((zenithAngle * 180.0) / pi)), -1.253));
float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(abs(93.885 - ((zenithAngle * 180.0) / pi)), -1.253));
vec3 Fex = exp(-(betaR * sR + betaM * sM));
float cosTheta = dot(normalize(vWorldPosition - cameraPos), sunDirection);
float rPhase = rayleighPhase(cosTheta*0.5+0.5);
vec3 betaRTheta = betaR * rPhase;
float mPhase = hgPhase(cosTheta, mieDirectionalG);
vec3 betaMTheta = betaM * mPhase;
vec3 Lin = pow(abs(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex)),vec3(1.5));
Lin *= mix(vec3(1.0),pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up,sunDirection),5.0),0.0,1.0));
vec3 L0 = vec3(0.1) * Fex;
float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);
L0 += (sunE * 19000.0 * Fex)*sundisk;
vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));
vec3 texColor = (Lin+L0);
texColor *= 0.04 ;
texColor += vec3(0.0,0.001,0.0025)*0.3;
vec3 curr = Uncharted2Tonemap((log2(2.0/pow(luminance,4.0)))*texColor);
vec3 color = curr*whiteScale;
vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));
gl_FragColor.rgb = retColor;
gl_FragColor.a = 1.0;
}
我使用的是LibGDX,所以我的着色器类如下:
public class SkyShader implements Shader{
ShaderProgram program;
Camera specCamera;
int WIDTH, HEIGHT;
int u_projTrans;
int u_worldTrans;
int u_sunPosition;
int u_res;
int u_luminance;
int u_turbidity;
int u_reileigh;
int u_mieCoefficient;
int u_mieDirectionalG;
public Vector3 sunDirection = new Vector3();
Matrix4 viewInvTraMatrix = new Matrix4();
@Override
public void init() {
program = new ShaderProgram(vert, frag);
if (!program.isCompiled())throw new RuntimeException(program.getLog());
else Gdx.app.log("sky program", "shader compiled successfully!");
u_projTrans = program.getUniformLocation("u_projTrans");
u_worldTrans = program.getUniformLocation("u_worldTrans");
u_sunPosition = program.getUniformLocation("sunPosition");
u_res = program.getUniformLocation("u_res");
}
@Override
public void dispose() {
if(program!=null){
program.dispose();
program = null;
}
}
static final float delta = 0.0028526667f;
Matrix4 projectionMatrix = new Matrix4();
@Override
public void begin(Camera camera, RenderContext context) {
program.begin();
projectionMatrix.set(camera.projection);
if(Settings.landscape)
projectionMatrix.rotate(0, 1, 0, (Settings.EarthRotation-100) * .4f);
else projectionMatrix.rotate(0, 1, 0, (Settings.EarthRotation-100) * .7f);
program.setUniformMatrix(u_projTrans, projectionMatrix);
if(Settings.EnableSlightShadowGradient)
program.setUniformf(u_res, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
float rotation = Settings.EarthRotation * delta -.0375f;//- .00674f;
float azimuth = rotation; //_azimuth;
float inclination = .3f; //skyParams[i][4];
float theta = (float) (Math.PI * ( inclination - 0.5f ));
float phi = (float) (2f * Math.PI * ( azimuth - 0.5f ));
float distance = 4000;//400000;
sunDirection.x = (float) (distance * Math.cos( phi ));
sunDirection.y = (float) (distance * Math.sin( phi ) * Math.sin( theta ));
sunDirection.z = (float) (distance * Math.sin( phi ) * Math.cos( theta ));
context.setDepthTest(GL20.GL_LEQUAL);
context.setCullFace(GL20.GL_FRONT);
}
@Override
public boolean canRender(Renderable arg0) {
return true;
}
@Override
public int compareTo(Shader arg0) {
return 0;
}
@Override
public void end() {
program.end();
}
@Override
public void render(Renderable renderable) {
program.setUniformMatrix(u_worldTrans, renderable.worldTransform);
program.setUniformf(u_sunPosition, sunDirection);
renderable.mesh.render(program, renderable.primitiveType,
renderable.meshPartOffset, renderable.meshPartSize);
}
}
最后,我使用以下代码渲染它:
modelBatch.begin(cam);
modelBatch.render(sphere, skyShader);
modelBatch.end();
球体在哪里:
public ModelInstance createSphere() {
ModelBuilder modelBuilder = new ModelBuilder();
float radius = 4500;//450000;
Model tempSphere;
tempSphere = modelBuilder.createSphere(radius, radius, radius, 32, 8,
new Material(),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates
);
return new ModelInstance(tempSphere,0,0,0);
}
原始着色器为here
修改
如果我在浏览器中的problem
设备上运行原始着色器(链接在上面),它可以完美运行!
提前致谢。