youqiwong's picture
Upload folder using huggingface_hub
0c51b93 verified
// This code contains NVIDIA Confidential Information and is disclosed to you
// under a form of NVIDIA software license agreement provided separately to you.
//
// Notice
// NVIDIA Corporation and its licensors retain all intellectual property and
// proprietary rights in and to this software and related documentation and
// any modifications thereto. Any use, reproduction, disclosure, or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA Corporation is strictly prohibited.
//
// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Information and code furnished is believed to be accurate and reliable.
// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
// information or for any infringement of patents or other rights of third parties that may
// result from its use. No license is granted by implication or otherwise under any patent
// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
// This code supersedes and replaces all information previously supplied.
// NVIDIA Corporation products are not authorized for use as critical
// components in life support devices or systems without express written approval of
// NVIDIA Corporation.
//
// Copyright (c) 20132017 NVIDIA Corporation. All rights reserved.
#include "../shaders.h"
#include "../../core/mesh.h"
#include "../../core/tga.h"
#include "../../core/platform.h"
#include "../../core/extrude.h"
#include "../../external/SDL2-2.0.4/include/SDL.h"
#include "../../external/glad/src/glad.c"
// #ifdef __linux__
#include "../../external/glad/src/glad_egl.c"
#include "../../external/glad/include/glad/glad_egl.h"
// #endif
#include "imguiRenderGL.h"
#include "utilsGL.h"
#include "shader.h"
#ifdef ANDROID
#include "android/Log.h"
#include "android/AndroidDefine.h"
#include "android/AndroidMatrixTool.h"
#endif
#define CudaCheck(x) { cudaError_t err = x; if (err != cudaSuccess) { printf("Cuda error: %d in %s at %s:%d\n", err, #x, __FILE__, __LINE__); assert(0); } }
typedef unsigned int VertexBuffer;
typedef unsigned int IndexBuffer;
typedef unsigned int Texture;
struct FluidRenderBuffersGL
{
FluidRenderBuffersGL(int numParticles = 0):
mPositionVBO(0),
mDensityVBO(0),
mIndices(0),
mPositionBuf(nullptr),
mDensitiesBuf(nullptr),
mIndicesBuf(nullptr)
{
mNumParticles = numParticles;
for (int i = 0; i < 3; i++)
{
mAnisotropyVBO[i] = 0;
mAnisotropyBuf[i] = nullptr;
}
}
~FluidRenderBuffersGL()
{
glDeleteBuffers(1, &mPositionVBO);
glDeleteBuffers(3, mAnisotropyVBO);
glDeleteBuffers(1, &mDensityVBO);
glDeleteBuffers(1, &mIndices);
NvFlexUnregisterOGLBuffer(mPositionBuf);
NvFlexUnregisterOGLBuffer(mDensitiesBuf);
NvFlexUnregisterOGLBuffer(mIndicesBuf);
NvFlexUnregisterOGLBuffer(mAnisotropyBuf[0]);
NvFlexUnregisterOGLBuffer(mAnisotropyBuf[1]);
NvFlexUnregisterOGLBuffer(mAnisotropyBuf[2]);
}
int mNumParticles;
VertexBuffer mPositionVBO;
VertexBuffer mDensityVBO;
VertexBuffer mAnisotropyVBO[3];
IndexBuffer mIndices;
// wrapper buffers that allow Flex to write directly to VBOs
NvFlexBuffer* mPositionBuf;
NvFlexBuffer* mDensitiesBuf;
NvFlexBuffer* mAnisotropyBuf[3];
NvFlexBuffer* mIndicesBuf;
};
// vertex buffers for diffuse particles
struct DiffuseRenderBuffersGL
{
DiffuseRenderBuffersGL(int numParticles = 0):
mDiffusePositionVBO(0),
mDiffuseVelocityVBO(0),
mDiffuseIndicesIBO(0),
mDiffuseIndicesBuf(nullptr),
mDiffusePositionsBuf(nullptr),
mDiffuseVelocitiesBuf(nullptr)
{
mNumParticles = numParticles;
}
~DiffuseRenderBuffersGL()
{
if (mNumParticles > 0)
{
glDeleteBuffers(1, &mDiffusePositionVBO);
glDeleteBuffers(1, &mDiffuseVelocityVBO);
glDeleteBuffers(1, &mDiffuseIndicesIBO);
NvFlexUnregisterOGLBuffer(mDiffuseIndicesBuf);
NvFlexUnregisterOGLBuffer(mDiffusePositionsBuf);
NvFlexUnregisterOGLBuffer(mDiffuseVelocitiesBuf);
}
}
int mNumParticles;
VertexBuffer mDiffusePositionVBO;
VertexBuffer mDiffuseVelocityVBO;
IndexBuffer mDiffuseIndicesIBO;
NvFlexBuffer* mDiffuseIndicesBuf;
NvFlexBuffer* mDiffusePositionsBuf;
NvFlexBuffer* mDiffuseVelocitiesBuf;
};
struct FluidRenderer
{
GLuint mDepthFbo;
GLuint mDepthTex;
GLuint mDepthSmoothTex;
GLuint mSceneFbo;
GLuint mSceneTex;
GLuint mReflectTex;
GLuint mThicknessFbo;
GLuint mThicknessTex;
GLuint mPointThicknessProgram;
//GLuint mPointDepthProgram;
GLuint mEllipsoidThicknessProgram;
GLuint mEllipsoidDepthProgram;
GLuint mCompositeProgram;
GLuint mDepthBlurProgram;
int mSceneWidth;
int mSceneHeight;
};
struct ShadowMap
{
GLuint texture;
GLuint framebuffer;
};
struct GpuMesh
{
GLuint mPositionsVBO;
GLuint mNormalsVBO;
GLuint mIndicesIBO;
int mNumVertices;
int mNumFaces;
};
// texture pool
#include "../../core/png.h"
GLuint LoadTexture(const char* filename)
{
PngImage img;
if (PngLoad(filename, img))
{
GLuint tex;
glVerify(glGenTextures(1, &tex));
glVerify(glActiveTexture(GL_TEXTURE0));
glVerify(glBindTexture(GL_TEXTURE_2D, tex));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE));
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.m_width, img.m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.m_data));
PngFree(img);
return tex;
}
else
{
return NULL;
}
}
struct RenderTexture
{
GLuint colorTex;
GLuint colorFrameBuffer;
GLuint depthTex;
GLuint depthFrameBuffer;
RenderTexture()
{
memset(this, 0, sizeof(*this));
}
};
namespace
{
int g_msaaSamples;
GLuint g_msaaFbo;
GLuint g_msaaColorBuf;
GLuint g_msaaDepthBuf;
int g_screenWidth;
int g_screenHeight;
SDL_Window* g_window;
static float g_spotMin = 0.5f;
static float g_spotMax = 1.0f;
float g_shadowBias = 0.05f;
#ifdef __linux__
EGLDisplay* g_eglDisplay;
EGLConfig* g_eglConfig;
EGLContext* g_eglContext;
EGLSurface* g_eglSurface;
#endif
} // anonymous namespace
extern NvFlexLibrary* g_flexLib;
extern Colour g_colors[];
extern Mesh* g_mesh;
void DrawShapes();
namespace OGL_Renderer
{
char font_path[100];
char* make_path(char* full_path, std::string path) {
strcpy(full_path, getenv("PYFLEXROOT"));
strcat(full_path, path.c_str());
return full_path;
}
void InitRender(const RenderInitOptions& options)
{
SDL_Window* window = options.window;
int msaaSamples = options.numMsaaSamples;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
// Turn on double buffering with a 24bit Z buffer.
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_CreateContext(window);
// This makes our buffer swap syncronized with the monitor's vertical refresh
SDL_GL_SetSwapInterval(1);
if (!gladLoadGLLoader(SDL_GL_GetProcAddress))
{
printf("Could not initialize GL extensions\n");
}
imguiRenderGLInit(GetFilePathByPlatform(make_path(font_path, "/data/DroidSans.ttf")).c_str());
g_msaaSamples = msaaSamples;
g_window = window;
}
void DestroyRender()
{
}
void StartFrame(Vec4 clearColor)
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glPointSize(5.0f);
glVerify(glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, g_msaaFbo));
glVerify(glClearColor(powf(clearColor.x, 1.0f / 2.2f), powf(clearColor.y, 1.0f / 2.2f), powf(clearColor.z, 1.0f / 2.2f), 0.0f));
glVerify(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
}
void EndFrame()
{
if (g_msaaFbo)
{
// blit the msaa buffer to the window
glVerify(glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, g_msaaFbo));
glVerify(glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0));
glVerify(glBlitFramebuffer(0, 0, g_screenWidth, g_screenHeight, 0, 0, g_screenWidth, g_screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR));
}
// render help to back buffer
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, 0));
// glVerify(glClear(GL_DEPTH_BUFFER_BIT));
}
void SetView(Matrix44 view, Matrix44 proj)
{
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(view);
}
void SetFillMode(bool wireframe)
{
glPolygonMode(GL_FRONT_AND_BACK, wireframe?GL_LINE:GL_FILL);
}
void SetCullMode(bool enabled)
{
if (enabled)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
}
void imguiGraphDraw()
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE3);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE4);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_CUBE_MAP);
glActiveTexture(GL_TEXTURE5);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_POINT_SPRITE);
// save scene camera transform
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
const Matrix44 ortho = OrthographicMatrix(0.0f, float(g_screenWidth), 0.0f, float(g_screenHeight), -1.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixf(ortho);
glUseProgram(0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
imguiRenderGLDraw();
// restore camera transform (for picking)
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void ReshapeRender(int width, int height, bool minimized)
{
if (g_msaaSamples)
{
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, 0));
if (g_msaaFbo)
{
glVerify(glDeleteFramebuffers(1, &g_msaaFbo));
glVerify(glDeleteRenderbuffers(1, &g_msaaColorBuf));
glVerify(glDeleteRenderbuffers(1, &g_msaaDepthBuf));
}
int samples;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
// clamp samples to 4 to avoid problems with point sprite scaling
samples = Min(samples, Min(g_msaaSamples, 4));
glVerify(glGenFramebuffers(1, &g_msaaFbo));
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo));
glVerify(glGenRenderbuffers(1, &g_msaaColorBuf));
glVerify(glBindRenderbuffer(GL_RENDERBUFFER, g_msaaColorBuf));
glVerify(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, width, height));
glVerify(glGenRenderbuffers(1, &g_msaaDepthBuf));
glVerify(glBindRenderbuffer(GL_RENDERBUFFER, g_msaaDepthBuf));
glVerify(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height));
glVerify(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, g_msaaDepthBuf));
glVerify(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, g_msaaColorBuf));
glVerify(glCheckFramebufferStatus(GL_FRAMEBUFFER));
glEnable(GL_MULTISAMPLE);
}
g_screenWidth = width;
g_screenHeight = height;
}
void GetViewRay(int x, int y, Vec3& origin, Vec3& dir)
{
float modelview[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
float projection[16];
glGetFloatv(GL_PROJECTION_MATRIX, projection);
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
float nearPos[3];
UnProjectf(float(x), float(y), 0.0f, modelview, projection, viewport, nearPos);
float farPos[3];
UnProjectf(float(x), float(y), 1.0f, modelview, projection, viewport, farPos);
origin = Vec3(float(nearPos[0]), float(nearPos[1]), float(nearPos[2]));
dir = Normalize(Vec3(float(farPos[0]-nearPos[0]), float(farPos[1]-nearPos[1]), float(farPos[2]-nearPos[2])));
}
Vec3 GetScreenCoord(Vec3& pos) {
float modelview[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
float projection[16];
glGetFloatv(GL_PROJECTION_MATRIX, projection);
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
float screen[3];
Projectf(pos.x, pos.y, pos.z, modelview, projection, viewport, screen);
return Vec3((float)screen[0], (float)screen[1], (float)screen[2]);
}
void ReadFrame(int* backbuffer, int width, int height)
{
glVerify(glReadBuffer(GL_BACK));
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, backbuffer);
}
void PresentFrame(bool fullsync)
{
#ifndef ANDROID
SDL_GL_SetSwapInterval(fullsync);
glFinish();
SDL_GL_SwapWindow(g_window);
#endif
}
RenderTexture* CreateRenderTexture(const char* filename)
{
GLuint tex = LoadTexture(filename);
if (tex)
{
RenderTexture* t = new RenderTexture();
t->colorTex = tex;
return t;
}
else
{
return NULL;
}
}
RenderTexture* CreateRenderTarget(int width, int height, bool depth)
{
return NULL;
}
void DestroyRenderTexture(RenderTexture* t)
{
if (t)
{
if (t->colorTex)
glDeleteTextures(1, &t->colorTex);
if (t->colorFrameBuffer)
glDeleteFramebuffers(1, &t->colorFrameBuffer);
if (t->depthTex)
glDeleteTextures(1, &t->depthTex);
if (t->depthFrameBuffer)
glDeleteFramebuffers(1, &t->depthFrameBuffer);
delete t;
}
}
// fixes some banding artifacts with repeated blending during thickness and diffuse rendering
#define USE_HDR_DIFFUSE_BLEND 0
// vertex shader
const char *vertexPointShader = "#version 130\n" STRINGIFY(
uniform float pointRadius; // point size in world space
uniform float pointScale; // scale to calculate size in pixels
uniform mat4 lightTransform;
uniform vec3 lightDir;
uniform vec3 lightDirView;
uniform vec4 colors[8];
uniform vec4 transmission;
uniform int mode;
//in int density;
in float density;
in int phase;
in vec4 velocity;
void main()
{
// calculate window-space point size
vec4 viewPos = gl_ModelViewMatrix*vec4(gl_Vertex.xyz, 1.0);
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
gl_PointSize = -pointScale * (pointRadius / viewPos.z);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = lightTransform*vec4(gl_Vertex.xyz-lightDir*pointRadius*2.0, 1.0);
gl_TexCoord[2] = gl_ModelViewMatrix*vec4(lightDir, 0.0);
if (mode == 1)
{
// density visualization
if (density < 0.0f)
gl_TexCoord[3].xyz = mix(vec3(0.1, 0.1, 1.0), vec3(0.1, 1.0, 1.0), -density);
else
gl_TexCoord[3].xyz = mix(vec3(1.0, 1.0, 1.0), vec3(0.1, 0.2, 1.0), density);
}
else if (mode == 2)
{
gl_PointSize *= clamp(gl_Vertex.w*0.25, 0.0f, 1.0);
gl_TexCoord[3].xyzw = vec4(clamp(gl_Vertex.w*0.05, 0.0f, 1.0));
}
else
{
gl_TexCoord[3].xyz = mix(colors[phase % 8].xyz*2.0, vec3(1.0), 0.1);
}
gl_TexCoord[4].xyz = gl_Vertex.xyz;
gl_TexCoord[5].xyz = viewPos.xyz;
}
);
// pixel shader for rendering points as shaded spheres
const char *fragmentPointShader = STRINGIFY(
uniform vec3 lightDir;
uniform vec3 lightPos;
uniform float spotMin;
uniform float spotMax;
uniform int mode;
uniform sampler2DShadow shadowTex;
uniform vec2 shadowTaps[12];
uniform float pointRadius; // point size in world space
// sample shadow map
float shadowSample()
{
vec3 pos = vec3(gl_TexCoord[1].xyz/gl_TexCoord[1].w);
vec3 uvw = (pos.xyz*0.5)+vec3(0.5);
// user clip
if (uvw.x < 0.0 || uvw.x > 1.0)
return 1.0;
if (uvw.y < 0.0 || uvw.y > 1.0)
return 1.0;
float s = 0.0;
float radius = 0.002;
for (int i=0; i < 8; i++)
{
s += shadow2D(shadowTex, vec3(uvw.xy + shadowTaps[i]*radius, uvw.z)).r;
}
s /= 8.0;
return s;
}
float sqr(float x) { return x*x; }
void main()
{
// calculate normal from texture coordinates
vec3 normal;
normal.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0);
float mag = dot(normal.xy, normal.xy);
if (mag > 1.0) discard; // kill pixels outside circle
normal.z = sqrt(1.0-mag);
if (mode == 2)
{
float alpha = normal.z*gl_TexCoord[3].w;
gl_FragColor.xyz = gl_TexCoord[3].xyz*alpha;
gl_FragColor.w = alpha;
return;
}
// calculate lighting
float shadow = shadowSample();
vec3 lVec = normalize(gl_TexCoord[4].xyz-(lightPos));
vec3 lPos = vec3(gl_TexCoord[1].xyz/gl_TexCoord[1].w);
float attenuation = max(smoothstep(spotMax, spotMin, dot(lPos.xy, lPos.xy)), 0.05);
vec3 diffuse = vec3(0.9, 0.9, 0.9);
vec3 reflectance = gl_TexCoord[3].xyz;
vec3 Lo = diffuse*reflectance*max(0.0, sqr(-dot(gl_TexCoord[2].xyz, normal)*0.5 + 0.5))*max(0.2,shadow)*attenuation;
gl_FragColor = vec4(pow(Lo, vec3(1.0/2.2)), 1.0);
vec3 eyePos = gl_TexCoord[5].xyz + normal*pointRadius;//*2.0;
vec4 ndcPos = gl_ProjectionMatrix * vec4(eyePos, 1.0);
ndcPos.z /= ndcPos.w;
gl_FragDepth = ndcPos.z*0.5 + 0.5;
}
);
// vertex shader
const char *vertexShader = "#version 130\n" STRINGIFY(
uniform mat4 lightTransform;
uniform vec3 lightDir;
uniform float bias;
uniform vec4 clipPlane;
uniform float expand;
uniform mat4 objectTransform;
void main()
{
vec3 n = normalize((objectTransform*vec4(gl_Normal, 0.0)).xyz);
vec3 p = (objectTransform*vec4(gl_Vertex.xyz, 1.0)).xyz;
// calculate window-space point size
gl_Position = gl_ModelViewProjectionMatrix * vec4(p + expand*n, 1.0);
gl_TexCoord[0].xyz = n;
gl_TexCoord[1] = lightTransform*vec4(p + n*bias, 1.0);
gl_TexCoord[2] = gl_ModelViewMatrix*vec4(lightDir, 0.0);
gl_TexCoord[3].xyz = p;
gl_TexCoord[4] = gl_Color;
gl_TexCoord[5] = gl_MultiTexCoord0;
gl_TexCoord[6] = gl_SecondaryColor;
gl_TexCoord[7] = gl_ModelViewMatrix*vec4(gl_Vertex.xyz, 1.0);
gl_ClipDistance[0] = dot(clipPlane,vec4(gl_Vertex.xyz, 1.0));
}
);
const char *passThroughShader = STRINGIFY(
void main()
{
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
);
// pixel shader for rendering points as shaded spheres
const char *fragmentShader = STRINGIFY(
uniform vec3 lightDir;
uniform vec3 lightPos;
uniform float spotMin;
uniform float spotMax;
uniform vec3 color;
uniform vec4 fogColor;
uniform sampler2DShadow shadowTex;
uniform vec2 shadowTaps[12];
uniform sampler2D tex;
uniform bool sky;
uniform bool grid;
uniform bool texture;
float sqr(float x) { return x*x; }
// sample shadow map
float shadowSample()
{
vec3 pos = vec3(gl_TexCoord[1].xyz/gl_TexCoord[1].w);
vec3 uvw = (pos.xyz*0.5)+vec3(0.5);
// user clip
if (uvw.x < 0.0 || uvw.x > 1.0)
return 1.0;
if (uvw.y < 0.0 || uvw.y > 1.0)
return 1.0;
float s = 0.0;
float radius = 0.002;
const int numTaps = 12;
for (int i=0; i < numTaps; i++)
{
s += shadow2D(shadowTex, vec3(uvw.xy + shadowTaps[i]*radius, uvw.z)).r;
}
s /= numTaps;
return s;
}
float filterwidth(vec2 v)
{
vec2 fw = max(abs(dFdx(v)), abs(dFdy(v)));
return max(fw.x, fw.y);
}
vec2 bump(vec2 x)
{
return (floor((x)/2) + 2.f * max(((x)/2) - floor((x)/2) - .5f, 0.f));
}
float checker(vec2 uv)
{
float width = filterwidth(uv);
vec2 p0 = uv - 0.5 * width;
vec2 p1 = uv + 0.5 * width;
vec2 i = (bump(p1) - bump(p0)) / width;
return i.x * i.y + (1 - i.x) * (1 - i.y);
}
void main()
{
// calculate lighting
float shadow = max(shadowSample(), 0.5);
vec3 lVec = normalize(gl_TexCoord[3].xyz-(lightPos));
vec3 lPos = vec3(gl_TexCoord[1].xyz/gl_TexCoord[1].w);
float attenuation = max(smoothstep(spotMax, spotMin, dot(lPos.xy, lPos.xy)), 0.05);
vec3 n = gl_TexCoord[0].xyz;
vec3 color = gl_TexCoord[4].xyz;
if (!gl_FrontFacing)
{
color = gl_TexCoord[6].xyz;
n *= -1.0f;
}
if (grid && (n.y >0.995))
{
color *= 1.0 - 0.25 * checker(vec2(gl_TexCoord[3].x, gl_TexCoord[3].z));
}
else if (grid && abs(n.z) > 0.995)
{
color *= 1.0 - 0.25 * checker(vec2(gl_TexCoord[3].y, gl_TexCoord[3].x));
}
if (texture)
{
color = texture2D(tex, gl_TexCoord[5].xy).xyz;
}
// direct light term
float wrap = 0.0;
vec3 diffuse = color*vec3(1.0, 1.0, 1.0)*max(0.0, (-dot(lightDir, n)+wrap)/(1.0+wrap)*shadow)*attenuation;
// wrap ambient term aligned with light dir
vec3 light = vec3(0.03, 0.025, 0.025)*1.5;
vec3 dark = vec3(0.025, 0.025, 0.03);
vec3 ambient = 4.0*color*mix(dark, light, -dot(lightDir, n)*0.5 + 0.5)*attenuation;
vec3 fog = mix(vec3(fogColor), diffuse + ambient, exp(gl_TexCoord[7].z*fogColor.w));
gl_FragColor = vec4(pow(fog, vec3(1.0/2.2)), 1.0);
}
);
void ShadowApply(GLint sprogram, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, GLuint shadowTex)
{
GLint uLightTransform = glGetUniformLocation(sprogram, "lightTransform");
glUniformMatrix4fv(uLightTransform, 1, false, lightTransform);
GLint uLightPos = glGetUniformLocation(sprogram, "lightPos");
glUniform3fv(uLightPos, 1, lightPos);
GLint uLightDir = glGetUniformLocation(sprogram, "lightDir");
glUniform3fv(uLightDir, 1, Normalize(lightTarget-lightPos));
GLint uBias = glGetUniformLocation(sprogram, "bias");
glUniform1f(uBias, g_shadowBias);
const Vec2 taps[] =
{
Vec2(-0.326212f,-0.40581f),Vec2(-0.840144f,-0.07358f),
Vec2(-0.695914f,0.457137f),Vec2(-0.203345f,0.620716f),
Vec2(0.96234f,-0.194983f),Vec2(0.473434f,-0.480026f),
Vec2(0.519456f,0.767022f),Vec2(0.185461f,-0.893124f),
Vec2(0.507431f,0.064425f),Vec2(0.89642f,0.412458f),
Vec2(-0.32194f,-0.932615f),Vec2(-0.791559f,-0.59771f)
};
GLint uShadowTaps = glGetUniformLocation(sprogram, "shadowTaps");
glUniform2fv(uShadowTaps, 12, &taps[0].x);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, shadowTex);
}
void DrawPoints(FluidRenderBuffers* buffersIn, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ShadowMap* shadowMap, bool showDensity)
{
FluidRenderBuffersGL* buffers = reinterpret_cast<FluidRenderBuffersGL*>(buffersIn);
GLuint positions = buffers->mPositionVBO;
GLuint colors = buffers->mDensityVBO;
GLuint indices = buffers->mIndices;
static int sprogram = -1;
if (sprogram == -1)
{
sprogram = CompileProgram(vertexPointShader, fragmentPointShader);
}
if (sprogram)
{
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
//glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
int mode = 0;
if (showDensity)
mode = 1;
if (shadowMap == NULL)
mode = 2;
glVerify(glUseProgram(sprogram));
glVerify(glUniform1f( glGetUniformLocation(sprogram, "pointRadius"), radius));
glVerify(glUniform1f( glGetUniformLocation(sprogram, "pointScale"), screenWidth/screenAspect * (1.0f / (tanf(fov*0.5f)))));
glVerify(glUniform1f( glGetUniformLocation(sprogram, "spotMin"), g_spotMin));
glVerify(glUniform1f( glGetUniformLocation(sprogram, "spotMax"), g_spotMax));
glVerify(glUniform1i( glGetUniformLocation(sprogram, "mode"), mode));
glVerify(glUniform4fv( glGetUniformLocation(sprogram, "colors"), 8, (float*)&g_colors[0].r));
// set shadow parameters
ShadowApply(sprogram, lightPos, lightTarget, lightTransform, shadowMap->texture);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, positions);
glVertexPointer(4, GL_FLOAT, 0, 0);
int d = glGetAttribLocation(sprogram, "density");
int p = glGetAttribLocation(sprogram, "phase");
if (d != -1)
{
glVerify(glEnableVertexAttribArray(d));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, colors));
glVerify(glVertexAttribPointer(d, 1, GL_FLOAT, GL_FALSE, 0, 0)); // densities
}
if (p != -1)
{
glVerify(glEnableVertexAttribArray(p));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, colors));
glVerify(glVertexAttribIPointer(p, 1, GL_INT, 0, 0)); // phases
}
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices));
glVerify(glDrawElements(GL_POINTS, n, GL_UNSIGNED_INT, (const void*)(offset*sizeof(int))));
glVerify(glUseProgram(0));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
glVerify(glDisableClientState(GL_VERTEX_ARRAY));
if (d != -1)
glVerify(glDisableVertexAttribArray(d));
if (p != -1)
glVerify(glDisableVertexAttribArray(p));
glDisable(GL_POINT_SPRITE);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
}
}
void DrawPlane(const Vec4& p);
static GLuint s_diffuseProgram = GLuint(-1);
static GLuint s_shadowProgram = GLuint(-1);
#ifdef ANDROID
void ResetProgramId()
{
s_diffuseProgram = GLuint(-1);
s_shadowProgram = GLuint(-1);
}
#endif
static const int kShadowResolution = 2048;
ShadowMap* ShadowCreate()
{
GLuint texture;
GLuint framebuffer;
glVerify(glGenFramebuffers(1, &framebuffer));
glVerify(glGenTextures(1, &texture));
glVerify(glBindTexture(GL_TEXTURE_2D, texture));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
// This is to allow usage of shadow2DProj function in the shader
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY));
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, kShadowResolution, kShadowResolution, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL));
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture, 0));
ShadowMap* map = new ShadowMap();
map->texture = texture;
map->framebuffer = framebuffer;
return map;
}
void ShadowDestroy(ShadowMap* map)
{
glVerify(glDeleteTextures(1, &map->texture));
glVerify(glDeleteFramebuffers(1, &map->framebuffer));
delete map;
}
void ShadowBegin(ShadowMap* map)
{
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(8.f, 8.f);
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, map->framebuffer));
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, kShadowResolution, kShadowResolution);
// draw back faces (for teapot)
glDisable(GL_CULL_FACE);
// bind shadow shader
if (s_shadowProgram == GLuint(-1))
s_shadowProgram = CompileProgram(vertexShader, passThroughShader);
glUseProgram(s_shadowProgram);
glVerify(glUniformMatrix4fv(glGetUniformLocation(s_shadowProgram, "objectTransform"), 1, false, Matrix44::kIdentity));
}
void ShadowEnd()
{
glDisable(GL_POLYGON_OFFSET_FILL);
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo));
glEnable(GL_CULL_FACE);
glUseProgram(0);
}
void BindSolidShader(Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ShadowMap* shadowMap, float bias, Vec4 fogColor)
{
glVerify(glViewport(0, 0, g_screenWidth, g_screenHeight));
if (s_diffuseProgram == GLuint(-1))
s_diffuseProgram = CompileProgram(vertexShader, fragmentShader);
if (s_diffuseProgram)
{
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glVerify(glUseProgram(s_diffuseProgram));
glVerify(glUniform1i(glGetUniformLocation(s_diffuseProgram, "grid"), 0));
glVerify(glUniform1f( glGetUniformLocation(s_diffuseProgram, "spotMin"), g_spotMin));
glVerify(glUniform1f( glGetUniformLocation(s_diffuseProgram, "spotMax"), g_spotMax));
glVerify(glUniform4fv( glGetUniformLocation(s_diffuseProgram, "fogColor"), 1, fogColor));
glVerify(glUniformMatrix4fv( glGetUniformLocation(s_diffuseProgram, "objectTransform"), 1, false, Matrix44::kIdentity));
// set shadow parameters
ShadowApply(s_diffuseProgram, lightPos, lightTarget, lightTransform, shadowMap->texture);
}
}
void UnbindSolidShader()
{
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glUseProgram(0);
}
void SetMaterial(const Matrix44& xform, const RenderMaterial& mat)
{
GLint program;
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
if (program)
{
glUniformMatrix4fv( glGetUniformLocation(program, "objectTransform"), 1, false, xform);
const float maxSpecularPower = 2048.0f;
glVerify(glUniform1f(glGetUniformLocation(program, "specularPower"), powf(maxSpecularPower, 1.0f-mat.roughness)));
glVerify(glUniform3fv(glGetUniformLocation(program, "specularColor"), 1, Lerp(Vec3(mat.specular*0.08f), mat.frontColor, mat.metallic)));
glVerify(glUniform1f(glGetUniformLocation(program, "roughness"), mat.roughness));
glVerify(glUniform1f(glGetUniformLocation(program, "metallic"), mat.metallic));
// set material properties
if (mat.colorTex)
{
GLuint tex = mat.colorTex->colorTex;
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glVerify(glUniform1i(glGetUniformLocation(program, "tex"), 1)); // use slot one
glVerify(glUniform1i(glGetUniformLocation(program, "texture"), 1)); // enable tex sampling
}
else
{
glVerify(glUniform1i(glGetUniformLocation(program, "tex"), 1)); // use slot one
glVerify(glUniform1i(glGetUniformLocation(program, "texture"), 0)); // disable tex sampling}
}
}
glVerify(glColor3fv(mat.frontColor));
glVerify(glSecondaryColor3fv(mat.backColor));
}
void DrawPlanes(Vec4* planes, int n, float bias)
{
// diffuse
glColor3f(0.9f, 0.9f, 0.9f);
GLint uBias = glGetUniformLocation(s_diffuseProgram, "bias");
glVerify(glUniform1f(uBias, 0.0f));
GLint uGrid = glGetUniformLocation(s_diffuseProgram, "grid");
glVerify(glUniform1i(uGrid, 1));
GLint uExpand = glGetUniformLocation(s_diffuseProgram, "expand");
glVerify(glUniform1f(uExpand, 0.0f));
for (int i=0; i < n; ++i)
{
Vec4 p = planes[i];
p.w -= bias;
DrawPlane(p, false);
}
glVerify(glUniform1i(uGrid, 0));
glVerify(glUniform1f(uBias, g_shadowBias));
}
void DrawMesh(const Mesh* m, Vec3 color)
{
if (m)
{
glVerify(glColor3fv(color));
glVerify(glSecondaryColor3fv(color));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
glVerify(glEnableClientState(GL_NORMAL_ARRAY));
glVerify(glEnableClientState(GL_VERTEX_ARRAY));
glVerify(glNormalPointer(GL_FLOAT, sizeof(float) * 3, &m->m_normals[0]));
glVerify(glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, &m->m_positions[0]));
if (m->m_colours.size())
{
glVerify(glEnableClientState(GL_COLOR_ARRAY));
glVerify(glColorPointer(4, GL_FLOAT, 0, &m->m_colours[0]));
}
glVerify(glDrawElements(GL_TRIANGLES, m->GetNumFaces() * 3, GL_UNSIGNED_INT, &m->m_indices[0]));
glVerify(glDisableClientState(GL_VERTEX_ARRAY));
glVerify(glDisableClientState(GL_NORMAL_ARRAY));
if (m->m_colours.size())
glVerify(glDisableClientState(GL_COLOR_ARRAY));
}
}
void DrawCloth(const Vec4* positions, const Vec4* normals, const float* uvs, const int* indices, int numTris, int numPositions, int colorIndex, float expand, bool twosided, bool smooth)
{
if (!numTris)
return;
if (twosided)
glDisable(GL_CULL_FACE);
#if 1
GLint program;
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
if (program == GLint(s_diffuseProgram))
{
GLint uBias = glGetUniformLocation(s_diffuseProgram, "bias");
glUniform1f(uBias, 0.0f);
GLint uExpand = glGetUniformLocation(s_diffuseProgram, "expand");
glUniform1f(uExpand, expand);
}
#endif
glColor3fv(g_colors[colorIndex+1]*1.5f);
glSecondaryColor3fv(g_colors[colorIndex]*1.5f);
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
glVerify(glEnableClientState(GL_VERTEX_ARRAY));
glVerify(glEnableClientState(GL_NORMAL_ARRAY));
glVerify(glVertexPointer(3, GL_FLOAT, sizeof(float)*4, positions));
glVerify(glNormalPointer(GL_FLOAT, sizeof(float)*4, normals));
glVerify(glDrawElements(GL_TRIANGLES, numTris*3, GL_UNSIGNED_INT, indices));
glVerify(glDisableClientState(GL_VERTEX_ARRAY));
glVerify(glDisableClientState(GL_NORMAL_ARRAY));
if (twosided)
glEnable(GL_CULL_FACE);
#if 1
if (program == GLint(s_diffuseProgram))
{
GLint uBias = glGetUniformLocation(s_diffuseProgram, "bias");
glUniform1f(uBias, g_shadowBias);
GLint uExpand = glGetUniformLocation(s_diffuseProgram, "expand");
glUniform1f(uExpand, 0.0f);
}
#endif
}
void DrawRope(Vec4* positions, int* indices, int numIndices, float radius, int color)
{
if (numIndices < 2)
return;
std::vector<Vec3> vertices;
std::vector<Vec3> normals;
std::vector<int> triangles;
// flatten curve
std::vector<Vec3> curve(numIndices);
for (int i=0; i < numIndices; ++i)
curve[i] = Vec3(positions[indices[i]]);
const int resolution = 8;
const int smoothing = 3;
vertices.reserve(resolution*numIndices*smoothing);
normals.reserve(resolution*numIndices*smoothing);
triangles.reserve(numIndices*resolution*6*smoothing);
Extrude(&curve[0], int(curve.size()), vertices, normals, triangles, radius, resolution, smoothing);
glVerify(glDisable(GL_CULL_FACE));
glVerify(glColor3fv(g_colors[color%8]*1.5f));
glVerify(glSecondaryColor3fv(g_colors[color%8]*1.5f));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
glVerify(glEnableClientState(GL_VERTEX_ARRAY));
glVerify(glEnableClientState(GL_NORMAL_ARRAY));
glVerify(glVertexPointer(3, GL_FLOAT, sizeof(float)*3, &vertices[0]));
glVerify(glNormalPointer(GL_FLOAT, sizeof(float)*3, &normals[0]));
glVerify(glDrawElements(GL_TRIANGLES, GLsizei(triangles.size()), GL_UNSIGNED_INT, &triangles[0]));
glVerify(glDisableClientState(GL_VERTEX_ARRAY));
glVerify(glDisableClientState(GL_NORMAL_ARRAY));
glVerify(glEnable(GL_CULL_FACE));
}
struct ReflectMap
{
GLuint texture;
int width;
int height;
};
ReflectMap* ReflectCreate(int width, int height)
{
GLuint texture;
// copy frame buffer to texture
glVerify(glActiveTexture(GL_TEXTURE0));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glGenTextures(1, &texture));
glVerify(glBindTexture(GL_TEXTURE_2D, texture));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
ReflectMap* map = new ReflectMap();
map->texture = texture;
map->width = width;
map->height = height;
return map;
}
void ReflectDestroy(ReflectMap* map)
{
glVerify(glDeleteTextures(1, &map->texture));
delete map;
}
void ReflectBegin(ReflectMap* map, Vec4 plane, int width, int height)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Matrix44 scale = Matrix44::kIdentity;
scale.columns[0][0] *= -2.0f;
scale.columns[1][1] *= -2.0f;
scale.columns[2][2] *= -2.0f;
scale.columns[3][3] *= -2.0f;
Matrix44 reflect = (scale*Outer(Vec4(plane.x, plane.y, plane.z, 0.0f), plane));
reflect.columns[0][0] += 1.0f;
reflect.columns[1][1] += 1.0f;
reflect.columns[2][2] += 1.0f;
reflect.columns[3][3] += 1.0f;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(reflect);
glVerify(glFrontFace(GL_CW));
glVerify(glEnable(GL_CLIP_PLANE0));
glVerify(glUniform4fv( glGetUniformLocation(s_diffuseProgram, "clipPlane"), 1, plane));
}
void ReflectEnd(ReflectMap* map, int width, int height)
{
// copy frame buffer to texture
glVerify(glActiveTexture(GL_TEXTURE0));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glBindTexture(GL_TEXTURE_2D, map->texture));
glVerify(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height));
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glVerify(glDisable(GL_CLIP_PLANE0));
glVerify(glFrontFace(GL_CCW));
glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo);
glViewport(0, 0, g_screenWidth, g_screenHeight);
}
//-----------------------------------------------------------------------------------------------------
// vertex shader
const char *vertexPointDepthShader = STRINGIFY(
uniform float pointRadius; // point size in world space
uniform float pointScale; // scale to calculate size in pixels
void main()
{
// calculate window-space point size
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
gl_PointSize = pointScale * (pointRadius / gl_Position.w);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_ModelViewMatrix * vec4(gl_Vertex.xyz, 1.0);
}
);
// pixel shader for rendering points as shaded spheres
const char *fragmentPointDepthShader = STRINGIFY(
uniform float pointRadius; // point size in world space
void main()
{
// calculate normal from texture coordinates
vec3 normal;
normal.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0);
float mag = dot(normal.xy, normal.xy);
if (mag > 1.0) discard; // kill pixels outside circle
normal.z = sqrt(1.0-mag);
vec3 eyePos = gl_TexCoord[1].xyz + normal*pointRadius*2.0;
vec4 ndcPos = gl_ProjectionMatrix * vec4(eyePos, 1.0);
ndcPos.z /= ndcPos.w;
gl_FragColor = vec4(eyePos.z, 1.0, 1.0, 1.0);
gl_FragDepth = ndcPos.z*0.5 + 0.5;
}
);
// pixel shader for rendering points density
const char *fragmentPointThicknessShader = STRINGIFY(
void main()
{
// calculate normal from texture coordinates
vec3 normal;
normal.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0);
float mag = dot(normal.xy, normal.xy);
if (mag > 1.0) discard; // kill pixels outside circle
normal.z = sqrt(1.0-mag);
gl_FragColor = vec4(normal.z*0.005);
}
);
//--------------------------------------------------------
// Ellipsoid shaders
//
const char *vertexEllipsoidDepthShader = "#version 120\n" STRINGIFY(
// rotation matrix in xyz, scale in w
attribute vec4 q1;
attribute vec4 q2;
attribute vec4 q3;
// returns 1.0 for x==0.0 (unlike glsl)
float Sign(float x) { return x < 0.0 ? -1.0: 1.0; }
bool solveQuadratic(float a, float b, float c, out float minT, out float maxT)
{
if (a == 0.0 && b == 0.0)
{
minT = maxT = 0.0;
return false;
}
float discriminant = b*b - 4.0*a*c;
if (discriminant < 0.0)
{
return false;
}
float t = -0.5*(b + Sign(b)*sqrt(discriminant));
minT = t / a;
maxT = c / t;
if (minT > maxT)
{
float tmp = minT;
minT = maxT;
maxT = tmp;
}
return true;
}
float DotInvW(vec4 a, vec4 b) { return a.x*b.x + a.y*b.y + a.z*b.z - a.w*b.w; }
void main()
{
vec3 worldPos = gl_Vertex.xyz;// - vec3(0.0, 0.1*0.25, 0.0); // hack move towards ground to account for anisotropy
// construct quadric matrix
mat4 q;
q[0] = vec4(q1.xyz*q1.w, 0.0);
q[1] = vec4(q2.xyz*q2.w, 0.0);
q[2] = vec4(q3.xyz*q3.w, 0.0);
q[3] = vec4(worldPos, 1.0);
// transforms a normal to parameter space (inverse transpose of (q*modelview)^-T)
mat4 invClip = transpose(gl_ModelViewProjectionMatrix*q);
// solve for the right hand bounds in homogenous clip space
float a1 = DotInvW(invClip[3], invClip[3]);
float b1 = -2.0f*DotInvW(invClip[0], invClip[3]);
float c1 = DotInvW(invClip[0], invClip[0]);
float xmin;
float xmax;
solveQuadratic(a1, b1, c1, xmin, xmax);
// solve for the right hand bounds in homogenous clip space
float a2 = DotInvW(invClip[3], invClip[3]);
float b2 = -2.0f*DotInvW(invClip[1], invClip[3]);
float c2 = DotInvW(invClip[1], invClip[1]);
float ymin;
float ymax;
solveQuadratic(a2, b2, c2, ymin, ymax);
gl_Position = vec4(worldPos.xyz, 1.0);
gl_TexCoord[0] = vec4(xmin, xmax, ymin, ymax);
// construct inverse quadric matrix (used for ray-casting in parameter space)
mat4 invq;
invq[0] = vec4(q1.xyz/q1.w, 0.0);
invq[1] = vec4(q2.xyz/q2.w, 0.0);
invq[2] = vec4(q3.xyz/q3.w, 0.0);
invq[3] = vec4(0.0, 0.0, 0.0, 1.0);
invq = transpose(invq);
invq[3] = -(invq*gl_Position);
// transform a point from view space to parameter space
invq = invq*gl_ModelViewMatrixInverse;
// pass down
gl_TexCoord[1] = invq[0];
gl_TexCoord[2] = invq[1];
gl_TexCoord[3] = invq[2];
gl_TexCoord[4] = invq[3];
// compute ndc pos for frustrum culling in GS
vec4 ndcPos = gl_ModelViewProjectionMatrix * vec4(worldPos.xyz, 1.0);
gl_TexCoord[5] = ndcPos / ndcPos.w;
}
);
const char* geometryEllipsoidDepthShader =
"#version 120\n"
"#extension GL_EXT_geometry_shader4 : enable\n"
STRINGIFY(
void main()
{
vec3 pos = gl_PositionIn[0].xyz;
vec4 bounds = gl_TexCoordIn[0][0];
vec4 ndcPos = gl_TexCoordIn[0][5];
// frustrum culling
const float ndcBound = 1.0;
if (ndcPos.x < -ndcBound) return;
if (ndcPos.x > ndcBound) return;
if (ndcPos.y < -ndcBound) return;
if (ndcPos.y > ndcBound) return;
float xmin = bounds.x;
float xmax = bounds.y;
float ymin = bounds.z;
float ymax = bounds.w;
// inv quadric transform
gl_TexCoord[0] = gl_TexCoordIn[0][1];
gl_TexCoord[1] = gl_TexCoordIn[0][2];
gl_TexCoord[2] = gl_TexCoordIn[0][3];
gl_TexCoord[3] = gl_TexCoordIn[0][4];
gl_Position = vec4(xmin, ymax, 0.0, 1.0);
EmitVertex();
gl_Position = vec4(xmin, ymin, 0.0, 1.0);
EmitVertex();
gl_Position = vec4(xmax, ymax, 0.0, 1.0);
EmitVertex();
gl_Position = vec4(xmax, ymin, 0.0, 1.0);
EmitVertex();
}
);
// pixel shader for rendering points as shaded spheres
const char *fragmentEllipsoidDepthShader = "#version 120\n" STRINGIFY(
uniform vec3 invViewport;
uniform vec3 invProjection;
float Sign(float x) { return x < 0.0 ? -1.0: 1.0; }
bool solveQuadratic(float a, float b, float c, out float minT, out float maxT)
{
if (a == 0.0 && b == 0.0)
{
minT = maxT = 0.0;
return true;
}
float discriminant = b*b - 4.0*a*c;
if (discriminant < 0.0)
{
return false;
}
float t = -0.5*(b + Sign(b)*sqrt(discriminant));
minT = t / a;
maxT = c / t;
if (minT > maxT)
{
float tmp = minT;
minT = maxT;
maxT = tmp;
}
return true;
}
float sqr(float x) { return x*x; }
void main()
{
// transform from view space to parameter space
mat4 invQuadric;
invQuadric[0] = gl_TexCoord[0];
invQuadric[1] = gl_TexCoord[1];
invQuadric[2] = gl_TexCoord[2];
invQuadric[3] = gl_TexCoord[3];
vec4 ndcPos = vec4(gl_FragCoord.xy*invViewport.xy*vec2(2.0, 2.0) - vec2(1.0, 1.0), -1.0, 1.0);
vec4 viewDir = gl_ProjectionMatrixInverse*ndcPos;
// ray to parameter space
vec4 dir = invQuadric*vec4(viewDir.xyz, 0.0);
vec4 origin = invQuadric[3];
// set up quadratric equation
float a = sqr(dir.x) + sqr(dir.y) + sqr(dir.z);// - sqr(dir.w);
float b = dir.x*origin.x + dir.y*origin.y + dir.z*origin.z - dir.w*origin.w;
float c = sqr(origin.x) + sqr(origin.y) + sqr(origin.z) - sqr(origin.w);
float minT;
float maxT;
if (solveQuadratic(a, 2.0*b, c, minT, maxT))
{
vec3 eyePos = viewDir.xyz*minT;
vec4 ndcPos = gl_ProjectionMatrix * vec4(eyePos, 1.0);
ndcPos.z /= ndcPos.w;
gl_FragColor = vec4(eyePos.z, 1.0, 1.0, 1.0);
gl_FragDepth = ndcPos.z*0.5 + 0.5;
return;
}
else
discard;
gl_FragColor = vec4(0.5, 0.0, 0.0, 1.0);
}
);
//--------------------------------------------------------------------------------
// Composite shaders
const char* vertexPassThroughShader = STRINGIFY(
void main()
{
gl_Position = vec4(gl_Vertex.xyz, 1.0);
gl_TexCoord[0] = gl_MultiTexCoord0;
}
);
const char* fragmentBlurDepthShader =
"#extension GL_ARB_texture_rectangle : enable\n"
STRINGIFY(
uniform sampler2DRect depthTex;
uniform sampler2D thicknessTex;
uniform float blurRadiusWorld;
uniform float blurScale;
uniform float blurFalloff;
uniform vec2 invTexScale;
uniform bool debug;
float sqr(float x) { return x*x; }
void main()
{
// eye-space depth of center sample
float depth = texture2DRect(depthTex, gl_FragCoord.xy).x;
float thickness = texture2D(thicknessTex, gl_TexCoord[0].xy).x;
// hack: ENABLE_SIMPLE_FLUID
//thickness = 0.0f;
if (debug)
{
// do not blur
gl_FragColor.x = depth;
return;
}
// threshold on thickness to create nice smooth silhouettes
if (depth == 0.0)//|| thickness < 0.02f)
{
gl_FragColor.x = 0.0;
return;
}
/*
float dzdx = dFdx(depth);
float dzdy = dFdy(depth);
// handle edge case
if (max(abs(dzdx), abs(dzdy)) > 0.05)
{
dzdx = 0.0;
dzdy = 0.0;
gl_FragColor.x = depth;
return;
}
*/
float blurDepthFalloff = 5.5;//blurFalloff*mix(4.0, 1.0, thickness)/blurRadiusWorld*0.0375; // these constants are just a re-scaling from some known good values
float maxBlurRadius = 5.0;
//float taps = min(maxBlurRadius, blurScale * (blurRadiusWorld / -depth));
//vec2 blurRadius = min(mix(0.25, 2.0/blurFalloff, thickness) * blurScale * (blurRadiusWorld / -depth) / taps, 0.15)*invTexScale;
//discontinuities between different tap counts are visible. to avoid this we
//use fractional contributions between #taps = ceil(radius) and floor(radius)
float radius = min(maxBlurRadius, blurScale * (blurRadiusWorld / -depth));
float radiusInv = 1.0/radius;
float taps = ceil(radius);
float frac = taps - radius;
float sum = 0.0;
float wsum = 0.0;
float count = 0.0;
for(float y=-taps; y <= taps; y += 1.0)
{
for(float x=-taps; x <= taps; x += 1.0)
{
vec2 offset = vec2(x, y);
float sample = texture2DRect(depthTex, gl_FragCoord.xy + offset).x;
if (sample < -10000.0*0.5)
continue;
// spatial domain
float r1 = length(vec2(x, y))*radiusInv;
float w = exp(-(r1*r1));
//float expectedDepth = depth + dot(vec2(dzdx, dzdy), offset);
// range domain (based on depth difference)
float r2 = (sample - depth) * blurDepthFalloff;
float g = exp(-(r2*r2));
//fractional radius contributions
float wBoundary = step(radius, max(abs(x), abs(y)));
float wFrac = 1.0 - wBoundary*frac;
sum += sample * w * g * wFrac;
wsum += w * g * wFrac;
count += g * wFrac;
}
}
if (wsum > 0.0) {
sum /= wsum;
}
float blend = count/sqr(2.0*radius+1.0);
gl_FragColor.x = mix(depth, sum, blend);
}
);
const char* fragmentCompositeShader = STRINGIFY(
uniform sampler2D tex;
uniform vec2 invTexScale;
uniform vec3 lightPos;
uniform vec3 lightDir;
uniform float spotMin;
uniform float spotMax;
uniform vec4 color;
uniform float ior;
uniform vec2 clipPosToEye;
uniform sampler2D reflectTex;
uniform sampler2DShadow shadowTex;
uniform vec2 shadowTaps[12];
uniform mat4 lightTransform;
uniform sampler2D thicknessTex;
uniform sampler2D sceneTex;
uniform bool debug;
// sample shadow map
float shadowSample(vec3 worldPos, out float attenuation)
{
// hack: ENABLE_SIMPLE_FLUID
//attenuation = 0.0f;
//return 0.5;
vec4 pos = lightTransform*vec4(worldPos+lightDir*0.15, 1.0);
pos /= pos.w;
vec3 uvw = (pos.xyz*0.5)+vec3(0.5);
attenuation = max(smoothstep(spotMax, spotMin, dot(pos.xy, pos.xy)), 0.05);
// user clip
if (uvw.x < 0.0 || uvw.x > 1.0)
return 1.0;
if (uvw.y < 0.0 || uvw.y > 1.0)
return 1.0;
float s = 0.0;
float radius = 0.002;
for (int i=0; i < 8; i++)
{
s += shadow2D(shadowTex, vec3(uvw.xy + shadowTaps[i]*radius, uvw.z)).r;
}
s /= 8.0;
return s;
}
vec3 viewportToEyeSpace(vec2 coord, float eyeZ)
{
// find position at z=1 plane
vec2 uv = (coord*2.0 - vec2(1.0))*clipPosToEye;
return vec3(-uv*eyeZ, eyeZ);
}
vec3 srgbToLinear(vec3 c) { return pow(c, vec3(2.2)); }
vec3 linearToSrgb(vec3 c) { return pow(c, vec3(1.0/2.2)); }
float sqr(float x) { return x*x; }
float cube(float x) { return x*x*x; }
void main()
{
float eyeZ = texture2D(tex, gl_TexCoord[0].xy).x;
if (eyeZ == 0.0)
discard;
// reconstruct eye space pos from depth
vec3 eyePos = viewportToEyeSpace(gl_TexCoord[0].xy, eyeZ);
// finite difference approx for normals, can't take dFdx because
// the one-sided difference is incorrect at shape boundaries
vec3 zl = eyePos - viewportToEyeSpace(gl_TexCoord[0].xy - vec2(invTexScale.x, 0.0), texture2D(tex, gl_TexCoord[0].xy - vec2(invTexScale.x, 0.0)).x);
vec3 zr = viewportToEyeSpace(gl_TexCoord[0].xy + vec2(invTexScale.x, 0.0), texture2D(tex, gl_TexCoord[0].xy + vec2(invTexScale.x, 0.0)).x) - eyePos;
vec3 zt = viewportToEyeSpace(gl_TexCoord[0].xy + vec2(0.0, invTexScale.y), texture2D(tex, gl_TexCoord[0].xy + vec2(0.0, invTexScale.y)).x) - eyePos;
vec3 zb = eyePos - viewportToEyeSpace(gl_TexCoord[0].xy - vec2(0.0, invTexScale.y), texture2D(tex, gl_TexCoord[0].xy - vec2(0.0, invTexScale.y)).x);
vec3 dx = zl;
vec3 dy = zt;
if (abs(zr.z) < abs(zl.z))
dx = zr;
if (abs(zb.z) < abs(zt.z))
dy = zb;
//vec3 dx = dFdx(eyePos.xyz);
//vec3 dy = dFdy(eyePos.xyz);
vec4 worldPos = gl_ModelViewMatrixInverse*vec4(eyePos, 1.0);
float attenuation;
float shadow = shadowSample(worldPos.xyz, attenuation);
vec3 l = (gl_ModelViewMatrix*vec4(lightDir, 0.0)).xyz;
vec3 v = -normalize(eyePos);
vec3 n = normalize(cross(dx, dy));
vec3 h = normalize(v + l);
vec3 skyColor = vec3(0.1, 0.2, 0.4)*1.2;
vec3 groundColor = vec3(0.1, 0.1, 0.2);
float fresnel = 0.1 + (1.0 - 0.1)*cube(1.0-max(dot(n, v), 0.0));
vec3 lVec = normalize(worldPos.xyz-lightPos);
float ln = dot(l, n)*attenuation;
vec3 rEye = reflect(-v, n).xyz;
vec3 rWorld = (gl_ModelViewMatrixInverse*vec4(rEye, 0.0)).xyz;
vec2 texScale = vec2(0.75, 1.0); // to account for backbuffer aspect ratio (todo: pass in)
float refractScale = ior*0.025;
float reflectScale = ior*0.1;
// attenuate refraction near ground (hack)
refractScale *= smoothstep(0.1, 0.4, worldPos.y);
vec2 refractCoord = gl_TexCoord[0].xy + n.xy*refractScale*texScale;
//vec2 refractCoord = gl_TexCoord[0].xy + refract(-v, n, 1.0/1.33)*refractScale*texScale;
// read thickness from refracted coordinate otherwise we get halos around objectsw
float thickness = max(texture2D(thicknessTex, refractCoord).x, 0.3);
//vec3 transmission = exp(-(vec3(1.0)-color.xyz)*thickness);
vec3 transmission = (1.0-(1.0-color.xyz)*thickness*0.8)*color.w;
vec3 refract = texture2D(sceneTex, refractCoord).xyz*transmission;
vec2 sceneReflectCoord = gl_TexCoord[0].xy - rEye.xy*texScale*reflectScale/eyePos.z;
vec3 sceneReflect = (texture2D(sceneTex, sceneReflectCoord).xyz)*shadow;
vec3 planarReflect = texture2D(reflectTex, gl_TexCoord[0].xy).xyz;
planarReflect = vec3(0.0);
// fade out planar reflections above the ground
vec3 reflect = mix(planarReflect, sceneReflect, smoothstep(0.05, 0.3, worldPos.y)) + mix(groundColor, skyColor, smoothstep(0.15, 0.25, rWorld.y)*shadow);
// lighting
vec3 diffuse = color.xyz*mix(vec3(0.29, 0.379, 0.59), vec3(1.0), (ln*0.5 + 0.5)*max(shadow, 0.4))*(1.0-color.w);
vec3 specular = vec3(1.2*pow(max(dot(h, n), 0.0), 400.0));
gl_FragColor.xyz = diffuse + (mix(refract, reflect, fresnel) + specular)*color.w;
gl_FragColor.w = 1.0;
if (debug)
gl_FragColor = vec4(n*0.5 + vec3(0.5), 1.0);
// write valid z
vec4 clipPos = gl_ProjectionMatrix*vec4(0.0, 0.0, eyeZ, 1.0);
clipPos.z /= clipPos.w;
gl_FragDepth = clipPos.z*0.5 + 0.5;
}
);
FluidRenderer* CreateFluidRenderer(uint32_t width, uint32_t height)
{
FluidRenderer* renderer = new FluidRenderer();
renderer->mSceneWidth = width;
renderer->mSceneHeight = height;
// scene depth texture
glVerify(glGenTextures(1, &renderer->mDepthTex));
glVerify(glBindTexture(GL_TEXTURE_RECTANGLE_ARB, renderer->mDepthTex));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glVerify(glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE32F_ARB, width, height, 0, GL_LUMINANCE, GL_FLOAT, NULL));
// smoothed depth texture
glVerify(glGenTextures(1, &renderer->mDepthSmoothTex));
glVerify(glBindTexture(GL_TEXTURE_2D, renderer->mDepthSmoothTex));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE32F_ARB, width, height, 0, GL_LUMINANCE, GL_FLOAT, NULL));
// scene copy
glVerify(glGenTextures(1, &renderer->mSceneTex));
glVerify(glBindTexture(GL_TEXTURE_2D, renderer->mSceneTex));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
glVerify(glGenFramebuffers(1, &renderer->mSceneFbo));
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, renderer->mSceneFbo));
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderer->mSceneTex, 0));
// frame buffer
glVerify(glGenFramebuffers(1, &renderer->mDepthFbo));
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, renderer->mDepthFbo));
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, renderer->mDepthTex, 0));
GLuint zbuffer;
glVerify(glGenRenderbuffers(1, &zbuffer));
glVerify(glBindRenderbuffer(GL_RENDERBUFFER, zbuffer));
glVerify(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height));
glVerify(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, zbuffer));
glVerify(glDrawBuffer(GL_COLOR_ATTACHMENT0));
glVerify(glReadBuffer(GL_COLOR_ATTACHMENT0));
glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo);
// reflect texture
glVerify(glGenTextures(1, &renderer->mReflectTex));
glVerify(glBindTexture(GL_TEXTURE_2D, renderer->mReflectTex));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
// thickness texture
const int thicknessWidth = width;
const int thicknessHeight = height;
glVerify(glGenTextures(1, &renderer->mThicknessTex));
glVerify(glBindTexture(GL_TEXTURE_2D, renderer->mThicknessTex));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
#if USE_HDR_DIFFUSE_BLEND
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, thicknessWidth, thicknessHeight, 0, GL_RGBA, GL_FLOAT, NULL));
#else
glVerify(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, thicknessWidth, thicknessHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
#endif
// thickness buffer
glVerify(glGenFramebuffers(1, &renderer->mThicknessFbo));
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, renderer->mThicknessFbo));
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderer->mThicknessTex, 0));
GLuint thickz;
glVerify(glGenRenderbuffers(1, &thickz));
glVerify(glBindRenderbuffer(GL_RENDERBUFFER, thickz));
glVerify(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, thicknessWidth, thicknessHeight));
glVerify(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, thickz));
glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo);
// compile shaders
//renderer->mPointDepthProgram = CompileProgram(vertexPointDepthShader, fragmentPointDepthShader);
renderer->mPointThicknessProgram = CompileProgram(vertexPointDepthShader, fragmentPointThicknessShader);
//renderer->mEllipsoidThicknessProgram = CompileProgram(vertexEllipsoidDepthShader, fragmentEllipsoidThicknessShader);
renderer->mEllipsoidDepthProgram = CompileProgram(vertexEllipsoidDepthShader, fragmentEllipsoidDepthShader, geometryEllipsoidDepthShader);
renderer->mCompositeProgram = CompileProgram(vertexPassThroughShader, fragmentCompositeShader);
renderer->mDepthBlurProgram = CompileProgram(vertexPassThroughShader, fragmentBlurDepthShader);
return renderer;
}
void DestroyFluidRenderer(FluidRenderer* renderer)
{
glVerify(glDeleteFramebuffers(1, &renderer->mSceneFbo));
glVerify(glDeleteFramebuffers(1, &renderer->mDepthFbo));
glVerify(glDeleteTextures(1, &renderer->mDepthTex));
glVerify(glDeleteTextures(1, &renderer->mDepthSmoothTex));
glVerify(glDeleteTextures(1, &renderer->mSceneTex));
glVerify(glDeleteFramebuffers(1, &renderer->mThicknessFbo));
glVerify(glDeleteTextures(1, &renderer->mThicknessTex));
}
FluidRenderBuffers* CreateFluidRenderBuffers(int numFluidParticles, bool enableInterop)
{
FluidRenderBuffersGL* buffers = new FluidRenderBuffersGL(numFluidParticles);
// vbos
glVerify(glGenBuffers(1, &buffers->mPositionVBO));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mPositionVBO));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * numFluidParticles, 0, GL_DYNAMIC_DRAW));
// density
glVerify(glGenBuffers(1, &buffers->mDensityVBO));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDensityVBO));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(int)*numFluidParticles, 0, GL_DYNAMIC_DRAW));
for (int i = 0; i < 3; ++i)
{
glVerify(glGenBuffers(1, &buffers->mAnisotropyVBO[i]));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mAnisotropyVBO[i]));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * numFluidParticles, 0, GL_DYNAMIC_DRAW));
}
glVerify(glGenBuffers(1, &buffers->mIndices));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers->mIndices));
glVerify(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*numFluidParticles, 0, GL_DYNAMIC_DRAW));
if (enableInterop)
{
buffers->mPositionBuf = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mPositionVBO, numFluidParticles, sizeof(Vec4));
buffers->mDensitiesBuf = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mDensityVBO, numFluidParticles, sizeof(float));
buffers->mIndicesBuf = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mIndices, numFluidParticles, sizeof(int));
buffers->mAnisotropyBuf[0] = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mAnisotropyVBO[0], numFluidParticles, sizeof(Vec4));
buffers->mAnisotropyBuf[1] = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mAnisotropyVBO[1], numFluidParticles, sizeof(Vec4));
buffers->mAnisotropyBuf[2] = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mAnisotropyVBO[2], numFluidParticles, sizeof(Vec4));
}
return reinterpret_cast<FluidRenderBuffers*>(buffers);
}
void DestroyFluidRenderBuffers(FluidRenderBuffers* buffers)
{
delete reinterpret_cast<FluidRenderBuffersGL*>(buffers);
}
void UpdateFluidRenderBuffers(FluidRenderBuffers* buffersIn, NvFlexSolver* solver, bool anisotropy, bool density)
{
FluidRenderBuffersGL* buffers = reinterpret_cast<FluidRenderBuffersGL*>(buffersIn);
// use VBO buffer wrappers to allow Flex to write directly to the OpenGL buffers
// Flex will take care of any CUDA interop mapping/unmapping during the get() operations
if (!anisotropy)
{
// regular particles
NvFlexGetParticles(solver, buffers->mPositionBuf, NULL);
}
else
{
// fluid buffers
NvFlexGetSmoothParticles(solver, buffers->mPositionBuf, NULL);
NvFlexGetAnisotropy(solver, buffers->mAnisotropyBuf[0], buffers->mAnisotropyBuf[1], buffers->mAnisotropyBuf[2], NULL);
}
if (density)
{
NvFlexGetDensities(solver, buffers->mDensitiesBuf, NULL);
}
else
{
NvFlexGetPhases(solver, buffers->mDensitiesBuf, NULL);
}
NvFlexGetActive(solver, buffers->mIndicesBuf, NULL);
}
void UpdateFluidRenderBuffers(FluidRenderBuffers* buffersIn, Vec4* particles, float* densities, Vec4* anisotropy1, Vec4* anisotropy2, Vec4* anisotropy3, int numParticles, int* indices, int numIndices)
{
FluidRenderBuffersGL* buffers = reinterpret_cast<FluidRenderBuffersGL*>(buffersIn);
// regular particles
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mPositionVBO));
glVerify(glBufferSubData(GL_ARRAY_BUFFER, 0, buffers->mNumParticles*sizeof(Vec4), particles));
Vec4*const anisotropies[] =
{
anisotropy1,
anisotropy2,
anisotropy3,
};
for (int i = 0; i < 3; i++)
{
Vec4* anisotropy = anisotropies[i];
if (anisotropy)
{
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mAnisotropyVBO[i]));
glVerify(glBufferSubData(GL_ARRAY_BUFFER, 0, buffers->mNumParticles * sizeof(Vec4), anisotropy));
}
}
// density /phase buffer
if (densities)
{
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDensityVBO));
glVerify(glBufferSubData(GL_ARRAY_BUFFER, 0, buffers->mNumParticles*sizeof(float), densities));
}
if (indices)
{
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers->mIndices));
glVerify(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numIndices*sizeof(int), indices));
}
// reset
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
DiffuseRenderBuffers* CreateDiffuseRenderBuffers(int numDiffuseParticles, bool& enableInterop)
{
DiffuseRenderBuffersGL* buffers = new DiffuseRenderBuffersGL(numDiffuseParticles);
if (numDiffuseParticles > 0)
{
glVerify(glGenBuffers(1, &buffers->mDiffusePositionVBO));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDiffusePositionVBO));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * numDiffuseParticles, 0, GL_DYNAMIC_DRAW));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
glVerify(glGenBuffers(1, &buffers->mDiffuseVelocityVBO));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDiffuseVelocityVBO));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * numDiffuseParticles, 0, GL_DYNAMIC_DRAW));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
if (enableInterop)
{
buffers->mDiffusePositionsBuf = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mDiffusePositionVBO, numDiffuseParticles, sizeof(Vec4));
buffers->mDiffuseVelocitiesBuf = NvFlexRegisterOGLBuffer(g_flexLib, buffers->mDiffuseVelocityVBO, numDiffuseParticles, sizeof(Vec4));
}
}
return reinterpret_cast<DiffuseRenderBuffers*>(buffers);
}
void DestroyDiffuseRenderBuffers(DiffuseRenderBuffers* buffersIn)
{
DiffuseRenderBuffersGL* buffers = reinterpret_cast<DiffuseRenderBuffersGL*>(buffersIn);
if (buffers->mNumParticles > 0)
{
glDeleteBuffers(1, &buffers->mDiffusePositionVBO);
glDeleteBuffers(1, &buffers->mDiffuseVelocityVBO);
NvFlexUnregisterOGLBuffer(buffers->mDiffusePositionsBuf);
NvFlexUnregisterOGLBuffer(buffers->mDiffuseVelocitiesBuf);
}
}
void UpdateDiffuseRenderBuffers(DiffuseRenderBuffers* buffersIn, NvFlexSolver* solver)
{
DiffuseRenderBuffersGL* buffers = reinterpret_cast<DiffuseRenderBuffersGL*>(buffersIn);
// diffuse particles
if (buffers->mNumParticles)
{
NvFlexGetDiffuseParticles(solver, buffers->mDiffusePositionsBuf, buffers->mDiffuseVelocitiesBuf, NULL);
}
}
void UpdateDiffuseRenderBuffers(DiffuseRenderBuffers* buffersIn, Vec4* diffusePositions, Vec4* diffuseVelocities, int numDiffuseParticles)
{
DiffuseRenderBuffersGL* buffers = reinterpret_cast<DiffuseRenderBuffersGL*>(buffersIn);
// diffuse particles
if (buffers->mNumParticles)
{
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDiffusePositionVBO));
glVerify(glBufferSubData(GL_ARRAY_BUFFER, 0, buffers->mNumParticles*sizeof(Vec4), diffusePositions));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDiffuseVelocityVBO));
glVerify(glBufferSubData(GL_ARRAY_BUFFER, 0, buffers->mNumParticles*sizeof(Vec4), diffuseVelocities));
}
}
void RenderFullscreenQuad()
{
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
}
void RenderEllipsoids(FluidRenderer* render, FluidRenderBuffers* buffersIn, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ShadowMap* shadowMap, Vec4 color, float blur, float ior, bool debug)
{
FluidRenderBuffersGL* buffers = reinterpret_cast<FluidRenderBuffersGL*>(buffersIn);
#if !ENABLE_SIMPLE_FLUID
// resolve msaa back buffer to texture
glVerify(glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, g_msaaFbo));
glVerify(glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, render->mSceneFbo));
glVerify(glBlitFramebuffer(0, 0, GLsizei(screenWidth), GLsizei(screenWidth/screenAspect), 0, 0, GLsizei(screenWidth), GLsizei(screenWidth/screenAspect), GL_COLOR_BUFFER_BIT, GL_LINEAR));
//thickness texture
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, render->mThicknessFbo));
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render->mThicknessTex, 0));
glVerify(glDrawBuffer(GL_COLOR_ATTACHMENT0));
glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenWidth/screenAspect));
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glDepthMask(GL_TRUE);
glDisable(GL_CULL_FACE);
if (g_mesh)
OGL_Renderer::DrawMesh(g_mesh, Vec3(1.0f));
DrawShapes();
glClear(GL_COLOR_BUFFER_BIT);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_POINT_SPRITE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDepthMask(GL_FALSE);
// make sprites larger to get smoother thickness texture
const float thicknessScale = 4.0f;
glUseProgram(render->mPointThicknessProgram);
glUniform1f( glGetUniformLocation(render->mPointThicknessProgram, "pointRadius"), thicknessScale*radius);
glUniform1f( glGetUniformLocation(render->mPointThicknessProgram, "pointScale"), screenWidth/screenAspect * (1.0f / (tanf(fov*0.5f))));
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers->mPositionVBO);
glVertexPointer(3, GL_FLOAT, sizeof(float)*4, (void*)(offset*sizeof(float)*4));
glDrawArrays(GL_POINTS, 0, n);
glUseProgram(0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_POINT_SPRITE);
glDisable(GL_BLEND);
#endif
// depth texture
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, render->mDepthFbo));
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, render->mDepthTex, 0));
glVerify(glDrawBuffer(GL_COLOR_ATTACHMENT0));
// draw points
//glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glDisable(GL_POINT_SPRITE);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glViewport(0, 0, int(screenWidth), int(screenWidth/screenAspect));
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const float viewHeight = tanf(fov/2.0f);
glUseProgram(render->mEllipsoidDepthProgram);
glUniform3fv( glGetUniformLocation(render->mEllipsoidDepthProgram, "invViewport"), 1, Vec3(1.0f/screenWidth, screenAspect/screenWidth, 1.0f));
glUniform3fv( glGetUniformLocation(render->mEllipsoidDepthProgram, "invProjection"), 1, Vec3(screenAspect*viewHeight, viewHeight, 1.0f));
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers->mPositionVBO);
glVertexPointer(3, GL_FLOAT, sizeof(float)*4, 0);//(void*)(offset*sizeof(float)*4));
// ellipsoid eigenvectors
int s1 = glGetAttribLocation(render->mEllipsoidDepthProgram, "q1");
glEnableVertexAttribArray(s1);
glBindBuffer(GL_ARRAY_BUFFER, buffers->mAnisotropyVBO[0]);
glVertexAttribPointer(s1, 4, GL_FLOAT, GL_FALSE, 0, 0);// (void*)(offset*sizeof(float)*4));
int s2 = glGetAttribLocation(render->mEllipsoidDepthProgram, "q2");
glEnableVertexAttribArray(s2);
glBindBuffer(GL_ARRAY_BUFFER, buffers->mAnisotropyVBO[1]);
glVertexAttribPointer(s2, 4, GL_FLOAT, GL_FALSE, 0, 0);//(void*)(offset*sizeof(float)*4));
int s3 = glGetAttribLocation(render->mEllipsoidDepthProgram, "q3");
glEnableVertexAttribArray(s3);
glBindBuffer(GL_ARRAY_BUFFER, buffers->mAnisotropyVBO[2]);
glVertexAttribPointer(s3, 4, GL_FLOAT, GL_FALSE, 0, 0);// (void*)(offset*sizeof(float)*4));
glVerify(glDrawArrays(GL_POINTS, offset, n));
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableVertexAttribArray(s1);
glDisableVertexAttribArray(s2);
glDisableVertexAttribArray(s3);
glDisable(GL_POINT_SPRITE);
//---------------------------------------------------------------
// blur
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glVerify(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render->mDepthSmoothTex, 0));
glUseProgram(render->mDepthBlurProgram);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, render->mDepthTex);
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, render->mThicknessTex);
glVerify(glUniform1f( glGetUniformLocation(render->mDepthBlurProgram, "blurRadiusWorld"), radius*0.5f)); // blur half the radius by default
glVerify(glUniform1f( glGetUniformLocation(render->mDepthBlurProgram, "blurScale"), screenWidth/screenAspect * (1.0f / (tanf(fov*0.5f)))));
glVerify(glUniform2fv( glGetUniformLocation(render->mDepthBlurProgram, "invTexScale"), 1, Vec2(1.0f/screenAspect, 1.0f)));
glVerify(glUniform1f( glGetUniformLocation(render->mDepthBlurProgram, "blurFalloff"), blur));
glVerify(glUniform1i( glGetUniformLocation(render->mDepthBlurProgram, "depthTex"), 0));
glVerify(glUniform1i( glGetUniformLocation(render->mDepthBlurProgram, "thicknessTex"), 1));
glVerify(glUniform1i(glGetUniformLocation(render->mDepthBlurProgram, "debug"), debug));
glVerify(RenderFullscreenQuad());
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
//---------------------------------------------------------------
// composite with scene
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo));
glVerify(glEnable(GL_DEPTH_TEST));
glVerify(glDepthMask(GL_TRUE));
glVerify(glDisable(GL_BLEND));
glVerify(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
glVerify(glUseProgram(render->mCompositeProgram));
glVerify(glUniform2fv(glGetUniformLocation(render->mCompositeProgram, "invTexScale"), 1, Vec2(1.0f/screenWidth, screenAspect/screenWidth)));
glVerify(glUniform2fv(glGetUniformLocation(render->mCompositeProgram, "clipPosToEye"), 1, Vec2(tanf(fov*0.5f)*screenAspect, tanf(fov*0.5f))));
glVerify(glUniform4fv(glGetUniformLocation(render->mCompositeProgram, "color"), 1, color));
glVerify(glUniform1f(glGetUniformLocation(render->mCompositeProgram, "ior"), ior));
glVerify(glUniform1f(glGetUniformLocation(render->mCompositeProgram, "spotMin"), g_spotMin));
glVerify(glUniform1f(glGetUniformLocation(render->mCompositeProgram, "spotMax"), g_spotMax));
glVerify(glUniform1i(glGetUniformLocation(render->mCompositeProgram, "debug"), debug));
glVerify(glUniform3fv(glGetUniformLocation(render->mCompositeProgram, "lightPos"), 1, lightPos));
glVerify(glUniform3fv(glGetUniformLocation(render->mCompositeProgram, "lightDir"), 1, -Normalize(lightTarget-lightPos)));
glVerify(glUniformMatrix4fv(glGetUniformLocation(render->mCompositeProgram, "lightTransform"), 1, false, lightTransform));
const Vec2 taps[] =
{
Vec2(-0.326212f,-0.40581f),Vec2(-0.840144f,-0.07358f),
Vec2(-0.695914f,0.457137f),Vec2(-0.203345f,0.620716f),
Vec2(0.96234f,-0.194983f),Vec2(0.473434f,-0.480026f),
Vec2(0.519456f,0.767022f),Vec2(0.185461f,-0.893124f),
Vec2(0.507431f,0.064425f),Vec2(0.89642f,0.412458f),
Vec2(-0.32194f,-0.932615f),Vec2(-0.791559f,-0.59771f)
};
glVerify(glUniform2fv(glGetUniformLocation(render->mCompositeProgram, "shadowTaps"), 12, &taps[0].x));
// smoothed depth tex
glVerify(glActiveTexture(GL_TEXTURE0));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glBindTexture(GL_TEXTURE_2D, render->mDepthSmoothTex));
// shadow tex
glVerify(glActiveTexture(GL_TEXTURE1));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glBindTexture(GL_TEXTURE_2D, shadowMap->texture));
// thickness tex
glVerify(glActiveTexture(GL_TEXTURE2));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glBindTexture(GL_TEXTURE_2D, render->mThicknessTex));
// scene tex
glVerify(glActiveTexture(GL_TEXTURE3));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glBindTexture(GL_TEXTURE_2D, render->mSceneTex));
/*
// reflection tex
glVerify(glActiveTexture(GL_TEXTURE5));
glVerify(glEnable(GL_TEXTURE_2D));
glVerify(glBindTexture(GL_TEXTURE_2D, reflectMap->texture));
*/
glVerify(glUniform1i(glGetUniformLocation(render->mCompositeProgram, "tex"), 0));
glVerify(glUniform1i(glGetUniformLocation(render->mCompositeProgram, "shadowTex"), 1));
glVerify(glUniform1i(glGetUniformLocation(render->mCompositeProgram, "thicknessTex"), 2));
glVerify(glUniform1i(glGetUniformLocation(render->mCompositeProgram, "sceneTex"), 3));
glVerify(glUniform1i(glGetUniformLocation(render->mCompositeProgram, "reflectTex"), 5));
// -- end shadowing
// ignores projection matrices
glVerify(RenderFullscreenQuad());
// reset state
glActiveTexture(GL_TEXTURE5);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE3);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
//------------------------------------------------------------------------------
// Diffuse Shading
const char *vertexDiffuseShader = STRINGIFY(
uniform float pointRadius; // point size in world space
uniform float pointScale; // scale to calculate size in pixels
uniform vec3 lightPos;
uniform vec3 lightDir;
uniform mat4 lightTransform;
uniform float spotMin;
uniform float spotMax;
uniform vec4 color;
void main()
{
vec3 worldPos = gl_Vertex.xyz;// - vec3(0.0, 0.1*0.25, 0.0); // hack move towards ground to account for anisotropy;
vec4 eyePos = gl_ModelViewMatrix * vec4(worldPos, 1.0);
gl_Position = gl_ProjectionMatrix * eyePos;
//gl_Position.z -= 0.0025; // bias above fluid surface
// calculate window-space point size
gl_PointSize = pointRadius * (pointScale / gl_Position.w);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = vec4(worldPos, gl_Vertex.w);
gl_TexCoord[2] = eyePos;
gl_TexCoord[3].xyz = gl_ModelViewMatrix*vec4(gl_MultiTexCoord1.xyz, 0.0);
gl_TexCoord[4].xyzw = color;
// hack to color different emitters
if (gl_MultiTexCoord1.w == 2.0)
gl_TexCoord[4].xyzw = vec4(0.85, 0.65, 0.65, color.w);
else if (gl_MultiTexCoord1.w == 1.0)
gl_TexCoord[4].xyzw = vec4(0.65, 0.85, 0.65, color.w);
// compute ndc pos for frustrum culling in GS
vec4 ndcPos = gl_ModelViewProjectionMatrix * vec4(worldPos.xyz, 1.0);
gl_TexCoord[5] = ndcPos / ndcPos.w;
}
);
const char *geometryDiffuseShader =
"#version 120\n"
"#extension GL_EXT_geometry_shader4 : enable\n"
STRINGIFY(
uniform float pointScale; // point size in world space
uniform float motionBlurScale;
uniform float diffusion;
uniform vec3 lightDir;
void main()
{
vec4 ndcPos = gl_TexCoordIn[0][5];
// frustrum culling
const float ndcBound = 1.0;
if (ndcPos.x < -ndcBound) return;
if (ndcPos.x > ndcBound) return;
if (ndcPos.y < -ndcBound) return;
if (ndcPos.y > ndcBound) return;
float velocityScale = 1.0;
vec3 v = gl_TexCoordIn[0][3].xyz*velocityScale;
vec3 p = gl_TexCoordIn[0][2].xyz;
// billboard in eye space
vec3 u = vec3(0.0, pointScale, 0.0);
vec3 l = vec3(pointScale, 0.0, 0.0);
// increase size based on life
float lifeFade = mix(1.0f+diffusion, 1.0, min(1.0, gl_TexCoordIn[0][1].w*0.25f));
u *= lifeFade;
l *= lifeFade;
//lifeFade = 1.0;
float fade = 1.0/(lifeFade*lifeFade);
float vlen = length(v)*motionBlurScale;
if (vlen > 0.5)
{
float len = max(pointScale, vlen*0.016);
fade = min(1.0, 2.0/(len/pointScale));
u = normalize(v)*max(pointScale, vlen*0.016); // assume 60hz
l = normalize(cross(u, vec3(0.0, 0.0, -1.0)))*pointScale;
}
{
gl_TexCoord[1] = gl_TexCoordIn[0][1]; // vertex world pos (life in w)
gl_TexCoord[2] = gl_TexCoordIn[0][2]; // vertex eye pos
gl_TexCoord[3] = gl_TexCoordIn[0][3]; // vertex velocity in view space
gl_TexCoord[3].w = fade;
gl_TexCoord[4] = gl_ModelViewMatrix*vec4(lightDir, 0.0);
gl_TexCoord[4].w = gl_TexCoordIn[0][3].w; // attenuation
gl_TexCoord[5].xyzw = gl_TexCoordIn[0][4].xyzw; // color
float zbias = 0.0f;//0.00125*2.0;
gl_TexCoord[0] = vec4(0.0, 1.0, 0.0, 0.0);
gl_Position = gl_ProjectionMatrix * vec4(p + u - l, 1.0);
gl_Position.z -= zbias;
EmitVertex();
gl_TexCoord[0] = vec4(0.0, 0.0, 0.0, 0.0);
gl_Position = gl_ProjectionMatrix * vec4(p - u - l, 1.0);
gl_Position.z -= zbias;
EmitVertex();
gl_TexCoord[0] = vec4(1.0, 1.0, 0.0, 0.0);
gl_Position = gl_ProjectionMatrix * vec4(p + u + l, 1.0);
gl_Position.z -= zbias;
EmitVertex();
gl_TexCoord[0] = vec4(1.0, 0.0, 0.0, 0.0);
gl_Position = gl_ProjectionMatrix * vec4(p - u + l, 1.0);
gl_Position.z -= zbias;
EmitVertex();
}
}
);
const char *fragmentDiffuseShader = STRINGIFY(
float sqr(float x) { return x*x; }
float cube(float x) { return x*x*x; }
uniform sampler2D depthTex;
uniform sampler2D noiseTex;
uniform vec2 invViewport;
uniform vec4 color;
uniform bool front;
uniform bool shadow;
//uniform sampler2DShadow shadowTex;
uniform sampler2D shadowTex;
uniform vec2 shadowTaps[12];
uniform mat4 lightTransform;
uniform vec3 lightDir;
uniform float inscatterCoefficient;
uniform float outscatterCoefficient;
void main()
{
float attenuation = gl_TexCoord[4].w;
float lifeFade = min(1.0, gl_TexCoord[1].w*0.125);
// calculate normal from texture coordinates
vec3 normal;
normal.xy = gl_TexCoord[0].xy*vec2(2.0, 2.0) + vec2(-1.0, -1.0);
float mag = dot(normal.xy, normal.xy);
if (mag > 1.0) discard; // kill pixels outside circle
normal.z = 1.0-mag;
float velocityFade = gl_TexCoord[3].w;
float alpha = lifeFade*velocityFade*sqr(normal.z);
gl_FragColor = alpha;
}
);
int GetNumDiffuseRenderParticles(DiffuseRenderBuffers* buffers)
{
return reinterpret_cast<DiffuseRenderBuffersGL*>(buffers)->mNumParticles;
}
void RenderDiffuse(FluidRenderer* render, DiffuseRenderBuffers* buffersIn, int n, float radius, float screenWidth, float screenAspect, float fov, Vec4 color, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ShadowMap* shadowMap, float motionBlur, float inscatter, float outscatter, bool shadow, bool front)
{
DiffuseRenderBuffersGL* buffers = reinterpret_cast<DiffuseRenderBuffersGL*>(buffersIn);
static int sprogram = -1;
if (sprogram == -1)
sprogram = CompileProgram(vertexDiffuseShader, fragmentDiffuseShader, geometryDiffuseShader);
int thicknessScale = 1;
if (sprogram)
{
#if USE_HDR_DIFFUSE_BLEND
{
glVerify(glBindFramebuffer(GL_READ_FRAMEBUFFER, g_msaaFbo));
glVerify(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, render->mThicknessFbo));
glVerify(glBlitFramebuffer(0, 0, render->mSceneWidth, render->mSceneHeight, 0, 0, render->mSceneWidth/thicknessScale, render->mSceneHeight/thicknessScale, GL_DEPTH_BUFFER_BIT, GL_NEAREST));
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
#endif
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(sprogram);
glUniform1f( glGetUniformLocation(sprogram, "motionBlurScale"), motionBlur);
glUniform1f( glGetUniformLocation(sprogram, "diffusion"), 1.0f);
glUniform1f( glGetUniformLocation(sprogram, "pointScale"), radius*1.0f);
glUniform1f( glGetUniformLocation(sprogram, "pointRadius"), screenWidth / float(thicknessScale) / (2.0f*screenAspect*tanf(fov*0.5f)));
glUniform2fv( glGetUniformLocation(sprogram, "invViewport"), 1, Vec2(1.0f/screenWidth, screenAspect/screenWidth));
glUniform4fv( glGetUniformLocation(sprogram, "color"), 1, color);
glUniform1i( glGetUniformLocation(sprogram, "tex"), 0);
glUniform1f( glGetUniformLocation(sprogram, "inscatterCoefficient"), inscatter);
glUniform1f( glGetUniformLocation(sprogram, "outscatterCoefficient"), outscatter);
GLint uLightTransform = glGetUniformLocation(sprogram, "lightTransform");
glUniformMatrix4fv(uLightTransform, 1, false, lightTransform);
GLint uLightPos = glGetUniformLocation(sprogram, "lightPos");
glUniform3fv(uLightPos, 1, lightPos);
GLint uLightDir = glGetUniformLocation(sprogram, "lightDir");
glUniform3fv(uLightDir, 1, Normalize(lightTarget-lightPos));
glUniform1f( glGetUniformLocation(sprogram, "spotMin"), g_spotMin);
glUniform1f( glGetUniformLocation(sprogram, "spotMax"), g_spotMax);
const Vec2 taps[] =
{
Vec2(-0.326212f,-0.40581f),Vec2(-0.840144f,-0.07358f),
Vec2(-0.695914f,0.457137f),Vec2(-0.203345f,0.620716f),
Vec2(0.96234f,-0.194983f),Vec2(0.473434f,-0.480026f),
Vec2(0.519456f,0.767022f),Vec2(0.185461f,-0.893124f),
Vec2(0.507431f,0.064425f),Vec2(0.89642f,0.412458f),
Vec2(-0.32194f,-0.932615f),Vec2(-0.791559f,-0.59771f)
};
glVerify(glUniform2fv(glGetUniformLocation(sprogram, "shadowTaps"), 12, &taps[0].x));
glVerify(glUniform1i(glGetUniformLocation(sprogram, "noiseTex"), 2));
glVerify(glUniform1i(glGetUniformLocation(sprogram, "shadowTex"), 1));
glVerify(glUniform1i(glGetUniformLocation(sprogram, "depthTex"), 0));
glVerify(glUniform1i(glGetUniformLocation(sprogram, "front"), front));
glVerify(glUniform1i(glGetUniformLocation(sprogram, "shadow"), shadow));
// noise tex
//glActiveTexture(GL_TEXTURE2);
//glEnable(GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, noiseTex);
// shadow tex
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, shadowMap->texture);
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE));
//glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL));
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, render->mDepthSmoothTex);
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVerify(glBindBuffer(GL_ARRAY_BUFFER, buffers->mDiffuseVelocityVBO));
glTexCoordPointer(4, GL_FLOAT, sizeof(float)*4, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers->mDiffusePositionVBO);
glVertexPointer(4, GL_FLOAT, sizeof(float)*4, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_POINTS, 0, n);
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_POINT_SPRITE);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glVerify(glActiveTexture(GL_TEXTURE2));
glVerify(glDisable(GL_TEXTURE_2D));
glVerify(glActiveTexture(GL_TEXTURE1));
glVerify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE));
glVerify(glDisable(GL_TEXTURE_2D));
glVerify(glActiveTexture(GL_TEXTURE0));
glVerify(glDisable(GL_TEXTURE_2D));
#if USE_HDR_DIFFUSE_BLEND
{
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo));
glVerify(glViewport(0, 0, int(screenWidth), int(screenWidth/screenAspect)));
//glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(0);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glVerify(glActiveTexture(GL_TEXTURE0));
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, render->mThicknessTex);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0);
RenderFullscreenQuad();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glDepthMask(GL_TRUE);
}
#endif
}
}
GpuMesh* CreateGpuMesh(const Mesh* m)
{
GpuMesh* mesh = new GpuMesh();
mesh->mNumVertices = m->GetNumVertices();
mesh->mNumFaces = m->GetNumFaces();
// vbos
glVerify(glGenBuffers(1, &mesh->mPositionsVBO));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, mesh->mPositionsVBO));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*m->m_positions.size(), &m->m_positions[0], GL_STATIC_DRAW));
glVerify(glGenBuffers(1, &mesh->mNormalsVBO));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, mesh->mNormalsVBO));
glVerify(glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*m->m_normals.size(), &m->m_normals[0], GL_STATIC_DRAW));
glVerify(glGenBuffers(1, &mesh->mIndicesIBO));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->mIndicesIBO));
glVerify(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*m->m_indices.size(), &m->m_indices[0], GL_STATIC_DRAW));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
return mesh;
}
void DestroyGpuMesh(GpuMesh* m)
{
glVerify(glDeleteBuffers(1, &m->mPositionsVBO));
glVerify(glDeleteBuffers(1, &m->mNormalsVBO));
glVerify(glDeleteBuffers(1, &m->mIndicesIBO));
}
void DrawGpuMesh(GpuMesh* m, const Matrix44& xform, const Vec3& color)
{
if (m)
{
GLint program;
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
if (program)
glUniformMatrix4fv( glGetUniformLocation(program, "objectTransform"), 1, false, xform);
glVerify(glColor3fv(color));
glVerify(glSecondaryColor3fv(color));
glVerify(glEnableClientState(GL_VERTEX_ARRAY));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, m->mPositionsVBO));
glVerify(glVertexPointer(3, GL_FLOAT, sizeof(float)*3, 0));
glVerify(glEnableClientState(GL_NORMAL_ARRAY));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, m->mNormalsVBO));
glVerify(glNormalPointer(GL_FLOAT, sizeof(float)*3, 0));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->mIndicesIBO));
glVerify(glDrawElements(GL_TRIANGLES, m->mNumFaces*3, GL_UNSIGNED_INT, 0));
glVerify(glDisableClientState(GL_VERTEX_ARRAY));
glVerify(glDisableClientState(GL_NORMAL_ARRAY));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, 0));
if (program)
glUniformMatrix4fv(glGetUniformLocation(program, "objectTransform"), 1, false, Matrix44::kIdentity);
}
}
void DrawGpuMeshInstances(GpuMesh* m, const Matrix44* xforms, int n, const Vec3& color)
{
if (m)
{
GLint program;
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
GLint param = glGetUniformLocation(program, "objectTransform");
glVerify(glColor3fv(color));
glVerify(glSecondaryColor3fv(color));
glVerify(glEnableClientState(GL_VERTEX_ARRAY));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, m->mPositionsVBO));
glVerify(glVertexPointer(3, GL_FLOAT, sizeof(float)*3, 0));
glVerify(glEnableClientState(GL_NORMAL_ARRAY));
glVerify(glBindBuffer(GL_ARRAY_BUFFER, m->mNormalsVBO));
glVerify(glNormalPointer(GL_FLOAT, sizeof(float)*3, 0));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->mIndicesIBO));
for (int i=0; i < n; ++i)
{
if (program)
glUniformMatrix4fv( param, 1, false, xforms[i]);
glVerify(glDrawElements(GL_TRIANGLES, m->mNumFaces*3, GL_UNSIGNED_INT, 0));
}
glVerify(glDisableClientState(GL_VERTEX_ARRAY));
glVerify(glDisableClientState(GL_NORMAL_ARRAY));
glVerify(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
}
void BeginLines()
{
glUseProgram(0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glLineWidth(1.0f);
for (int i = 0; i < 8; ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glDisable(GL_TEXTURE_2D);
}
glBegin(GL_LINES);
}
void DrawLine(const Vec3& p, const Vec3& q, const Vec4& color)
{
glColor4fv(color);
glVertex3fv(p);
glVertex3fv(q);
}
void EndLines()
{
glEnd();
}
void BeginPoints(float size)
{
glPointSize(size);
glUseProgram(0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POINT_SPRITE);
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
for (int i = 0; i < 8; ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glDisable(GL_TEXTURE_2D);
}
glBegin(GL_POINTS);
}
void DrawPoint(const Vec3& p, const Vec4& color)
{
glColor3fv(color);
glVertex3fv(p);
}
void EndPoints()
{
glEnd();
}
float SyncAndGetRenderTime(unsigned long long* begin, unsigned long long* end, unsigned long long* freq)
{
*begin = 0;
*end = 0;
*freq = 1;
return 0.0f;
}
float RendererGetDeviceTimestamps(unsigned long long* begin, unsigned long long* end, unsigned long long* freq) { return 0.0f; }
void* GetGraphicsCommandQueue() { return nullptr; }
void GraphicsTimerBegin() { }
void GraphicsTimerEnd() { }
void StartGpuWork() { }
void EndGpuWork() { }
void GetRenderDevice(void** deviceOut, void** contextOut)
{
*deviceOut = nullptr;
*contextOut = nullptr;
}
void DrawImguiGraph()
{
imguiGraphDraw();
}
} // OGL Renderer
#include "../demoContext.h"
#include "demoContextOGL.h"
DemoContext* CreateDemoContextOGL()
{
return new DemoContextOGL;
}
bool DemoContextOGL::initialize(const RenderInitOptions& options)
{
OGL_Renderer::InitRender(options);
return true;
}
void DemoContextOGL::startFrame(Vec4 colorIn)
{
OGL_Renderer::StartFrame(colorIn);
}
void DemoContextOGL::endFrame()
{
OGL_Renderer::EndFrame();
}
void DemoContextOGL::presentFrame(bool fullsync)
{
OGL_Renderer::PresentFrame(fullsync);
}
void DemoContextOGL::readFrame(int* buffer, int width, int height)
{
OGL_Renderer::ReadFrame(buffer, width, height);
}
void DemoContextOGL::getViewRay(int x, int y, Vec3& origin, Vec3& dir)
{
OGL_Renderer::GetViewRay(x, y, origin, dir);
}
void DemoContextOGL::setView(Matrix44 view, Matrix44 projection)
{
OGL_Renderer::SetView(view, projection);
}
void DemoContextOGL::renderEllipsoids(FluidRenderer* renderer, FluidRenderBuffers* buffers, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, Vec4 color, float blur, float ior, bool debug)
{
OGL_Renderer::RenderEllipsoids(renderer, buffers, n, offset, radius, screenWidth, screenAspect, fov, lightPos, lightTarget, lightTransform, shadowMap, color, blur, ior, debug);
}
void DemoContextOGL::drawMesh(const Mesh* m, Vec3 color)
{
OGL_Renderer::DrawMesh(m, color);
}
void DemoContextOGL::drawCloth(const Vec4* positions, const Vec4* normals, const float* uvs, const int* indices, int numTris, int numPositions, int colorIndex, float expand, bool twosided, bool smooth)
{
OGL_Renderer::DrawCloth(positions, normals, uvs, indices, numTris, numPositions, colorIndex, expand, twosided, smooth);
}
void DemoContextOGL::drawRope(Vec4* positions, int* indices, int numIndices, float radius, int color)
{
OGL_Renderer::DrawRope(positions, indices, numIndices, radius, color);
}
void DemoContextOGL::drawPlane(const Vec4& p, bool color)
{
OGL_Renderer::DrawPlane(p, color);
}
void DemoContextOGL::drawPlanes(Vec4* planes, int n, float bias)
{
OGL_Renderer::DrawPlanes(planes, n, bias);
}
void DemoContextOGL::drawPoints(FluidRenderBuffers* buffers, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowTex, bool showDensity)
{
OGL_Renderer::DrawPoints(buffers, n, offset, radius, screenWidth, screenAspect, fov, lightPos, lightTarget, lightTransform, shadowTex, showDensity);
}
void DemoContextOGL::graphicsTimerBegin()
{
OGL_Renderer::GraphicsTimerBegin();
}
void DemoContextOGL::graphicsTimerEnd()
{
OGL_Renderer::GraphicsTimerEnd();
}
float DemoContextOGL::rendererGetDeviceTimestamps(unsigned long long* begin, unsigned long long* end, unsigned long long* freq)
{
return OGL_Renderer::RendererGetDeviceTimestamps(begin, end, freq);
}
void DemoContextOGL::bindSolidShader(Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, float bias, Vec4 fogColor)
{
OGL_Renderer::BindSolidShader(lightPos, lightTarget, lightTransform, shadowMap, bias, fogColor);
}
void DemoContextOGL::unbindSolidShader()
{
OGL_Renderer::UnbindSolidShader();
}
ShadowMap* DemoContextOGL::shadowCreate()
{
return OGL_Renderer::ShadowCreate();
}
void DemoContextOGL::shadowDestroy(ShadowMap* map)
{
OGL_Renderer::ShadowDestroy(map);
}
void DemoContextOGL::shadowBegin(ShadowMap* map)
{
OGL_Renderer::ShadowBegin(map);
}
void DemoContextOGL::shadowEnd()
{
OGL_Renderer::ShadowEnd();
}
FluidRenderer* DemoContextOGL::createFluidRenderer(uint32_t width, uint32_t height)
{
return OGL_Renderer::CreateFluidRenderer(width, height);
}
void DemoContextOGL::destroyFluidRenderer(FluidRenderer* renderer)
{
OGL_Renderer::DestroyFluidRenderer(renderer);
}
FluidRenderBuffers* DemoContextOGL::createFluidRenderBuffers(int numParticles, bool enableInterop)
{
return OGL_Renderer::CreateFluidRenderBuffers(numParticles, enableInterop);
}
void DemoContextOGL::updateFluidRenderBuffers(FluidRenderBuffers* buffers, NvFlexSolver* flex, bool anisotropy, bool density)
{
OGL_Renderer::UpdateFluidRenderBuffers(buffers, flex, anisotropy, density);
}
void DemoContextOGL::updateFluidRenderBuffers(FluidRenderBuffers* buffers, Vec4* particles, float* densities, Vec4* anisotropy1, Vec4* anisotropy2, Vec4* anisotropy3, int numParticles, int* indices, int numIndices)
{
OGL_Renderer::UpdateFluidRenderBuffers(buffers, particles, densities, anisotropy1, anisotropy2, anisotropy3, numParticles, indices, numIndices);
}
void DemoContextOGL::destroyFluidRenderBuffers(FluidRenderBuffers* buffers)
{
OGL_Renderer::DestroyFluidRenderBuffers(buffers);
}
GpuMesh* DemoContextOGL::createGpuMesh(const Mesh* m)
{
return OGL_Renderer::CreateGpuMesh(m);
}
void DemoContextOGL::destroyGpuMesh(GpuMesh* mesh)
{
OGL_Renderer::DestroyGpuMesh(mesh);
}
void DemoContextOGL::drawGpuMesh(GpuMesh* m, const Matrix44& xform, const Vec3& color)
{
OGL_Renderer::DrawGpuMesh(m, xform, color);
}
void DemoContextOGL::drawGpuMeshInstances(GpuMesh* m, const Matrix44* xforms, int n, const Vec3& color)
{
OGL_Renderer::DrawGpuMeshInstances(m, xforms, n, color);
}
DiffuseRenderBuffers* DemoContextOGL::createDiffuseRenderBuffers(int numDiffuseParticles, bool& enableInterop)
{
return OGL_Renderer::CreateDiffuseRenderBuffers(numDiffuseParticles, enableInterop);
}
void DemoContextOGL::destroyDiffuseRenderBuffers(DiffuseRenderBuffers* buffers)
{
OGL_Renderer::DestroyDiffuseRenderBuffers(buffers);
}
void DemoContextOGL::updateDiffuseRenderBuffers(DiffuseRenderBuffers* buffers, Vec4* diffusePositions, Vec4* diffuseVelocities, int numDiffuseParticles)
{
OGL_Renderer::UpdateDiffuseRenderBuffers(buffers, diffusePositions, diffuseVelocities, numDiffuseParticles);
}
void DemoContextOGL::updateDiffuseRenderBuffers(DiffuseRenderBuffers* buffers, NvFlexSolver* solver)
{
OGL_Renderer::UpdateDiffuseRenderBuffers(buffers, solver);
}
void DemoContextOGL::drawDiffuse(FluidRenderer* render, const DiffuseRenderBuffers* buffers, int n, float radius, float screenWidth, float screenAspect, float fov, Vec4 color, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, float motionBlur, float inscatter, float outscatter, bool shadowEnabled, bool front)
{
OGL_Renderer::RenderDiffuse(render, (DiffuseRenderBuffers*)buffers, n, radius, screenWidth, screenAspect, fov, color, lightPos, lightTarget, lightTransform, shadowMap, motionBlur, inscatter, outscatter, shadowEnabled, front);
}
int DemoContextOGL::getNumDiffuseRenderParticles(DiffuseRenderBuffers* buffers)
{
return OGL_Renderer::GetNumDiffuseRenderParticles(buffers);
}
void DemoContextOGL::beginLines()
{
OGL_Renderer::BeginLines();
}
void DemoContextOGL::drawLine(const Vec3& p, const Vec3& q, const Vec4& color)
{
OGL_Renderer::DrawLine(p, q, color);
}
void DemoContextOGL::endLines()
{
OGL_Renderer::EndLines();
}
void DemoContextOGL::onSizeChanged(int width, int height, bool minimized)
{
OGL_Renderer::ReshapeRender(width, height, minimized);
}
void DemoContextOGL::startGpuWork()
{
OGL_Renderer::StartGpuWork();
}
void DemoContextOGL::endGpuWork()
{
OGL_Renderer::EndGpuWork();
}
void DemoContextOGL::flushGraphicsAndWait()
{
}
void DemoContextOGL::setFillMode(bool wire)
{
OGL_Renderer::SetFillMode(wire);
}
void DemoContextOGL::setCullMode(bool enabled)
{
OGL_Renderer::SetCullMode(enabled);
}
void DemoContextOGL::drawImguiGraph()
{
OGL_Renderer::DrawImguiGraph();
}
void* DemoContextOGL::getGraphicsCommandQueue()
{
return OGL_Renderer::GetGraphicsCommandQueue();
}
void DemoContextOGL::getRenderDevice(void** device, void** context)
{
OGL_Renderer::GetRenderDevice(device, context);
}
// yf: copied from Flex Robotics
void InitRenderHeadless(const RenderInitOptions& options, int width, int height)
{
#ifdef __linux__
int msaaSamples = options.numMsaaSamples;
EGLint ignore;
EGLBoolean ok;
EGLNativeDisplayType native_display = EGL_DEFAULT_DISPLAY;
const char* s = getenv("EGL_GPU");
EGLDisplay selectedDisplay;
if (s != NULL)
{
int egl_index = atoi(s);
static const int MAX_DEVICES = 10;
EGLDeviceEXT eglDevs[MAX_DEVICES];
EGLint numDevices;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
(PFNEGLQUERYDEVICESEXTPROC) eglGetProcAddress("eglQueryDevicesEXT");
eglQueryDevicesEXT(MAX_DEVICES, eglDevs, &numDevices);
printf("Detected %d devices\n", numDevices);
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
(PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT");
selectedDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevs[egl_index], 0);
}
else
{
selectedDisplay = eglGetDisplay(native_display);
}
EGLint eglSurfaceType = EGL_PBUFFER_BIT;
EGLint eglConfigAttribs[] = {
EGL_SURFACE_TYPE, eglSurfaceType,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_BUFFER_SIZE, 32,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_SAMPLE_BUFFERS, 0,
EGL_SAMPLES, 0,
EGL_NONE,
};
static const EGLint eglPBAttribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_NONE,
};
ok = eglBindAPI(EGL_OPENGL_API);
if (!ok)
printf("eglBindAPI(0x%x) failed", EGL_OPENGL_API);
// printf("after eglbindAPI\n");
EGLDisplay g_eglDisplay = selectedDisplay;
if (g_eglDisplay == EGL_NO_DISPLAY)
printf("eglGetDisplay() failed");
ok = eglInitialize(g_eglDisplay, &ignore, &ignore);
if (!ok)
printf("eglInitialize() failed");
EGLint configs_size = 256;
EGLConfig* configs = new EGLConfig[configs_size];
EGLint num_configs;
ok = eglChooseConfig(
g_eglDisplay,
eglConfigAttribs,
configs,
configs_size, // num requested configs
&num_configs); // num returned configs
if (!ok)
printf("eglChooseConfig() failed");
if (num_configs == 0)
printf("failed to find suitable EGLConfig");
g_eglConfig = configs[0];
delete [] configs;
g_eglContext = eglCreateContext(
g_eglDisplay,
g_eglConfig,
EGL_NO_CONTEXT,
NULL);
if (!g_eglContext)
printf("eglCreateContext() failed");
g_eglSurface = eglCreatePbufferSurface(g_eglDisplay, g_eglConfig,
eglPBAttribs);
if (!g_eglSurface)
printf("eglCreatePbufferSurface() failed");
ok = eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, g_eglContext);
if (!ok)
printf("eglMakeCurrent() failed");
// Check if surface is double buffered.
EGLint render_buffer;
ok = eglQueryContext(
g_eglDisplay,
g_eglContext,
EGL_RENDER_BUFFER,
&render_buffer);
if (!ok)
printf("eglQueyContext(EGL_RENDER_BUFFER) failed");
if (render_buffer == EGL_SINGLE_BUFFER)
printf("warn: EGL surface is single buffered\n");
if (!gladLoadEGL())
{
printf("Could not initialize EGL extensions\n");
}
if (!gladLoadGL())
{
printf("Could not initialize GL extensions\n");
}
g_msaaSamples = msaaSamples;
if (g_msaaSamples)
{
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, 0));
if (g_msaaFbo)
{
glVerify(glDeleteFramebuffers(1, &g_msaaFbo));
glVerify(glDeleteRenderbuffers(1, &g_msaaColorBuf));
glVerify(glDeleteRenderbuffers(1, &g_msaaDepthBuf));
}
int samples;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
// clamp samples to 4 to avoid problems with point sprite scaling
//samples = Min(samples, Min(g_msaaSamples, 4));
samples = g_msaaSamples;
glVerify(glGenFramebuffers(1, &g_msaaFbo));
glVerify(glBindFramebuffer(GL_FRAMEBUFFER, g_msaaFbo));
glVerify(glGenRenderbuffers(1, &g_msaaColorBuf));
glVerify(glBindRenderbuffer(GL_RENDERBUFFER, g_msaaColorBuf));
glVerify(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, width, height));
glVerify(glGenRenderbuffers(1, &g_msaaDepthBuf));
glVerify(glBindRenderbuffer(GL_RENDERBUFFER, g_msaaDepthBuf));
glVerify(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height));
glVerify(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, g_msaaDepthBuf));
glVerify(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, g_msaaColorBuf));
glVerify(glCheckFramebufferStatus(GL_FRAMEBUFFER));
glEnable(GL_MULTISAMPLE);
}
g_screenWidth = width;
g_screenHeight = height;
#endif
}