WebGL之点上添加图片(using texture on point)

本文介绍了一种使用WebGL进行纹理点绘制的技术实现方法。通过加载图像作为纹理,并将其应用于点绘制中,使得每个点都能显示为具有纹理效果的小图片。文章详细展示了顶点着色器和片段着色器的编写过程,以及如何设置WebGL上下文和加载图像。
var VSHADER_SOURCE =[    
        "attribute vec4 a_Position;",                            
        "uniform mat4 u_ProjMatrix;",
        "uniform float u_PointSize;",
        "void main() {",
            "    gl_PointSize = u_PointSize;",
            "    gl_Position = u_ProjMatrix * a_Position;",
        "}"

    ].join("\n")
var FSHADER_SOURCE =
[
        "precision mediump float;",    
        "uniform sampler2D u_Sampler;",               
        "void main() {",     
     "  gl_FragColor = texture2D(u_Sampler,vec2(gl_PointCoord.x,1.0 - gl_PointCoord.y));",
"}" ].join("\n") function main() { var canvas = document.getElementById('webgl'); var gl = getWebGLContext(canvas); if (!gl) { console.log('Failed to get the rendering context for WebGL'); return; } if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to intialize shaders.'); return; } var projMatrix4=new Matrix4(); projMatrix4.setOrtho(-1,1,-1,1,0.0,1.0); var u_projMatrix=gl.getUniformLocation(gl.program,'u_ProjMatrix'); gl.uniformMatrix4fv(u_projMatrix,false,projMatrix4.elements); var position=gl.getAttribLocation(gl.program,'a_Position'); gl.vertexAttrib3f(position,0.0,0.0,0.0); gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); loadImg(gl); } function loadImg(gl){ var image=new Image(); image.onload=function(){ drawPic(gl,image) } image.src="pic.png"; } function drawPic(gl,image){ var width=image.width; var height=image.height; var pointSize=gl.getUniformLocation(gl.program,"u_PointSize"); gl.uniform1f(pointSize,Math.max(width,height)); var texture=gl.createTexture(); //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,texture); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); gl.uniform1i(gl.getUniformLocation(gl.program,"u_Sampler"),0); gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.POINTS,0,1); gl.bindTexture(gl.TEXTURE_2D, null); }

 

转载于:https://www.cnblogs.com/wema/p/7084835.html

<think>我们正在处理一个关于Unity中加载图片的问题,特别是关于使用类似`loadimage`方法时出现问题的解决方案。根据用户提供的引用,我们可以总结出几个关键: 引用[1]展示了在Unity中使用协程和队列加载图片的代码。主要思路是将加载请求加入队列,然后逐个加载,避免同时发起多个请求。代码中使用了`UnityWebRequestTexture.GetTexture`来获取纹理,然后创建Sprite并赋值给Image组件。 引用[2]提到了一个Unity3D动态加载Texture2D图片的教程,重解决了纹理失真问题。它使用WWW类(现在推荐使用UnityWebRequest)和IEnumerator方法,并强调了代码的健壮性。 引用[3]虽然提到了C/C++中的`loadimage`函数,但主要涉及图片路径和格式问题。它指出需要检查图片格式是否匹配、文件是否放在正确的项目路径下。 用户的问题是如何解决`loadimage`加载图片时的问题。由于用户提到的是Unity环境(引用[1]和[2]都是Unity相关),而引用[3]是C/C++的,我们重参考Unity的解决方案。 在Unity中,动态加载图片常见问题及解决方案: 1. **路径问题**:确保提供的URL或路径正确。如果是本地文件,应使用`file://`协议(例如`file:///C:/Users/...`)。如果是远程URL,确保可访问且支持HTTP/HTTPS。 2. **纹理格式问题**:加载的图片格式必须是Unity支持的(如PNG、JPG等)。如果纹理失真,可能需要调整纹理的导入设置(如Filter Mode、Format)或在使用`Sprite.Create`时确保纹理的尺寸正确。 3. **跨域问题(WebGL)**:在WebGL平台加载远程图片可能会遇到跨域问题。需要服务器设置CORS策略,或者将图片放在同一域名下。 4. **内存管理**:加载大量图片时要注意内存泄漏。引用[1]中在加载后调用了`Resources.UnloadUnusedAssets()`,但更推荐使用`Resources.UnloadAsset`或`Destroy`来释放不再使用的纹理。 5. **异步加载和并发控制**:引用[1]使用了队列机制控制同时只有一个加载请求,避免同时发起过多请求导致性能问题。如果用户没有使用队列,同时发起大量请求可能导致卡顿或失败。 6. **错误处理**:引用[1]中检查了`uwr.isHttpError`和`uwr.isNetworkError`,并打印错误日志。在实际应用中,应更详细地处理错误(如重试、显示错误提示等)。 7. **主线程问题**:Unity中只能在主线程操作Unity对象。引用[1]的代码在协程结束后直接操作`image.sprite`,这是安全的,因为协程在主线程执行。 解决方案步骤: 1. 检查URL或路径是否正确,特别是特殊字符(如空格)是否转义。 2. 检查网络连接和服务器状态(如果是远程图片)。 3. 确保图片格式支持。 4. 使用队列或限制并发数来避免同时加载过多图片。 5. 处理异常情况,如网络错误、无效的纹理数据等。 6. 对于纹理失真,可以尝试在创建Sprite时设置正确的像素单位(pixels per unit)和纹理过滤模式。 根据以上分析,我们可以给出以下解决方案: --- ### Unity中动态加载图片问题解决方案 在Unity中动态加载图片(如使用`UnityWebRequestTexture`)时,常见的问题包括图片无法加载、纹理失真、内存泄漏等。以下是针对这些问题的解决方案: #### 1. 检查路径和URL - **本地文件**:使用`file://`协议(例如:`file:///C:/Users/Example/图片.png`)。 - **远程URL**:确保URL完整且可访问(可通过浏览器测试)。注意:WebGL平台有严格的跨域限制,需服务器设置CORS响应头。 - **避免特殊字符**:对URL中的特殊字符(如空格、中文)进行转义(使用`System.Uri.EscapeUriString`或`UnityWebRequest.EscapeURL`)。 #### 2. 确保图片格式支持 Unity支持常见的图片格式(如PNG、JPG、TGA等)。如果加载后纹理失真: - **纹理压缩格式**:在不同平台(Android、iOS)上,纹理的压缩格式可能导致失真。可尝试将纹理设置为不压缩(RGBA32)或使用Crunch压缩。 - **过滤模式(Filter Mode)**:在创建纹理后,设置纹理的过滤模式: ```csharp texture2d.filterMode = FilterMode.Bilinear; // 或 Point, Trilinear ``` #### 3. 使用队列控制加载请求 避免同时发起大量请求导致卡顿(如引用[1]的实现): ```csharp private Queue<IEnumerator> _loadQueue = new Queue<IEnumerator>(); private bool _isLoading = false; public void LoadImage(string url, Image image) { if (string.IsNullOrEmpty(url)) return; _loadQueue.Enqueue(StartLoadImage(url, image)); if (!_isLoading && _loadQueue.Count > 0) { StartCoroutine(_loadQueue.Dequeue()); } } IEnumerator StartLoadImage(string url, Image image) { _isLoading = true; using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url)) { yield return uwr.SendWebRequest(); if (uwr.result == UnityWebRequest.Result.ConnectionError || uwr.result == UnityWebRequest.Result.ProtocolError) { Debug.LogError(uwr.error); } else { Texture2D texture = DownloadHandlerTexture.GetContent(uwr); // 调整纹理设置 texture.wrapMode = TextureWrapMode.Clamp; texture.filterMode = FilterMode.Bilinear; image.sprite = Sprite.Create(texture, new Rect(0,0,texture.width, texture.height), Vector2.zero); } } _isLoading = false; // 加载完成后触发下一个 if (_loadQueue.Count > 0) { StartCoroutine(_loadQueue.Dequeue()); } } ``` #### 4. 内存管理 - 卸载不再使用的纹理:使用`Destroy(oldTexture)`或`Resources.UnloadAsset`释放资源。 - 避免重复加载:使用缓存机制(如字典存储已加载的纹理)。 - 减少大图内存占用:使用`Texture2D.Compress`压缩纹理。 #### 5. 跨域问题(WebGL) 在WebGL平台,加载远程图片需要服务器设置CORS(跨域资源共享)响应头,例如: ``` Access-Control-Allow-Origin: * ``` #### 6. 异常处理 - 网络错误(超时、404等):设置超时时间,并重试或提示用户。 - 纹理创建失败:检查纹理尺寸(不能为0)和格式。 #### 7. 纹理失真处理 - 确保图片尺寸是2的幂次(非强制,但可避免部分平台问题)。 - 创建Sprite时设置正确的pixelsPerUnit(第二个参数): ```csharp Sprite.Create(..., 100.0f); // 例如100像素对应1单位 ``` 通过以上步骤,可以解决大部分动态加载图片的问题。如果问题仍然存在,请检查Unity版本兼容性或尝试使用其他加载方式(如`Resources.Load`或`AssetBundle`)。 §§相关问题§§ 1. 如何解决Unity中加载图片时的内存泄漏问题? 2. Unity动态加载远程图片如何避免跨域问题? 3. 如何优化Unity中大量图片的加载性能? </think>### Unity中LoadImage加载图片问题的解决方案 在Unity中动态加载图片时常见问题及解决方法如下: #### 1. 路径问题(最常见) - **本地文件路径**:必须使用`file://`协议前缀 ```csharp // Windows示例 string path = "file:///C:/Users/User/Images/pic.jpg"; // Android示例 string path = "file://" + Application.persistentDataPath + "/pic.png"; ``` - **项目资源路径**:放在`Assets/StreamingAssets`文件夹,使用: ```csharp string path = Application.streamingAssetsPath + "/pic.jpg"; ``` - **验证路径存在**: ```csharp if (!System.IO.File.Exists(path.Replace("file://", ""))) { Debug.LogError("文件不存在: " + path); } ``` #### 2. 图片格式问题 - **支持格式**:确保使用Unity支持的格式(PNG/JPG/BMP/TGA) - **格式验证**: ```csharp string ext = System.IO.Path.GetExtension(url).ToLower(); if(ext != ".png" && ext != ".jpg" && ext != ".jpeg") { Debug.LogError("不支持的图片格式: " + ext); } ``` #### 3. 纹理失真问题 [^2] - **正确设置纹理参数**: ```csharp Texture2D texture = new Texture2D(2, 2, TextureFormat.RGBA32, false); texture.LoadImage(byteArray); texture.filterMode = FilterMode.Bilinear; // 避免马赛克 texture.wrapMode = TextureWrapMode.Clamp; // 防止边缘拉伸 ``` #### 4. 异步加载优化 [^1] - **使用协程队列**:避免同时加载多个图片 ```csharp IEnumerator LoadImageSequence(string url, RawImage target) { using (UnityWebRequest req = UnityWebRequestTexture.GetTexture(url)) { yield return req.SendWebRequest(); if (req.result != UnityWebRequest.Result.Success) { Debug.LogError($"加载失败: {req.error}"); } else { target.texture = DownloadHandlerTexture.GetContent(req); } } // 触发下一个加载 StartNextLoad(); } ``` #### 5. 内存管理 - **显式释放资源**: ```csharp Resources.UnloadUnusedAssets(); // 或手动销毁 Destroy(oldTexture); ``` - **加载后压缩**: ```csharp texture.Compress(true); // 减少内存占用 ``` #### 6. 跨平台注意事项 - **WebGL特殊处理**: ```csharp #if UNITY_WEBGL StartCoroutine(LoadImageWebGL(url)); #endif ``` - **Android权限**: ```xml <!-- AndroidManifest.xml 添加权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ``` #### 完整解决方案示例 ```csharp IEnumerator SafeLoadImage(string url, RawImage target) { // 1. 验证路径 if (string.IsNullOrEmpty(url)) { Debug.LogError("URL为空"); yield break; } // 2. 添加文件协议(本地文件需要) if (!url.StartsWith("http") && !url.StartsWith("file://")) { url = "file://" + url; } // 3. 异步加载 using (UnityWebRequest req = UnityWebRequestTexture.GetTexture(url)) { yield return req.SendWebRequest(); if (req.result != UnityWebRequest.Result.Success) { Debug.LogError($"加载失败: {req.error} - {url}"); } else { // 4. 创建纹理并防失真 Texture2D texture = DownloadHandlerTexture.GetContent(req); texture.wrapMode = TextureWrapMode.Clamp; texture.filterMode = FilterMode.Trilinear; // 5. 赋值并释放旧纹理 if (target.texture != null) { Destroy(target.texture); } target.texture = texture; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值