I need to pass LUT from Android application to the fragment shader for color correction. I've found some examples where LUT is passed as Bitmap
GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, name);
...
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.raw.brick1);
GLUtils.texImage2D(GLES20.GL_TEXTURE_CUBE_MAP, 0, bitmap, 0);
But what to do if my LUT is not 3D image file and is not built with series of texture2D maps? My LUT is a float[] array. How I can bind it with uniform samplerCube in my fragment shader?
Short answer is "It's not possible do directly via OpenGL shader, but possible via renderscript"
More details about "shader" approach:
Fragment shader code is bellow. Pay attention the 1 line must be defined to use texture3D
#extension GL_OES_texture_3D : enable
precision mediump float;
uniform sampler2D u_texture0;
uniform vec4 uColor;
varying vec4 v_vertex;
uniform sampler3D u_lut;
void main() {
vec2 texcoord0 = v_vertex.xy;
vec4 rawColor=texture2D(u_texture0, texcoord0);
vec4 outColor = texture3D(u_lut, rawColor.rgb);
gl_FragColor = outColor; //rawColor;
}
java code:
FloatBuffer texBuffer = ByteBuffer.allocateDirect(array.length * Float.SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, iAxisSize, iAxisSize, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, texBuffer);
It works without compile or run time error but as result you'll see black screen. Sure you must use glTexImage3D function instead glTexImage2D, BUT it's not implemented in android SDK17 and you can't do anything with it.
The good news: in Android SDK17 implemented ScriptIntrinsicLUT that can be used to apply 1D LUT to source image. Java code is bellow:
private RenderScript mRS;
private Allocation mInAllocation;
private Allocation mOutAllocation;
private ScriptC_mono mScript;
private ScriptIntrinsicLUT mIntrinsic;
...
mRS = RenderScript.create(this);
mIntrinsic = ScriptIntrinsicLUT.create(mRS, Element.U8_4(mRS) );
createLUT();
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());
mIntrinsic.forEach(mInAllocation, mOutAllocation);
mOutAllocation.copyTo(mBitmapOut);
...
private void createLUT() {
for (int ct=0; ct < 256; ct++) {
float f = ((float)ct) / 255.f;
float r = f;
if (r < 0.5f) {
r = 4.0f * r * r * r;
} else {
r = 1.0f - r;
r = 1.0f - (4.0f * r * r * r);
}
mIntrinsic.setRed(ct, (int)(r * 255.f + 0.5f));
float g = f;
if (g < 0.5f) {
g = 2.0f * g * g;
} else {
g = 1.0f - g;
g = 1.0f - (2.0f * g * g);
}
mIntrinsic.setGreen(ct, (int)(g * 255.f + 0.5f));
float b = f * 0.5f + 0.25f;
mIntrinsic.setBlue(ct, (int)(b * 255.f + 0.5f));
}
}
More details about:
http://developer.android.com/reference/android/renderscript/ScriptIntrinsicLUT.html
http://my.fit.edu/~vkepuska/ece5570/adt-bundle-windows-x86_64/sdk/sources/android-17/com/android/rs/image/CrossProcess.java
Related
I want to implement backround blurring for selfie camera.
I have a blurring fragment shader
precision mediump float;
uniform sampler2D uSampler;
uniform float uBlur;
uniform float uRadius;
varying vec2 vTextureCoord;
void main() {
vec3 sum = vec3(0);
if (uBlur > 0.0) {
for (float i = -uBlur; i < uBlur; i++) {
for (float j = -uBlur; j < uBlur; j++) {
sum += texture2D(uSampler, vTextureCoord + vec2(i, j) * (uRadius / uBlur)).rgb / pow(uBlur * 2.0, 2.0);
}
}
} else {
sum = texture2D(uSampler, vTextureCoord).rgb;
}
gl_FragColor = vec4(sum, 1.0);
}
Also I have an array which indicates where I need to put blurring effect.
My idea is to pass the array somehow to the fragment shader and skip coordinates that should not be blurred.
Is there any way to do that or is there any other way I should follow?
UPD0:
Mask is generated dynamically several times per second. The mask data contained by com.google.mlkit.vision.segmentation.SegmentationMask class - It has ByteBuffer with width and heigh inside.
I tried to generate a bitmap with
Bitmap.createBitmap(maskColorsFromByteBuffer(mask), maskWidth, maskHeight, Config.ARGB_8888)
and
private int[] maskColorsFromByteBuffer(ByteBuffer byteBuffer) {
#ColorInt int[] colors = new int[maskWidth * maskHeight];
for (int i = 0; i < maskWidth * maskHeight; i++) {
float backgroundLikelihood = 1 - byteBuffer.getFloat();
if (backgroundLikelihood > 0.9) {
colors[i] = Color.argb(128, 51, 112, 69);
} else if (backgroundLikelihood > 0.2) {
// Linear interpolation to make sure when backgroundLikelihood is 0.2, the alpha is 0 and
// when backgroundLikelihood is 0.9, the alpha is 128.
// +0.5 to round the float value to the nearest int.
int alpha = (int) (182.9 * backgroundLikelihood - 36.6 + 0.5);
colors[i] = Color.argb(alpha, 51, 112, 69);
}
}
return colors;
}
After generating the bitmap I tried to draw it with ImageObjectFilterRender - as far as I see that class generating texture from the bitmap.
There are dozens of image filters written for the Android version of our app in GLSL (ES). As of iOS 12, OpenGL is deprecated, and CIFilter kernels have to be written in Metal.
I had some previous background in OpenGL, however writing CIFilter kernels in Metal is new to me.
Here is one of the filters. Could you help me in translating it to Metal as a CIFilter kernel? That would provide a good example for me so I could translate others.
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 vTextureCoord;
uniform samplerExternalOES sTexture;
uniform float texelWidth;
uniform float texelHeight;
uniform float intensivity;
void main() {
float SIZE = 1.25 + (intensivity / 100.0)*2.0;
vec4 color;
float min = 1.0;
float max = 0.0;
float val = 0.0;
for (float x = -SIZE; x < SIZE; x++) {
for (float y = -SIZE; y < SIZE; y++) {
color = texture2D(sTexture, vTextureCoord + vec2(x * texelWidth, y * texelHeight));
val = (color.r + color.g + color.b) / 3.;
if (val > max) { max = val; } else if (val < min) { min = val; }
}
}
float range = 5. * (max - min);
gl_FragColor = vec4(pow(1. - range, SIZE * 1.5));
gl_FragColor = vec4((gl_FragColor.r + gl_FragColor.g + gl_FragColor.b) / 3. > 0.75 ? vec3(1.) : gl_FragColor.rgb, 1.);
}
Here's the Metal source for a kernel that attempts to replicate your described filter:
#include <metal_stdlib>
#include <CoreImage/CoreImage.h>
using namespace metal;
extern "C" {
namespace coreimage {
float4 sketch(sampler src, float texelWidth, float texelHeight, float intensity40) {
float size = 1.25f + (intensity40 / 100.0f) * 2.0f;
float minVal = 1.0f;
float maxVal = 0.0f;
for (float x = -size; x < size; ++x) {
for (float y = -size; y < size; ++y) {
float4 color = src.sample(src.coord() + float2(x * texelWidth, y * texelHeight));
float val = (color.r + color.g + color.b) / 3.0f;
if (val > maxVal) {
maxVal = val;
} else if (val < minVal) {
minVal = val;
}
}
}
float range = 5.0f * (maxVal - minVal);
float4 outColor(pow(1.0f - range, size * 1.5f));
outColor = float4((outColor.r + outColor.g + outColor.b) / 3.0f > 0.75f ? float3(1.0f) : outColor.rgb, 1.0f);
return outColor;
}
}
}
I assume you're already familiar with the basics of how to correctly build Metal shaders into a library that can be loaded by Core Image.
You can instantiate your kernel at runtime by loading the default Metal library and requesting the "sketch" function (the name is arbitrary, so long as it matches the kernel source):
NSURL *libraryURL = [NSBundle.mainBundle URLForResource:#"default" withExtension:#"metallib"];
NSData *libraryData = [NSData dataWithContentsOfURL:libraryURL];
NSError *error;
CIKernel *kernel = [CIKernel kernelWithFunctionName:#"sketch" fromMetalLibraryData:libraryData error:&error];
You can then apply this kernel to an image by wrapping it in your own CIFilter subclass, or just invoke it directly:
CIImage *outputImage = [kernel applyWithExtent:CGRectMake(0, 0, width, height)
roiCallback:^CGRect(int index, CGRect destRect)
{ return destRect; }
arguments:#[inputImage, #(1.0f/width), #(1.0f/height), #(60.0f)]];
I've tried to select sensible defaults for each of the arguments (the first of which should be an instance of CIImage), but of course these can be adjusted to taste.
I have a shader of atmospheric scattering that I found through the Internet. In fact, this is the WebGL(three.js) shader. I try to run it on mobile devices. I found out that it works great on Qualcomm and KIRIN chipsets when I use hihgp precision and doesn't work on Mali chipsets at all (just black screen). Athouth, it compiles without any errors. I assume that this happens because Mali GPUs (or similar ones) have not enough highp precision for this shader. If I use mediump precision it doesn't work on all devices (just black screen). Is it possible to make this(any) shader works using mediump precision? Or how to make this shader works on all popular chipsets?
Vertex shader:
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;
}
Fragment shader:
#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;
}
I'm using LibGDX, so my shader class is bellow:
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);
}
}
And finally, I render it using the following code:
modelBatch.begin(cam);
modelBatch.render(sphere, skyShader);
modelBatch.end();
Where sphere is:
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);
}
Original shader is here
EDIT
If I run original shader(link is above) on problem devices in browser it works perfect!
Thanks in advance.
I am creating game in Libgdx and I'm using OpenGL water shader.
On desktop everything works fine (60 fps without V-Sync), but on Android I have only 1 FPS (tested on Samsung Galaxy S3 Neo and HTC One).
My fragment shader:
#ifdef GL_ES
precision mediump float;
#endif
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform float iGlobalTime; // shader playback time (in seconds)
const int NUM_STEPS = 8;
const float PI = 3.1415;
const float EPSILON = 1e-3;
float EPSILON_NRM = 0.1 / iResolution.x;
// sea
const int ITER_GEOMETRY = 3;
const int ITER_FRAGMENT = 5;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 4.0;
const float SEA_SPEED = 0.8;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.1,0.19,0.22);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
float SEA_TIME = iGlobalTime * SEA_SPEED;
mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
// math
mat3 fromEuler(vec3 ang) {
vec2 a1 = vec2(sin(ang.x),cos(ang.x));
vec2 a2 = vec2(sin(ang.y),cos(ang.y));
vec2 a3 = vec2(sin(ang.z),cos(ang.z));
mat3 m;
m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
return m;
}
float hash( vec2 p ) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
vec2 i = floor( p );
vec2 f = fract( p );
vec2 u = f*f*(3.0-2.0*f);
return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), hash( i + vec2(1.0,0.0) ), u.x), mix( hash( i + vec2(0.0,1.0) ), hash( i + vec2(1.0,1.0) ), u.x), u.y);
}
// lighting
float diffuse(vec3 n,vec3 l,float p) {
return pow(dot(n,l) * 0.4 + 0.6,p);
}
float specular(vec3 n,vec3 l,vec3 e,float s) {
float nrm = (s + 8.0) / (3.1415 * 8.0);
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
// sky
vec3 getSkyColor(vec3 e) {
e.y = max(e.y,0.0);
vec3 ret;
ret.x = pow(1.0-e.y,2.0);
ret.y = 1.0-e.y;
ret.z = 0.6+(1.0-e.y)*0.4;
return ret;
}
// sea
float sea_octave(vec2 uv, float choppy) {
uv += noise(uv);
vec2 wv = 1.0-abs(sin(uv));
vec2 swv = abs(cos(uv));
wv = mix(wv,swv,wv);
return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}
float map(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_GEOMETRY; i++) {
d = sea_octave((uv+SEA_TIME)*freq,choppy);
d += sea_octave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
float map_detailed(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_FRAGMENT; i++) {
d = sea_octave((uv+SEA_TIME)*freq,choppy);
d += sea_octave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
float fresnel = 1.0 - max(dot(n,-eye),0.0);
fresnel = pow(fresnel,3.0) * 0.65;
vec3 reflected = getSkyColor(reflect(eye,n));
vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
vec3 color = mix(refracted,reflected,fresnel);
float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
color += vec3(specular(n,l,eye,60.0));
return color;
}
// tracing
vec3 getNormal(vec3 p, float eps) {
vec3 n;
n.y = map_detailed(p);
n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
n.y = eps;
return normalize(n);
}
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
float tm = 0.0;
float tx = 10000.0;
float hx = map(ori + dir * tx);
if(hx > 0.0) return tx;
float hm = map(ori + dir * tm);
float tmid = 0.0;
for(int i = 0; i < NUM_STEPS; i++) {
tmid = mix(tm,tx, hm/(hm-hx));
p = ori + dir * tmid;
float hmid = map(p);
if(hmid < 0.0) {
tx = tmid;
hx = hmid;
} else {
tm = tmid;
hm = hmid;
}
}
return tmid;
}
// main
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
uv = uv * 2.0 - 1.65;
uv.x *= iResolution.x / iResolution.y;
float time = iGlobalTime * 0.3;
// ray
vec3 ang = vec3(0,0,0);
vec3 ori = vec3(0.0,20,0);
vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;
dir = normalize(dir) * fromEuler(ang);
// tracing
vec3 p;
heightMapTracing(ori,dir,p);
vec3 dist = p - ori;
vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
vec3 light = normalize(vec3(0.0,1.0,0.8));
// color
vec3 color = mix(
getSkyColor(dir),
getSeaColor(p,n,light,dir,dist),
pow(smoothstep(0.0,-0.05,dir.y),.3));
// post
fragColor = vec4(pow(color,vec3(0.75)), 1.0);
}
void main() {
vec4 color;
mainImage(color, gl_FragCoord.xy);
color.w = 1.0;
gl_FragColor = color;
}
My vertex shader:
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
My Libgdx code:
private Mesh mesh;
private ShaderProgram shader;
private float time = 0;
private OrthographicCamera camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
#Override
public void show() {
shader = new ShaderProgram(Gdx.files.internal("seaVertex.txt"), Gdx.files.internal("seaFragment.txt"));
shader.pedantic = false;
mesh = new Mesh(true, 4, 6, new VertexAttribute(Usage.Position, 2, "a_position"));
mesh.setVertices(new float[]{-Gdx.graphics.getWidth() / 2, -Gdx.graphics.getHeight() / 2,
Gdx.graphics.getWidth() / 2, -Gdx.graphics.getHeight() / 2,
-Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2,
Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2});
mesh.setIndices(new short[]{0, 2, 3, 0, 3, 1});
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
time += delta;
if (shader.isCompiled()){
shader.begin();
shader.setUniformMatrix("u_projTrans", camera.combined);
shader.setUniformf("iGlobalTime", time);
shader.setUniformf("iResolution", new Vector3(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0));
mesh.render(shader, GL20.GL_TRIANGLES);
shader.end();
}
}
Any ideas?
I am not familiar with Libgdx but I have a basic knowledge of OpenGL and graphics rendering in general(and I worked with this shader once) so here are my thoughts (I'm guessing you don't have a deep understand of the method this shader uses to generate water):
Your current "water shader" uses Raymarch wich is a very expensive way to make graphics and is usually used for demo scenes and some basic elements in most graphics scenes. Noise functions are very expensive and you are currently calling it a bunch of times for every ray, wich is also expensive because the raymarch procedure needs to call it a bunch of times to detect intersection with the water.
You are making very hard to create a game using this approach since combination of raymarched elements with tradicional OpenGL rendering system is not trivial, unless you are willing to work the hole game in procedural form, wich is also difficult.
I suggest you try other ways to render water that are not procedural, take a look at "thinMatrix" series on generating water in OpenGL, he uses Java but it should not be difficult to port it : https://www.youtube.com/watch?v=HusvGeEDU_U&list=PLRIWtICgwaX23jiqVByUs0bqhnalNTNZh
Good Luck!
i'm quite new to opengl , and I'm trying to display a square with opengl es 2.0 with an orthographics projection ( on android using c++ and ndk ) , but all I get is a blank screen.
If i don't use the projection matrix I can get the square but it's stretched depending on surface's aspect ratio.
I'm building the matrix with the following code ( referring to https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml ):
GLfloat projMat[16];
void ortho(float left, float right, float top, float bottom, float near, float far){
float tx = ((right+left)/(right-left))*-1;
float ty = ((top+bottom)/(top-bottom))*-1;
float tz = ((far+near)/(far-near))*-1;
projMat[0] = 2/right-left;
projMat[1] = 0.0f;
projMat[2] = 0.0f;
projMat[3] = 0.0f;
projMat[4] = 0.0f;
projMat[5] = 2/top-bottom;
projMat[6] = 0.0f;
projMat[7] = 0.0f;
projMat[8] = 0.0f;
projMat[9] = 0.0f;
projMat[10] = -2/far-near;
projMat[11] = 0.0f;
projMat[12] = tx;
projMat[13] = ty;
projMat[14] = tz;
projMat[15] = 1.0f; }
And i call this function with : ortho(0.0,width,0.0, height,-1.0,1.0); , where width and height are surface's width and height.
My vertex shader :
attribute vec4 vPosition;
uniform mat4 projMatrix;
void main() {
gl_Position = projMatrix * vPosition;
};
My fragment shader :
precision mediump float;
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
And my draw function :
// 3D drawing
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(mProgram);
glUniformMatrix4fv(mPerspectivehandler, 1, GL_FALSE, projMat);
glEnableVertexAttribArray(mvPositionHandle);
glVertexAttribPointer(mvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, quadverts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(mvPositionHandle);
Do you know where's the mistake?
Edit :
I added parentheses as suggested, but it still doesn't work
GLfloat projMat[16];
void ortho(float left, float right, float top, float bottom, float near, float far){
float tx = ((right+left)/(right-left))*-1;
float ty = ((top+bottom)/(top-bottom))*-1;
float tz = ((far+near)/(far-near))*-1;
projMat[0] = 2/(right-left);
projMat[1] = 0.0f;
projMat[2] = 0.0f;
projMat[3] = 0.0f;
projMat[4] = 0.0f;
projMat[5] = 2/(top-bottom);
projMat[6] = 0.0f;
projMat[7] = 0.0f;
projMat[8] = 0.0f;
projMat[9] = 0.0f;
projMat[10] = -2/(far-near);
projMat[11] = 0.0f;
projMat[12] = tx;
projMat[13] = ty;
projMat[14] = tz;
projMat[15] = 1.0f; }
You're missing parentheses in the matrix calculation for the diagonal elements. They should be:
projMat[0] = 2.0f / (right - left);
projMat[5] = 2.0f / (top - bottom);
projMat[10] = -2.0f / (far - near);
It can be hard to debug issues where nothing is rendered. You should simplify until you can isolate what is going wrong.
You've declared vPosition as a vec4, but in your comment, your vertex position array only has 12 floats (3 per vertex). a vec4 needs 4 floats per vertex. this is also a problem here:
glVertexAttribPointer(mvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, quadverts);
You use 3 as the second parameter in the line above, but vec4 in your shader means use 4 here. Be sure that quadVerts holds 4 floats per vertex!
To debug, don't use a projection matrix - just render your geometry directly to clip-coordinates in your shader like so:
attribute vec4 vPosition;
uniform mat4 projMatrix;
void main() {
gl_Position = vPosition;
};
If the above shader renders (after you fix your vec4 problem), then you can start to debug your projection matrix.
Does your glClear() call actually take effect? try changing the color with glClearColor() and make sure the background color changes accordingly. If it doesn't, you might have set up your GL window incorrectly.
This question is 4 months old and I don't know if you still need an aswer.
I also had a lot of problems with orto projection matrices in OpenGL, but this works (for me):
result[0] = 2.0 / (right - left);
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
result[4] = 0.0;
result[5] = 2.0 / (top - bottom);
result[6] = 0.0;
result[7] = 0.0;
result[8] = 0.0;
result[9] = 0.0;
result[10] = (1.0f / (near - far));
result[11] = 0.0;
result[12] = ((left + right) / (left - right));
result[13] = ((top + bottom) / (bottom - top));
result[14] = (near / (near - far));
result[15] = 1;