📜  JOGL-照明(1)

📅  最后修改于: 2023-12-03 15:16:40.486000             🧑  作者: Mango

JOGL-照明介绍

JOGL(JogAmp OpenGL)是Java绑定OpenGl API的开源项目,它为Java开发者提供了使用OpenGL进行3D图形编程的平台。而在3D绘图当中,照明是一个不可或缺的重要因素,而JOGL也提供了丰富的照明API接口,帮助开发者实现高品质的3D图形照明效果。

照明类型

JOGL支持多种照明类型,其中常见的有点照明、平行光与聚光照明。

点照明

点照明是一种最基本的照明类型,它基于光源距离物体的距离和物体表面的法向量计算光线的朝向和亮度。要使用点照明,需要先定义一个点光源。

PointLight light = new PointLight();
light.setPosition(new Vector3f(0f, 0f, 0f));
light.setDiffuse(new Color3f(1f, 1f, 1f));
light.setSpecular(new Color3f(1f, 1f, 1f));

上述代码中,设置了一个在坐标原点的点光源,漫反射和镜面反射颜色均为白色。在使用时,需要将点光源传入渲染上下文并启用照明。

gl.glPushMatrix();
gl.glEnable(GL2.GL_LIGHTING);
light.enable(gl, GL2.GL_LIGHT0);
gl.glPopMatrix();
平行光

平行光是一种没有位置信息的光源类型,沿着一个方向发射光线,可用于模拟太阳光。在绘制场景物体时,需要设置平行光源的方向和颜色信息。

DirectionalLight light = new DirectionalLight();
light.setDirection(new Vector3f(0f, 0f, -1f));
light.setDiffuse(new Color3f(1f, 1f, 1f));
light.setSpecular(new Color3f(1f, 1f, 1f));

上述代码中,设置了一个朝向-z方向的平行光,漫反射和镜面反射颜色均为白色。使用时同样需要传入渲染上下文并启用照明。

gl.glPushMatrix();
gl.glEnable(GL2.GL_LIGHTING);
light.enable(gl, GL2.GL_LIGHT0);
gl.glPopMatrix();
聚光照明

聚光照明是一种集中光源在指定方向上的技术,可通过调整聚光灯的方向和角度来模拟现实中的聚光灯效果。如下面的代码所示,创建聚光灯时需要设置其方向、半角、颜色等信息。

SpotLight light = new SpotLight();
light.setPosition(new Vector3f(0f, 0f, 0f));
light.setDirection(new Vector3f(0f, 0f, -1f));
light.setSpreadAngle(20f);
light.setDiffuse(new Color3f(1f, 1f, 1f));
light.setSpecular(new Color3f(1f, 1f, 1f));

聚光灯的使用方式与点光源和平行光源类似,需要传入渲染上下文并启用照明。

gl.glPushMatrix();
gl.glEnable(GL2.GL_LIGHTING);
light.enable(gl, GL2.GL_LIGHT0);
gl.glPopMatrix();
阴影效果

照明效果的精髓在于要通过光线与物体表面的相互作用,模拟出现实中的反光、折射、阴影等效果。而阴影效果又是照明效果中最复杂的一个,JOGL提供了多种阴影算法的实现,开发者可以根据需求进行选择。

阴影映射

阴影映射是目前最主流的一种实时阴影算法,它通过将光源视角下的场景渲染在深度纹理缓存中,再将渲染结果映射到场景物体上,从而实现阴影效果。

首先需要创建深度纹理缓存对象,定义渲染到纹理的帧缓冲对象。

int[] frameBuffer = new int[1];
int[] depthBuffer = new int[1];
gl.glGenFramebuffers(1, frameBuffer, 0);
gl.glGenRenderbuffers(1, depthBuffer, 0);
gl.glBindRenderbuffer(GL.GL_RENDERBUFFER_EXT, depthBuffer[0]);
gl.glRenderbufferStorage(GL.GL_RENDERBUFFER_EXT, GL2.GL_DEPTH_COMPONENT, width, height);
gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer[0]);
gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL2.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depthBuffer[0]);

然后根据深度纹理缓存,渲染光源视角下的场景,并将渲染结果存储到纹理中。

gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer[0]);
gl.glViewport(0, 0, width, height);
gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
glu.gluPerspective(45f, ratio, 1f, 1000f);
glu.gluLookAt(lightPosition.x, lightPosition.y, lightPosition.z,
            targetPosition.x, targetPosition.y, targetPosition.z, 0f, 1f, 0f);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
scene.draw(gl);    // scene表示场景中的物体
gl.glPopMatrix();
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glPopMatrix();
gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0);

最后使用阴影映射纹理对物体进行渲染,并通过调整阴影的颜色、透明度等属性来调整阴影效果。

gl.glEnable(GL2.GL_TEXTURE_GEN_S);
gl.glEnable(GL2.GL_TEXTURE_GEN_T);
gl.glEnable(GL2.GL_TEXTURE_GEN_R);
gl.glEnable(GL2.GL_TEXTURE_GEN_Q);
gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);

gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
gl.glBindTexture(GL2.GL_TEXTURE_2D, depthTexture[0]);

gl.glColorMaterial(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE);
gl.glEnable(GL2.GL_COLOR_MATERIAL);
gl.glEnable(GL2.GL_LIGHTING);
light.enable(gl, GL2.GL_LIGHT0);

scene.draw(gl);    // scene表示场景中的物体

gl.glDisable(GL2.GL_LIGHTING);
gl.glDisable(GL2.GL_COLOR_MATERIAL);
gl.glDisable(GL2.GL_TEXTURE_2D);
gl.glDisable(GL2.GL_TEXTURE_GEN_S);
gl.glDisable(GL2.GL_TEXTURE_GEN_T);
gl.glDisable(GL2.GL_TEXTURE_GEN_R);
gl.glDisable(GL2.GL_TEXTURE_GEN_Q);
阴影卷积

阴影卷积是一种渲染质量较高、效率较低的阴影算法,它基于光源在场景中的占的分布情况来计算阴影效果,同时使用高斯模糊来提高渲染质量。

ShadowMap shadowMap = new ShadowMap();
shadowMap.setBlur(true);
shadowMap.setPasses(2);
shadowMap.setBias(0.2f);
shadowMap.setRadius(1.0f);
shadowMap.setLightDirection(new Vector3f(0, -1, 0));
shadowMap.setDimension(1024);
shadowMap.setLightPosition(new Vector3f(-50, 50, 100));

shadowMap.prepare(gl);
shadowMap.beginShadow(gl);
scene.draw(gl);
shadowMap.endShadow(gl);

gl.glEnable(GL2.GL_LIGHTING);
light.enable(gl, GL2.GL_LIGHT0);
shadowMap.bind(gl, GL2.GL_TEXTURE0);
scene.draw(gl);
总结

JOGL是一个强大的图形编程工具包,可以帮助Java开发者快速实现高质量的3D图形效果。照明技术是其中重要的一环,本文主要介绍了JOGL的照明API接口和阴影算法实现,希望可以对开发者有所帮助。