- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的开源项目中,我使用 Qt3D 设置了延迟渲染管道。到目前为止一切顺利,但现在我想通过添加聚光灯投影量来继续前进。 (例如,好像场景中有烟雾)
像这样:
我正在使用的片段着色器位于问题的末尾。
我已经读过,对于每个片段,我应该从灯光位置进行光线行进并找到与锥体的交叉点,但我不知道如何将其转换为 GLSL。
我可以轻松地使用来自 GBuffer 的深度图(从相机的角度)添加制服,但我不知道这是否有帮助。
由于我的 GLSL 知识非常有限,请回复实际代码 ,而不是冗长的数学解释,我将无法理解/翻译成代码。请耐心等待我。
uniform sampler2D color;
uniform sampler2D position;
uniform sampler2D normal;
uniform vec2 winSize;
out vec4 fragColor;
const int MAX_LIGHTS = 102;
const int TYPE_POINT = 0;
const int TYPE_DIRECTIONAL = 1;
const int TYPE_SPOT = 2;
struct Light {
int type;
vec3 position;
vec3 color;
float intensity;
vec3 direction;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
float cutOffAngle;
};
uniform Light lightsArray[MAX_LIGHTS];
uniform int lightsNumber;
void main()
{
vec2 texCoord = gl_FragCoord.xy / winSize;
vec4 col = texture(color, texCoord);
vec3 pos = texture(position, texCoord).xyz;
vec3 norm = texture(normal, texCoord).xyz;
vec3 lightColor = vec3(0.0);
vec3 s;
float att;
for (int i = 0; i < lightsNumber; ++i) {
att = 1.0;
if ( lightsArray[i].type != TYPE_DIRECTIONAL ) {
s = lightsArray[i].position - pos;
if (lightsArray[i].constantAttenuation != 0.0
|| lightsArray[i].linearAttenuation != 0.0
|| lightsArray[i].quadraticAttenuation != 0.0) {
float dist = length(s);
att = 1.0 / (lightsArray[i].constantAttenuation + lightsArray[i].linearAttenuation * dist + lightsArray[i].quadraticAttenuation * dist * dist);
}
s = normalize( s );
if ( lightsArray[i].type == TYPE_SPOT ) {
if ( degrees(acos(dot(-s, normalize(lightsArray[i].direction))) ) > lightsArray[i].cutOffAngle)
att = 0.0;
}
} else {
s = normalize(-lightsArray[i].direction);
}
float diffuse = max( dot( s, norm ), 0.0 );
lightColor += att * lightsArray[i].intensity * diffuse * lightsArray[i].color;
}
fragColor = vec4(col.rgb * lightColor, col.a);
}
#version 140
uniform sampler2D color;
uniform sampler2D position;
uniform sampler2D normal;
uniform vec2 winSize;
out vec4 fragColor;
const int MAX_LIGHTS = 102;
const int TYPE_POINT = 0;
const int TYPE_DIRECTIONAL = 1;
const int TYPE_SPOT = 2;
struct Light {
int type;
vec3 position;
vec3 color;
float intensity;
vec3 direction;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
float cutOffAngle;
};
uniform Light lightsArray[MAX_LIGHTS];
uniform int lightsNumber;
uniform mat4 inverseViewMatrix; // defined by camera position, camera target and up vector
void main()
{
vec2 texCoord = gl_FragCoord.xy / winSize;
vec4 col = texture(color, texCoord);
vec3 pos = texture(position, texCoord).xyz;
vec3 norm = texture(normal, texCoord).xyz;
vec3 lightColor = vec3(0.0);
vec3 s;
// calculate unprojected fragment position on near plane and line of sight relative to view
float nearZ = -1.0;
vec3 nearPos = vec3( (texCoord.x - 0.5) * winSize.x / winSize.y, texCoord.y - 0.5, nearZ ); // 1.0 is camera near
vec3 los = normalize( nearPos );
// ray definition
vec3 O = vec3( inverseViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 ) ); // translation part of the camera matrix, which is equal to the camera position
vec3 D = (length(pos) > 0.0) ? normalize(pos - O) : (mat3(inverseViewMatrix) * los);
for (int i = 0; i < lightsNumber; ++i)
{
float att = 1.0;
if ( lightsArray[i].type == TYPE_DIRECTIONAL )
{
s = normalize( -lightsArray[i].direction );
}
else
{
s = lightsArray[i].position - pos;
if (lightsArray[i].type != TYPE_SPOT
&& (lightsArray[i].constantAttenuation != 0.0
|| lightsArray[i].linearAttenuation != 0.0
|| lightsArray[i].quadraticAttenuation != 0.0))
{
float dist = length(s);
att = 1.0 / (lightsArray[i].constantAttenuation + lightsArray[i].linearAttenuation * dist + lightsArray[i].quadraticAttenuation * dist * dist);
}
s = normalize( s );
if ( lightsArray[i].type == TYPE_SPOT )
{
// cone definition
vec3 C = lightsArray[i].position;
vec3 V = normalize(lightsArray[i].direction);
float cosTh = cos( radians(lightsArray[i].cutOffAngle) );
// ray - cone intersection
vec3 CO = O - C;
float DdotV = dot( D, V );
float COdotV = dot( CO, V );
float a = DdotV * DdotV - cosTh * cosTh;
float b = 2.0 * (DdotV * COdotV - dot( D, CO ) * cosTh * cosTh);
float c = COdotV * COdotV - dot( CO, CO ) * cosTh * cosTh;
float det = b * b - 4.0 * a * c;
// find intersection
float isIsect = 0.0;
vec3 isectP = vec3(0.0);
if ( det >= 0.0 )
{
vec3 P1 = O + (-b - sqrt(det)) / (2.0 * a) * D;
vec3 P2 = O + (-b + sqrt(det)) / (2.0 * a) * D;
float isect1 = step( 0.0, dot(normalize(P1 - C), V) );
float isect2 = step( 0.0, dot(normalize(P2 - C), V) );
if ( isect1 < 0.5 )
{
P1 = P2;
isect1 = isect2;
}
if ( isect2 < 0.5 )
{
P2 = P1;
isect2 = isect1;
}
isectP = (length(P1 - O) < length(P2 - O)) ? P1 : P2;
isIsect = mix( isect2, 1.0, isect1 );
if ( length(pos) != 0.0 && length(isectP - O) > length(pos - O))
isIsect = 0.0;
}
float dist = length( isectP - C.xyz );
float limit = degrees(acos(dot(-s, normalize(lightsArray[i].direction))) );
if (isIsect > 0 || limit <= lightsArray[i].cutOffAngle)
{
att = 1.0 / dot( vec3( 1.0, dist, dist * dist ),
vec3(lightsArray[i].constantAttenuation,
lightsArray[i].linearAttenuation,
lightsArray[i].quadraticAttenuation) );
}
else
att = 0.0;
}
}
float diffuse = max( dot( s, norm ), 0.0 );
lightColor += att * lightsArray[i].intensity * diffuse * lightsArray[i].color;
}
fragColor = vec4(col.rgb * lightColor, col.a);
}
qml: lightsArray[0].type = 0
qml: lightsArray[0].position = QVector3D(0, 10, 0)
qml: lightsArray[0].color = #ffffff
qml: lightsArray[0].intensity = 0.8
qml: lightsArray[0].constantAttenuation = 1
qml: lightsArray[0].linearAttenuation = 0
qml: lightsArray[0].quadraticAttenuation = 0
qml: lightsArray[1].type = 2
qml: lightsArray[1].position = QVector3D(0, 3, 0)
qml: lightsArray[1].color = #008000
qml: lightsArray[1].intensity = 0.5
qml: lightsArray[1].constantAttenuation = 2
qml: lightsArray[1].linearAttenuation = 0
qml: lightsArray[1].quadraticAttenuation = 0
qml: lightsArray[1].direction = QVector3D(-0.573576, -0.819152, 0)
qml: lightsArray[1].cutOffAngle = 15
qml: lightsNumber = 2
最佳答案
对于聚光灯的光锥的原始可视化,您必须对视线和光锥进行交集。以下算法在透视 View 中工作,并且计算在 View (眼睛)空间中完成。该算法不关心场景的几何形状,也不做任何深度测试或阴影测试,它只是光锥的叠加可视化。
透视图中的视线可以由一个点和一个方向来定义。由于计算是在 View (眼睛)空间中完成的,因此该点是视点(视锥体的原点),即 vec3(0.0)
。通过视线和相机平截头体的近平面的交点,可以很容易地确定方向。如果片段的投影 XY 坐标在标准化设备坐标中已知(左下点为 (-1,-1),右上点为 (1,1),则可以轻松计算出这一点,请参阅 this 问题的答案)。
float aspect = .....; // ratio of the view port (widht/length)
float fov = .....; // filed of view angle in radians (angle of the camera frustum on the Y-axis)
vec2 ndcPos = .....; // fragment position in NDC space from (-1,-1) to (1,1)
vec3 tanFov = tan( fov * 0.5 );
vec3 los = normalize( vec3( ndcPos.x * aspect * tanFov, ndcPos.y * tanFov, -1.0 ) );
vec3 vLightPos = .....; // position of the light source in view space
vec3 vLightDir = .....; // direction of the light in view space
float coneAngle = .....; // full angle of the light cone in radians
isectP
中。如果存在交叉点,则类型为
isIsect
的变量
float
设置为 1.0,否则设置为 0.0。
// ray definition
vec3 O = vec3(0.0);
vec3 D = los;
// cone definition
vec3 C = vLightPos;
vec3 V = vLightDir;
float cosTh = cos( coneAngle * 0.5 );
// ray - cone intersection
vec3 CO = O - C;
float DdotV = dot( D, V );
float COdotV = dot( CO, V );
float a = DdotV*DdotV - cosTh*cosTh;
float b = 2.0 * (DdotV*COdotV - dot( D, CO )*cosTh*cosTh);
float c = COdotV*COdotV - dot( CO, CO )*cosTh*cosTh;
float det = b*b - 4.0*a*c;
// find intersection
float isIsect = 0.0;
vec3 isectP = vec3(0.0);
if ( det >= 0.0 )
{
vec3 P1 = O + (-b-sqrt(det))/(2.0*a) * D;
vec3 P2 = O + (-b+sqrt(det))/(2.0*a) * D;
float isect1 = step( 0.0, dot(normalize(P1-C), V) );
float isect2 = step( 0.0, dot(normalize(P2-C), V) );
P1 = mix( P2, P1, isect1 );
isectP = P2.z < 0.0 && P2.z > P1.z ? P2 : P1;
isIsect = mix( isect2, 1.0, isect1 ) * step( isectP.z, 0.0 );
}
(function loadscene() {
var sliderScale = 100.0
var gl, canvas, vp_size, camera, progDraw, progLightCone, bufTorus = {}, bufQuad = {}, drawFB;
function render(deltaMS) {
var ambient = document.getElementById( "ambient" ).value / sliderScale;
var diffuse = document.getElementById( "diffuse" ).value / sliderScale;
var specular = document.getElementById( "specular" ).value / sliderScale;
var shininess = document.getElementById( "shininess" ).value;
var cutOffAngle = document.getElementById( "cutOffAngle" ).value;
// setup view projection and model
vp_size = [canvas.width, canvas.height];
var prjMat = camera.Perspective();
var viewMat = camera.LookAt();
var modelMat = IdentM44();
modelMat = RotateAxis( modelMat, CalcAng( deltaMS, 13.0 ), 0 );
modelMat = RotateAxis( modelMat, CalcAng( deltaMS, 17.0 ), 1 );
var lightPos = [0.95, 0.95, -1.0];
var lightDir = [-1.0, -1.0, -3.0];
var lightCutOffAngleRad = cutOffAngle * Math.PI / 180.0;
var lightAtt = [0.7, 0.1, 0.5];
drawFB.Bind( true );
gl.enable( gl.DEPTH_TEST );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
ShProg.Use( progDraw );
ShProg.SetM44( progDraw, "u_projectionMat44", prjMat );
ShProg.SetM44( progDraw, "u_viewMat44", viewMat );
ShProg.SetF3( progDraw, "u_light.position", lightPos );
ShProg.SetF3( progDraw, "u_light.direction", lightDir );
ShProg.SetF1( progDraw, "u_light.ambient", ambient );
ShProg.SetF1( progDraw, "u_light.diffuse", diffuse );
ShProg.SetF1( progDraw, "u_light.specular", specular );
ShProg.SetF1( progDraw, "u_light.shininess", shininess );
ShProg.SetF3( progDraw, "u_light.attenuation", lightAtt );
ShProg.SetF1( progDraw, "u_light.cutOffAngle", lightCutOffAngleRad );
ShProg.SetM44( progDraw, "u_modelMat44", modelMat );
bufObj = bufTorus;
gl.enableVertexAttribArray( progDraw.inPos );
gl.enableVertexAttribArray( progDraw.inNV );
gl.enableVertexAttribArray( progDraw.inCol );
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos );
gl.vertexAttribPointer( progDraw.inPos, 3, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.nv );
gl.vertexAttribPointer( progDraw.inNV, 3, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.col );
gl.vertexAttribPointer( progDraw.inCol, 3, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
gl.disableVertexAttribArray( progDraw.pos );
gl.disableVertexAttribArray( progDraw.nv );
gl.disableVertexAttribArray( progDraw.col );
drawFB.Release( true );
gl.viewport( 0, 0, canvas.width, canvas.height );
var texUnitDraw = 2;
drawFB.BindTexture( texUnitDraw );
ShProg.Use( progLightCone );
ShProg.SetI1( progLightCone, "u_colorAttachment0", texUnitDraw );
ShProg.SetF2( progLightCone, "u_depthRange", [ camera.near, camera.far ] );
ShProg.SetF2( progLightCone, "u_vp", camera.vp );
ShProg.SetF1( progLightCone, "u_fov", camera.fov_y * Math.PI / 180.0 );
ShProg.SetF3( progLightCone, "u_light.position", lightPos );
ShProg.SetF3( progLightCone, "u_light.direction", lightDir );
ShProg.SetF3( progLightCone, "u_light.attenuation", lightAtt );
ShProg.SetF1( progLightCone, "u_light.cutOffAngle", lightCutOffAngleRad );
gl.enableVertexAttribArray( progLightCone.inPos );
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.vertexAttribPointer( progLightCone.inPos, 2, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.drawElements( gl.TRIANGLES, bufQuad.inxLen, gl.UNSIGNED_SHORT, 0 );
gl.disableVertexAttribArray( progLightCone.inPos );
requestAnimationFrame(render);
}
function initScene() {
canvas = document.getElementById( "glow-canvas");
vp_size = [canvas.width, canvas.height];
gl = canvas.getContext( "experimental-webgl" );
if ( !gl )
return;
document.getElementById( "ambient" ).value = 0.25 * sliderScale;
document.getElementById( "diffuse" ).value = 1.0 * sliderScale;
document.getElementById( "specular" ).value = 1.0 * sliderScale;
document.getElementById( "shininess" ).value = 10.0;
document.getElementById( "cutOffAngle" ).value = 30.0;
progDraw = ShProg.Create(
[ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
progDraw.inPos = ShProg.AttrI( progDraw, "inPos" );
progDraw.inNV = ShProg.AttrI( progDraw, "inNV" );
progDraw.inCol = ShProg.AttrI( progDraw, "inCol" );
if ( progDraw == 0 )
return;
progLightCone = ShProg.Create(
[ { source : "light-cone-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "light-cone-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
progLightCone.inPos = ShProg.AttrI( progDraw, "inPos" );
if ( progDraw == 0 )
return;
var circum_size = 32, tube_size = 32;
var rad_circum = 1.5;
var rad_tube = 0.8;
var torus_pts = [];
var torus_nv = [];
var torus_col = [];
var torus_inx = [];
var col = [1, 0.5, 0.0];
for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
var center = [
Math.cos(2 * Math.PI * i_c / circum_size),
Math.sin(2 * Math.PI * i_c / circum_size) ]
for ( var i_t = 0; i_t < tube_size; ++ i_t ) {
var tubeX = Math.cos(2 * Math.PI * i_t / tube_size)
var tubeY = Math.sin(2 * Math.PI * i_t / tube_size)
var pt = [
center[0] * ( rad_circum + tubeX * rad_tube ),
center[1] * ( rad_circum + tubeX * rad_tube ),
tubeY * rad_tube ]
var nv = [ pt[0] - center[0] * rad_tube, pt[1] - center[1] * rad_tube, tubeY * rad_tube ]
torus_pts.push( pt[0], pt[1], pt[2] );
torus_nv.push( nv[0], nv[1], nv[2] );
torus_col.push( col[0], col[1], col[2] );
var i_cn = (i_c+1) % circum_size
var i_tn = (i_t+1) % tube_size
var i_c0 = i_c * tube_size;
var i_c1 = i_cn * tube_size;
torus_inx.push( i_c0+i_t, i_c0+i_tn, i_c1+i_t, i_c0+i_tn, i_c1+i_t, i_c1+i_tn )
}
}
bufTorus.pos = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufTorus.pos );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( torus_pts ), gl.STATIC_DRAW );
bufTorus.nv = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufTorus.nv );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( torus_nv ), gl.STATIC_DRAW );
bufTorus.col = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufTorus.col );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( torus_col ), gl.STATIC_DRAW );
bufTorus.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufTorus.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( torus_inx ), gl.STATIC_DRAW );
bufTorus.inxLen = torus_inx.length;
bufQuad.pos = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW );
bufQuad.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW );
bufQuad.inxLen = 6;
camera = new Camera( [0, 4, 0.0], [0, 0, 0], [0, 0, 1], 90, vp_size, 0.5, 100 );
window.onresize = resize;
resize();
requestAnimationFrame(render);
}
function resize() {
//vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
vp_size = [window.innerWidth, window.innerHeight]
//vp_size = [256, 256]
canvas.width = vp_size[0];
canvas.height = vp_size[1];
var fbsize = Math.max(vp_size[0], vp_size[1]);
fbsize = 1 << 31 - Math.clz32(fbsize); // nearest power of 2
var fb_rect = [fbsize, fbsize];
drawFB = FrameBuffer.Create( fb_rect );
}
function Fract( val ) {
return val - Math.trunc( val );
}
function CalcAng( deltaMS, intervall ) {
return Fract( deltaMS / (1000*intervall) ) * 2.0 * Math.PI;
}
function CalcMove( deltaMS, intervall, range ) {
var pos = self.Fract( deltaMS / (1000*intervall) ) * 2.0
var pos = pos < 1.0 ? pos : (2.0-pos)
return range[0] + (range[1] - range[0]) * pos;
}
function IdentM44() { return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; }
function RotateAxis(matA, angRad, axis) {
var aMap = [ [1, 2], [2, 0], [0, 1] ];
var a0 = aMap[axis][0], a1 = aMap[axis][1];
var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
var matB = matA.slice(0);
for ( var i = 0; i < 3; ++ i ) {
matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
}
return matB;
}
function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
return [ v[0] / len, v[1] / len, v[2] / len ];
}
Camera = function( pos, target, up, fov_y, vp, near, far ) {
this.Time = function() { return Date.now(); }
this.pos = pos;
this.target = target;
this.up = up;
this.fov_y = fov_y;
this.vp = vp;
this.near = near;
this.far = far;
this.orbit_mat = this.current_orbit_mat = this.model_mat = this.current_model_mat = IdentM44();
this.mouse_drag = this.auto_spin = false;
this.auto_rotate = true;
this.mouse_start = [0, 0];
this.mouse_drag_axis = [0, 0, 0];
this.mouse_drag_angle = 0;
this.mouse_drag_time = 0;
this.drag_start_T = this.rotate_start_T = this.Time();
this.Ortho = function() {
var fn = this.far + this.near;
var f_n = this.far - this.near;
var w = this.vp[0];
var h = this.vp[1];
return [
2/w, 0, 0, 0,
0, 2/h, 0, 0,
0, 0, -2/f_n, 0,
0, 0, -fn/f_n, 1 ];
};
this.Perspective = function() {
var n = this.near;
var f = this.far;
var fn = f + n;
var f_n = f - n;
var r = this.vp[0] / this.vp[1];
var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
return [
t/r, 0, 0, 0,
0, t, 0, 0,
0, 0, -fn/f_n, -1,
0, 0, -2*f*n/f_n, 0 ];
};
this.LookAt = function() {
var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
var mx = Normalize( Cross( this.up, mz ) );
var my = Normalize( Cross( mz, mx ) );
var tx = Dot( mx, this.pos );
var ty = Dot( my, this.pos );
var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos );
return [mx[0], my[0], mz[0], 0, mx[1], my[1], mz[1], 0, mx[2], my[2], mz[2], 0, tx, ty, tz, 1];
};
}
var FrameBuffer = {};
FrameBuffer.Create = function( vp, texturePlan ) {
var texPlan = texturePlan ? new Uint8Array( texturePlan ) : null;
var fb = gl.createFramebuffer();
fb.width = vp[0];
fb.height = vp[1];
gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
fb.color0_texture = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, texPlan );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
fb.renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
gl.bindTexture( gl.TEXTURE_2D, null );
gl.bindRenderbuffer( gl.RENDERBUFFER, null );
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
fb.Bind = function( clear ) {
gl.bindFramebuffer( gl.FRAMEBUFFER, this );
if ( clear ) {
gl.viewport( 0, 0, this.width, this.height );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
}
};
fb.Release = function( clear ) {
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
if ( clear ) {
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
}
};
fb.BindTexture = function( textureUnit ) {
gl.activeTexture( gl.TEXTURE0 + textureUnit );
gl.bindTexture( gl.TEXTURE_2D, this.color0_texture );
};
return fb;
}
var ShProg = {};
ShProg.Create = function( shaderList ) {
var shaderObjs = [];
for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
var shderObj = this.Compile( shaderList[i_sh].source, shaderList[i_sh].stage );
if ( shderObj == 0 )
return 0;
shaderObjs.push( shderObj );
}
var progObj = this.Link( shaderObjs )
if ( progObj != 0 ) {
progObj.attrInx = {};
var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
var name = gl.getActiveAttrib( progObj, i_n ).name;
progObj.attrInx[name] = gl.getAttribLocation( progObj, name );
}
progObj.uniLoc = {};
var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
var name = gl.getActiveUniform( progObj, i_n ).name;
progObj.uniLoc[name] = gl.getUniformLocation( progObj, name );
}
}
return progObj;
}
ShProg.AttrI = function( progObj, name ) { return progObj.attrInx[name]; }
ShProg.UniformL = function( progObj, name ) { return progObj.uniLoc[name]; }
ShProg.Use = function( progObj ) { gl.useProgram( progObj ); }
ShProg.SetI1 = function( progObj, name, val ) { if(progObj.uniLoc[name]) gl.uniform1i( progObj.uniLoc[name], val ); }
ShProg.SetF1 = function( progObj, name, val ) { if(progObj.uniLoc[name]) gl.uniform1f( progObj.uniLoc[name], val ); }
ShProg.SetF2 = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform2fv( progObj.uniLoc[name], arr ); }
ShProg.SetF3 = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform3fv( progObj.uniLoc[name], arr ); }
ShProg.SetF4 = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform4fv( progObj.uniLoc[name], arr ); }
ShProg.SetM44 = function( progObj, name, mat ) { if(progObj.uniLoc[name]) gl.uniformMatrix4fv( progObj.uniLoc[name], false, mat ); }
ShProg.Compile = function( source, shaderStage ) {
var shaderScript = document.getElementById(source);
if (shaderScript) {
source = "";
var node = shaderScript.firstChild;
while (node) {
if (node.nodeType == 3) source += node.textContent;
node = node.nextSibling;
}
}
var shaderObj = gl.createShader( shaderStage );
gl.shaderSource( shaderObj, source );
gl.compileShader( shaderObj );
var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
return status ? shaderObj : 0;
}
ShProg.Link = function( shaderObjs ) {
var prog = gl.createProgram();
for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
gl.attachShader( prog, shaderObjs[i_sh] );
gl.linkProgram( prog );
status = gl.getProgramParameter( prog, gl.LINK_STATUS );
if ( !status ) alert("Could not initialise shaders");
gl.useProgram( null );
return status ? prog : 0;
}
initScene();
})();
html,body { margin: 0; overflow: hidden; }
#gui { position : absolute; top : 0; left : 0; }
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
varying vec4 clip_space_pos;
uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
void main()
{
vec3 modelNV = mat3( u_modelMat44 ) * normalize( inNV );
vertNV = mat3( u_viewMat44 ) * modelNV;
vertCol = inCol;
vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
vec4 viewPos = u_viewMat44 * modelPos;
vertPos = viewPos.xyz / viewPos.w;
gl_Position = u_projectionMat44 * viewPos;
}
</script>
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
struct Light {
vec3 position;
vec3 direction;
float ambient;
float diffuse;
float specular;
float shininess;
vec3 attenuation;
float cutOffAngle;
};
uniform Light u_light;
void main()
{
vec3 color = vertCol;
vec3 lightCol = u_light.ambient * color;
vec3 normalV = normalize( vertNV );
vec3 lightV = normalize( u_light.position - vertPos );
float lightD = length( u_light.position - vertPos );
float cosL = dot( normalize( u_light.direction ), -lightV );
float inCone = step( cos( u_light.cutOffAngle * 0.5 ), cosL );
float att = 1.0 / dot( vec3( 1.0, lightD, lightD*lightD ), u_light.attenuation );
float NdotL = max( 0.0, dot( normalV, lightV ) );
lightCol += NdotL * u_light.diffuse * color * inCone * att;
vec3 eyeV = normalize( -vertPos );
vec3 halfV = normalize( eyeV + lightV );
float NdotH = max( 0.0, dot( normalV, halfV ) );
float kSpecular = ( u_light.shininess + 2.0 ) * pow( NdotH, u_light.shininess ) / ( 2.0 * 3.14159265 );
lightCol += kSpecular * u_light.specular * color * inCone * att;
gl_FragColor = vec4( lightCol.rgb, 1.0 );
}
</script>
<script id="light-cone-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 inPos;
varying vec2 vertPos;
void main()
{
vertPos.xy = inPos.xy;
gl_Position = vec4( inPos, 0.0, 1.0 );
}
</script>
<script id="light-cone-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vertPos;
uniform sampler2D u_colorAttachment0;
uniform vec2 u_depthRange;
uniform vec2 u_vp;
uniform float u_fov;
struct Light {
vec3 position;
vec3 direction;
float ambient;
float diffuse;
float specular;
float shininess;
vec3 attenuation;
float cutOffAngle;
};
uniform Light u_light;
void main()
{
vec4 texCol = texture2D( u_colorAttachment0, vertPos.st * 0.5 + 0.5 );
vec3 vLightPos = u_light.position;
vec3 vLightDir = normalize( u_light.direction );
float tanFOV = tan(u_fov*0.5);
vec3 nearPos = vec3( vertPos.x * u_vp.x/u_vp.y * tanFOV, vertPos.y * tanFOV, -1.0 );
//vec2 texCoord = gl_FragCoord.xy / u_vp;
//vec3 nearPos = vec3( (texCoord.x-0.5) * u_vp.x/u_vp.y, texCoord.y-0.5, -u_depthRange.x );
vec3 los = normalize( nearPos );
// ray definition
vec3 O = vec3(0.0);
vec3 D = los;
// cone definition
vec3 C = vLightPos;
vec3 V = vLightDir;
float cosTh = cos( u_light.cutOffAngle * 0.5 );
// ray - cone intersection
vec3 CO = O - C;
float DdotV = dot( D, V );
float COdotV = dot( CO, V );
float a = DdotV*DdotV - cosTh*cosTh;
float b = 2.0 * (DdotV*COdotV - dot( D, CO )*cosTh*cosTh);
float c = COdotV*COdotV - dot( CO, CO )*cosTh*cosTh;
float det = b*b - 4.0*a*c;
// find intersection
float isIsect = 0.0;
vec3 isectP = vec3(0.0);
if ( det >= 0.0 )
{
vec3 P1 = O + (-b-sqrt(det))/(2.0*a) * D;
vec3 P2 = O + (-b+sqrt(det))/(2.0*a) * D;
float isect1 = step( 0.0, dot(normalize(P1-C), V) );
float isect2 = step( 0.0, dot(normalize(P2-C), V) );
if ( isect1 < 0.5 )
{
P1 = P2;
isect1 = isect2;
}
if ( isect2 < 0.5 )
{
P2 = P1;
isect2 = isect1;
}
isectP = ( P1.z > -u_depthRange.x || (P2.z < -u_depthRange.x && P1.z < P2.z ) ) ? P2 : P1;
isIsect = mix( isect2, 1.0, isect1 ) * step( isectP.z, -u_depthRange.x );
}
float dist = length( isectP - vLightPos.xyz );
float att = 1.0 / dot( vec3( 1.0, dist, dist*dist ), u_light.attenuation );
gl_FragColor = vec4( mix( texCol.rgb, vec3(1.0, 1.0, 1.0), isIsect * att * 0.5 ), 1.0 );
}
</script>
<div><form id="gui" name="inputs">
<table>
<tr> <td> <font color=#40f040>ambient</font> </td>
<td> <input type="range" id="ambient" min="0" max="100" value="0"/></td> </tr>
<tr> <td> <font color=#40f040>diffuse</font> </td>
<td> <input type="range" id="diffuse" min="0" max="100" value="0"/></td> </tr>
<tr> <td> <font color=#40f040>specular</font> </td>
<td> <input type="range" id="specular" min="0" max="100" value="0"/></td> </tr>
<tr> <td> <font color=#40f040>shininess</font> </td>
<td> <input type="range" id="shininess" min="1" max="100" value="0"/></td> </tr>
<tr> <td> <font color=#40f040>cut off angle</font> </td>
<td> <input type="range" id="cutOffAngle" min="1" max="180" value="0"/></td> </tr>
</table>
</form>
</div>
<canvas id="glow-canvas" style="border: none;"></canvas>
关于opengl - GLSL聚光灯投影体积,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45783444/
我试图理解这两个概念。我正在阅读的手册对它们非常简短,像多 channel 算法这样的东西对我来说是新的。我想要一些示例(不是代码),说明我需要在哪里使用不变变量或精确变量,只是为了获得一个大致的想法
您好,我正在尝试获得一个快速的圆角矩形 glsl 着色器,但我只设法使用此函数( https://github.com/marklundin/glsl-sdf-primitives/blob/mast
这可能是一个简单的问题。作为 GLSL 的新手,我宁愿在这里问。 现在,在顶点着色器中,我可以通过以下方式获取世界坐标系中的位置: gl_Position = ftransform();
我想知道是否有人拥有完整、有效且高效的代码来在 glsl 中进行双三次纹理过滤。有这个: http://www.codeproject.com/Articles/236394/Bi-Cubic-and
真的有两个问题... GLSL ES 2 是完全独立的语言,还是 GLSL 的特殊版本? 在“标准库”函数、语法和功能方面,它们之间有什么区别? 我正在为一个针对 Windows、Mac 和 iPad
从GLSL文档(https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/length.xhtml)中,长度函数“计算 vector 的长度”
我想在 GLSL 着色器中实现颜色矩阵滤镜,但找不到与此相关的任何文档。我是着色器世界的新手(我自己从未编写过代码)所以如果我的解释/词汇没有意义,请原谅我。 到目前为止我可以收集到的信息: 一个颜色
我刚刚开始使用 openframeworks 中的着色器,并且正在尝试编写一个片段着色器,它根据片段的观看角度来更改片段的颜色。例如,给定一个矩形,如果从正面看(相机与法线平行)它会是红色,但如果从侧
似乎某些在 case 中具有输出的函数可能使用 if 语句作为底层实现,从而导致分支。我不认为它,但我想知道。 对于 sign(x),如果数字是正数、负数或零,则分别重新运行 1、-1 和 0。 那么
如何在 glsl 中执行位操作? 使用常规 C 风格的按位运算符 | , & , ^ , 或 !不起作用。 最佳答案 它们是在 GLSL 1.30 (OGL 3.0) 中引入的。 根据您想要做什么,您
最近我一直在玩 webGl,我偶然发现了一个很酷的小演示 here (来源 here )我想稍微改变一下以获得一些很酷的结果。 我对改变地形的生成方式很感兴趣。而不是分层 10 个 Octave
这是每个设备的事情吗?还是基于浏览器?抱歉问了这样一个基本问题,但我似乎找不到直接的答案。 最佳答案 它基于 OpenGL ES 2.0,并根据 the spec , 它必须支持 GLSL ES 版本
你如何在 GLSL 着色器中通过引用传递? 最佳答案 您可以将属性标记为 inout在函数签名中,这将使属性有效地“通过引用传递” 例如, void doSomething( vec3 trans,
我有一个浮点 RGBA 缓冲区,我想将其作为统一 Texel 缓冲区传递到我的计算着色器(用于只读访问,没有采样)。谁能告诉我如何在 GLSL 中执行此操作? 我能找到的所有示例似乎都在跳过该主题,或
我有一些参数从 CPU 传递到 GPU,这些参数对于所有片段都是恒定的,但在每一帧上都会发生变化(我使用的是 GLSL ES 1.1)。对于这些值,我应该使用制服还是属性?属性可能因顶点而异,所以我的
我已经看到这个伪随机数生成器在着色器中使用,引用here and there around the web : float rand(vec2 co){ return fract(sin(dot(
我尝试在结构内初始化数组,如下所示: struct myStruct { vec3 data[20] = vec3[20] (vec3(1, 1, 1), vec3( 1, -1, 1), v
我尝试在结构内初始化数组,如下所示: struct myStruct { vec3 data[20] = vec3[20] (vec3(1, 1, 1), vec3( 1, -1, 1), v
在 GLSL 着色器中,出于各种原因,我经常需要几个函数来修改单个值(例如,片段着色器使用四个函数来应用照明、纹理、镜面反射和雾化)。我可以想到至少三种方法来传递这些值进行修改: 使用 inout每个
我在 SL 引用中搜索了“copy”,但找不到任何相关内容。 如果我有: float a[3] = float[3] (1.0,2.0,3.0); float b[3] = a; 是 b现在指向 a
我是一名优秀的程序员,十分优秀!